@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
@@ -3,6 +3,10 @@ import path from "node:path";
3
3
  import { pathToFileURL } from "node:url";
4
4
  import { VariableDeclarationKind } from "ts-morph";
5
5
  import ts from "typescript-js";
6
+ import {
7
+ DEV_SUPERVISOR_MANIFEST_FILE,
8
+ DEV_SUPERVISOR_MANIFEST_VERSION
9
+ } from "../dev-supervisor-manifest.js";
6
10
  import {
7
11
  calculateStructureChecksum,
8
12
  toVar,
@@ -58,6 +62,11 @@ import {
58
62
  resolveStandaloneSourceMirrorBase
59
63
  } from "./scanner.js";
60
64
  import { loadGeneratorExtensions } from "./extensions/index.js";
65
+ import {
66
+ renderRouteManifestShardOutputs,
67
+ renderRouteMetadataOutput,
68
+ routeManifestShardFilePattern
69
+ } from "./route-manifest-shards.js";
61
70
  function assertUniqueBackendRoutePattern(seen, moduleId, pattern) {
62
71
  if (!pattern.startsWith("/backend/")) return;
63
72
  const previous = seen.get(pattern);
@@ -1157,12 +1166,16 @@ function discoverTranslations(roots) {
1157
1166
  const locales = /* @__PURE__ */ new Set();
1158
1167
  if (fs.existsSync(i18nCore)) {
1159
1168
  for (const entry of fs.readdirSync(i18nCore, { withFileTypes: true })) {
1160
- if (entry.isFile() && entry.name.endsWith(".json")) locales.add(entry.name.replace(/\.json$/, ""));
1169
+ if (entry.isFile() && /^[a-zA-Z0-9][a-zA-Z0-9_-]*\.json$/.test(entry.name)) {
1170
+ locales.add(entry.name.replace(/\.json$/, ""));
1171
+ }
1161
1172
  }
1162
1173
  }
1163
1174
  if (fs.existsSync(i18nApp)) {
1164
1175
  for (const entry of fs.readdirSync(i18nApp, { withFileTypes: true })) {
1165
- if (entry.isFile() && entry.name.endsWith(".json")) locales.add(entry.name.replace(/\.json$/, ""));
1176
+ if (entry.isFile() && /^[a-zA-Z0-9][a-zA-Z0-9_-]*\.json$/.test(entry.name)) {
1177
+ locales.add(entry.name.replace(/\.json$/, ""));
1178
+ }
1166
1179
  }
1167
1180
  }
1168
1181
  return Array.from(locales, (locale) => ({
@@ -1242,6 +1255,8 @@ async function processPageFiles(options) {
1242
1255
  const eagerRoutes = [];
1243
1256
  const runtimeRoutes = [];
1244
1257
  const manifestRoutes = [];
1258
+ const manifestShardRoutes = [];
1259
+ const metadataRoutes = [];
1245
1260
  const routePatterns = [];
1246
1261
  for (const { relPath, fromApp } of files.filter(({ relPath: f }) => isModulePageFile(path.basename(f)))) {
1247
1262
  const segs = relPath.split("/");
@@ -1309,7 +1324,19 @@ async function processPageFiles(options) {
1309
1324
  const manifestBaseProps = buildPageRouteManifestSpread(manifestMetaExpr, routePath);
1310
1325
  eagerRoutes.push(`{ ${baseProps}, Component: ${buildLazyRouteComponentExpression(importPath)} }`);
1311
1326
  runtimeRoutes.push(`{ ${runtimeBaseProps}, Component: ${buildLazyRouteComponentExpression(importPath)} }`);
1312
- manifestRoutes.push(`{ moduleId: ${toLiteral(modId)}, ${manifestBaseProps}, load: async () => { const mod = await ${buildDynamicImportExpression(importPath)}; return (mod.default ?? mod) as any } }`);
1327
+ const metadataDeclaration = `{ moduleId: ${toLiteral(modId)}, ${manifestBaseProps} }`;
1328
+ const manifestDeclaration = `{ moduleId: ${toLiteral(modId)}, ${manifestBaseProps}, load: async () => { const mod = await ${buildDynamicImportExpression(importPath)}; return (mod.default ?? mod) as any } }`;
1329
+ manifestRoutes.push(manifestDeclaration);
1330
+ manifestShardRoutes.push({
1331
+ path: routePath,
1332
+ declaration: manifestDeclaration,
1333
+ imports: manifestImportStatement ? [manifestImportStatement] : []
1334
+ });
1335
+ metadataRoutes.push({
1336
+ path: routePath,
1337
+ declaration: metadataDeclaration,
1338
+ imports: manifestImportStatement ? [manifestImportStatement] : []
1339
+ });
1313
1340
  routePatterns.push(routePath);
1314
1341
  }
1315
1342
  for (const { relPath, fromApp } of files.filter(({ relPath: f }) => !isModulePageFile(path.basename(f)))) {
@@ -1382,13 +1409,27 @@ async function processPageFiles(options) {
1382
1409
  const manifestBaseProps = buildPageRouteManifestSpread(manifestMetaExpr, routePath);
1383
1410
  eagerRoutes.push(`{ ${baseProps}, Component: ${buildLazyRouteComponentExpression(importPath)} }`);
1384
1411
  runtimeRoutes.push(`{ ${runtimeBaseProps}, Component: ${buildLazyRouteComponentExpression(importPath)} }`);
1385
- manifestRoutes.push(`{ moduleId: ${toLiteral(modId)}, ${manifestBaseProps}, load: async () => { const mod = await ${buildDynamicImportExpression(importPath)}; return (mod.default ?? mod) as any } }`);
1412
+ const metadataDeclaration = `{ moduleId: ${toLiteral(modId)}, ${manifestBaseProps} }`;
1413
+ const manifestDeclaration = `{ moduleId: ${toLiteral(modId)}, ${manifestBaseProps}, load: async () => { const mod = await ${buildDynamicImportExpression(importPath)}; return (mod.default ?? mod) as any } }`;
1414
+ manifestRoutes.push(manifestDeclaration);
1415
+ manifestShardRoutes.push({
1416
+ path: routePath,
1417
+ declaration: manifestDeclaration,
1418
+ imports: manifestImportStatement ? [manifestImportStatement] : []
1419
+ });
1420
+ metadataRoutes.push({
1421
+ path: routePath,
1422
+ declaration: metadataDeclaration,
1423
+ imports: manifestImportStatement ? [manifestImportStatement] : []
1424
+ });
1386
1425
  routePatterns.push(routePath);
1387
1426
  }
1388
1427
  return {
1389
1428
  eagerRoutes,
1390
1429
  runtimeRoutes,
1391
1430
  manifestRoutes,
1431
+ manifestShardRoutes,
1432
+ metadataRoutes,
1392
1433
  routePatterns
1393
1434
  };
1394
1435
  }
@@ -1397,11 +1438,13 @@ async function processApiRoutes(options) {
1397
1438
  const apiApp = path.join(roots.appBase, "api");
1398
1439
  const apiPkg = path.join(roots.pkgBase, "api");
1399
1440
  if (!fs.existsSync(apiApp) && !fs.existsSync(apiPkg)) {
1400
- return { eagerApis: [], runtimeApis: [], manifestApis: [] };
1441
+ return { eagerApis: [], runtimeApis: [], manifestApis: [], manifestShardApis: [], metadataApis: [] };
1401
1442
  }
1402
1443
  const eagerApis = [];
1403
1444
  const runtimeApis = [];
1404
1445
  const manifestApis = [];
1446
+ const manifestShardApis = [];
1447
+ const metadataApis = [];
1405
1448
  const routeFiles = scanModuleDir(roots, SCAN_CONFIGS.apiRoutes);
1406
1449
  for (const { relPath, fromApp } of routeFiles) {
1407
1450
  const segs = relPath.split("/");
@@ -1430,7 +1473,11 @@ async function processApiRoutes(options) {
1430
1473
  eagerImports.push(buildImportStatement(`* as ${importName}`, importPath));
1431
1474
  eagerApis.push(`{ path: ((${importName} as any).metadata?.path ?? ${toLiteral(routePath)}), metadata: (${importName} as any).metadata, handlers: ${importName} as any${docsPart} }`);
1432
1475
  runtimeApis.push(`{ path: ${toLiteral(resolvedPath)}, metadata: ${metadataLiteral}, handlers: { ${exportedMethods.map((method) => `${method}: async (req: Request, ctx?: any) => { const mod = await ${buildDynamicImportExpression(importPath)}; return (mod as any).${method}(req, ctx) }`).join(", ")} } }`);
1433
- manifestApis.push(`{ moduleId: ${toLiteral(modId)}, kind: ${toLiteral("route-file")}, path: ${toLiteral(resolvedPath)}, methods: [${exportedMethods.map((method) => toLiteral(method)).join(", ")}], load: async () => ${buildDynamicImportExpression(importPath)} }`);
1476
+ const metadataDeclaration = `{ moduleId: ${toLiteral(modId)}, kind: ${toLiteral("route-file")}, path: ${toLiteral(resolvedPath)}, methods: [${exportedMethods.map((method) => toLiteral(method)).join(", ")}] }`;
1477
+ const manifestDeclaration = `{ moduleId: ${toLiteral(modId)}, kind: ${toLiteral("route-file")}, path: ${toLiteral(resolvedPath)}, methods: [${exportedMethods.map((method) => toLiteral(method)).join(", ")}], load: async () => ${buildDynamicImportExpression(importPath)} }`;
1478
+ manifestApis.push(manifestDeclaration);
1479
+ manifestShardApis.push({ path: resolvedPath, declaration: manifestDeclaration });
1480
+ metadataApis.push({ path: resolvedPath, declaration: metadataDeclaration });
1434
1481
  }
1435
1482
  const plainFiles = scanModuleDir(roots, SCAN_CONFIGS.apiPlainFiles);
1436
1483
  for (const { relPath, fromApp } of plainFiles) {
@@ -1460,7 +1507,11 @@ async function processApiRoutes(options) {
1460
1507
  eagerImports.push(buildImportStatement(`* as ${importName}`, importPath));
1461
1508
  eagerApis.push(`{ path: ((${importName} as any).metadata?.path ?? ${toLiteral(routePath)}), metadata: (${importName} as any).metadata, handlers: ${importName} as any${docsPart} }`);
1462
1509
  runtimeApis.push(`{ path: ${toLiteral(resolvedPath)}, metadata: ${metadataLiteral}, handlers: { ${exportedMethods.map((entryMethod) => `${entryMethod}: async (req: Request, ctx?: any) => { const mod = await ${buildDynamicImportExpression(importPath)}; return (mod as any).${entryMethod}(req, ctx) }`).join(", ")} } }`);
1463
- manifestApis.push(`{ moduleId: ${toLiteral(modId)}, kind: ${toLiteral("route-file")}, path: ${toLiteral(resolvedPath)}, methods: [${exportedMethods.map((entryMethod) => toLiteral(entryMethod)).join(", ")}], load: async () => ${buildDynamicImportExpression(importPath)} }`);
1510
+ const metadataDeclaration = `{ moduleId: ${toLiteral(modId)}, kind: ${toLiteral("route-file")}, path: ${toLiteral(resolvedPath)}, methods: [${exportedMethods.map((entryMethod) => toLiteral(entryMethod)).join(", ")}] }`;
1511
+ const manifestDeclaration = `{ moduleId: ${toLiteral(modId)}, kind: ${toLiteral("route-file")}, path: ${toLiteral(resolvedPath)}, methods: [${exportedMethods.map((entryMethod) => toLiteral(entryMethod)).join(", ")}], load: async () => ${buildDynamicImportExpression(importPath)} }`;
1512
+ manifestApis.push(manifestDeclaration);
1513
+ manifestShardApis.push({ path: resolvedPath, declaration: manifestDeclaration });
1514
+ metadataApis.push({ path: resolvedPath, declaration: metadataDeclaration });
1464
1515
  }
1465
1516
  const methods = ["GET", "POST", "PUT", "PATCH", "DELETE"];
1466
1517
  for (const method of methods) {
@@ -1499,13 +1550,19 @@ async function processApiRoutes(options) {
1499
1550
  eagerImports.push(buildImportStatement(`${importName}, * as ${metaName}`, importPath));
1500
1551
  eagerApis.push(`{ method: ${toLiteral(method)}, path: (${metaName}.metadata?.path ?? ${toLiteral(routePath)}), handler: ${importName}, metadata: ${metaName}.metadata${docsPart} }`);
1501
1552
  runtimeApis.push(`{ method: ${toLiteral(method)}, path: ${toLiteral(resolvedPath)}, handler: async (req: Request, ctx?: any) => { const mod = await ${buildDynamicImportExpression(importPath)}; const handler = ((mod as any).default ?? (mod as any).${method} ?? (mod as any).handler) as any; return handler(req, ctx) }, metadata: ${metadataLiteral} }`);
1502
- manifestApis.push(`{ moduleId: ${toLiteral(modId)}, kind: ${toLiteral("legacy")}, method: ${toLiteral(method)}, path: ${toLiteral(resolvedPath)}, methods: [${toLiteral(method)}], load: async () => ${buildDynamicImportExpression(importPath)} }`);
1553
+ const metadataDeclaration = `{ moduleId: ${toLiteral(modId)}, kind: ${toLiteral("legacy")}, method: ${toLiteral(method)}, path: ${toLiteral(resolvedPath)}, methods: [${toLiteral(method)}] }`;
1554
+ const manifestDeclaration = `{ moduleId: ${toLiteral(modId)}, kind: ${toLiteral("legacy")}, method: ${toLiteral(method)}, path: ${toLiteral(resolvedPath)}, methods: [${toLiteral(method)}], load: async () => ${buildDynamicImportExpression(importPath)} }`;
1555
+ manifestApis.push(manifestDeclaration);
1556
+ manifestShardApis.push({ path: resolvedPath, declaration: manifestDeclaration });
1557
+ metadataApis.push({ path: resolvedPath, declaration: metadataDeclaration });
1503
1558
  }
1504
1559
  }
1505
1560
  return {
1506
1561
  eagerApis,
1507
1562
  runtimeApis,
1508
- manifestApis
1563
+ manifestApis,
1564
+ manifestShardApis,
1565
+ metadataApis
1509
1566
  };
1510
1567
  }
1511
1568
  function processSubscribers(discovered) {
@@ -2101,48 +2158,229 @@ function processWorkersAst(discovered) {
2101
2158
  }
2102
2159
  return workers;
2103
2160
  }
2161
+ function collectWorkerGenerationEntries(discovered, moduleId) {
2162
+ const workers = [];
2163
+ for (const { id, importPath, metadata } of discovered) {
2164
+ if (!metadata.queue) continue;
2165
+ workers.push({
2166
+ id: metadata.id ?? id,
2167
+ moduleId,
2168
+ queue: metadata.queue,
2169
+ concurrency: metadata.concurrency ?? 1,
2170
+ importPath
2171
+ });
2172
+ }
2173
+ return workers;
2174
+ }
2104
2175
  function processTranslationsAst(options) {
2105
- const { discovered, modId, appImportBase, pkgImportBase, imports, extraImports } = options;
2176
+ const { discovered, modId, appImportBase, pkgImportBase, imports, extraImports, localeOutputs } = options;
2106
2177
  const translations = [];
2107
2178
  for (const { locale, coreHas, appHas } of discovered) {
2108
2179
  if (coreHas && appHas) {
2109
2180
  const coreName = `T_${toVar(modId)}_${toVar(locale)}_C`;
2110
2181
  const appName = `T_${toVar(modId)}_${toVar(locale)}_A`;
2111
- imports.push(buildImportStatement(coreName, `${pkgImportBase}/i18n/${locale}.json`));
2112
- imports.push(buildImportStatement(appName, `${appImportBase}/i18n/${locale}.json`));
2113
- extraImports?.push(buildImportStatement(coreName, `${pkgImportBase}/i18n/${locale}.json`));
2114
- extraImports?.push(buildImportStatement(appName, `${appImportBase}/i18n/${locale}.json`));
2182
+ const localeImports = [
2183
+ buildImportStatement(coreName, `${pkgImportBase}/i18n/${locale}.json`),
2184
+ buildImportStatement(appName, `${appImportBase}/i18n/${locale}.json`)
2185
+ ];
2186
+ imports.push(...localeImports);
2187
+ extraImports?.push(...localeImports);
2188
+ const value = objectLiteral([
2189
+ { kind: "spread", value: asExpression(identifier(coreName), "unknown as Record<string, string>") },
2190
+ { kind: "spread", value: asExpression(identifier(appName), "unknown as Record<string, string>") }
2191
+ ]);
2115
2192
  translations.push({
2116
2193
  name: JSON.stringify(locale),
2117
- value: objectLiteral([
2118
- { kind: "spread", value: asExpression(identifier(coreName), "unknown as Record<string, string>") },
2119
- { kind: "spread", value: asExpression(identifier(appName), "unknown as Record<string, string>") }
2120
- ])
2194
+ value
2121
2195
  });
2196
+ localeOutputs?.set(locale, { imports: localeImports, value });
2122
2197
  continue;
2123
2198
  }
2124
2199
  if (appHas) {
2125
2200
  const appName = `T_${toVar(modId)}_${toVar(locale)}_A`;
2126
- imports.push(buildImportStatement(appName, `${appImportBase}/i18n/${locale}.json`));
2127
- extraImports?.push(buildImportStatement(appName, `${appImportBase}/i18n/${locale}.json`));
2201
+ const localeImports = [buildImportStatement(appName, `${appImportBase}/i18n/${locale}.json`)];
2202
+ imports.push(...localeImports);
2203
+ extraImports?.push(...localeImports);
2204
+ const value = asExpression(identifier(appName), "unknown as Record<string, string>");
2128
2205
  translations.push({
2129
2206
  name: JSON.stringify(locale),
2130
- value: asExpression(identifier(appName), "unknown as Record<string, string>")
2207
+ value
2131
2208
  });
2209
+ localeOutputs?.set(locale, { imports: localeImports, value });
2132
2210
  continue;
2133
2211
  }
2134
2212
  if (coreHas) {
2135
2213
  const coreName = `T_${toVar(modId)}_${toVar(locale)}_C`;
2136
- imports.push(buildImportStatement(coreName, `${pkgImportBase}/i18n/${locale}.json`));
2137
- extraImports?.push(buildImportStatement(coreName, `${pkgImportBase}/i18n/${locale}.json`));
2214
+ const localeImports = [buildImportStatement(coreName, `${pkgImportBase}/i18n/${locale}.json`)];
2215
+ imports.push(...localeImports);
2216
+ extraImports?.push(...localeImports);
2217
+ const value = asExpression(identifier(coreName), "unknown as Record<string, string>");
2138
2218
  translations.push({
2139
2219
  name: JSON.stringify(locale),
2140
- value: asExpression(identifier(coreName), "unknown as Record<string, string>")
2220
+ value
2141
2221
  });
2222
+ localeOutputs?.set(locale, { imports: localeImports, value });
2142
2223
  }
2143
2224
  }
2144
2225
  return translations;
2145
2226
  }
2227
+ function sourceDeclaresCliCommand(filePath, commandName) {
2228
+ let sourceText;
2229
+ try {
2230
+ sourceText = fs.readFileSync(filePath, "utf8");
2231
+ } catch {
2232
+ return false;
2233
+ }
2234
+ const sourceFile = ts.createSourceFile(filePath, sourceText, ts.ScriptTarget.Latest, true);
2235
+ const declarations = /* @__PURE__ */ new Map();
2236
+ for (const statement of sourceFile.statements) {
2237
+ if (!ts.isVariableStatement(statement)) continue;
2238
+ for (const declaration of statement.declarationList.declarations) {
2239
+ if (ts.isIdentifier(declaration.name) && declaration.initializer) {
2240
+ declarations.set(declaration.name.text, declaration.initializer);
2241
+ }
2242
+ }
2243
+ }
2244
+ const expressionDeclaresCommand = (expression, seen = /* @__PURE__ */ new Set()) => {
2245
+ if (ts.isParenthesizedExpression(expression) || ts.isAsExpression(expression) || ts.isSatisfiesExpression(expression)) {
2246
+ return expressionDeclaresCommand(expression.expression, seen);
2247
+ }
2248
+ if (ts.isIdentifier(expression)) {
2249
+ if (seen.has(expression.text)) return false;
2250
+ const initializer = declarations.get(expression.text);
2251
+ if (!initializer) return false;
2252
+ const nextSeen = new Set(seen);
2253
+ nextSeen.add(expression.text);
2254
+ return expressionDeclaresCommand(initializer, nextSeen);
2255
+ }
2256
+ if (ts.isArrayLiteralExpression(expression)) {
2257
+ return expression.elements.some((element) => ts.isSpreadElement(element) ? expressionDeclaresCommand(element.expression, seen) : expressionDeclaresCommand(element, seen));
2258
+ }
2259
+ if (!ts.isObjectLiteralExpression(expression)) return false;
2260
+ return expression.properties.some((property) => {
2261
+ if (!ts.isPropertyAssignment(property)) return false;
2262
+ const propertyName = ts.isIdentifier(property.name) || ts.isStringLiteralLike(property.name) ? property.name.text : null;
2263
+ return propertyName === "command" && (ts.isStringLiteralLike(property.initializer) || ts.isNoSubstitutionTemplateLiteral(property.initializer)) && property.initializer.text === commandName;
2264
+ });
2265
+ };
2266
+ return sourceFile.statements.some((statement) => ts.isExportAssignment(statement) && !statement.isExportEquals && expressionDeclaresCommand(statement.expression));
2267
+ }
2268
+ function appDeclaresProgrammaticDevSupervisorOverrides(appDir) {
2269
+ const srcDir = path.join(appDir, "src");
2270
+ const pending = [srcDir];
2271
+ while (pending.length > 0) {
2272
+ const current = pending.pop();
2273
+ let entries;
2274
+ try {
2275
+ entries = fs.readdirSync(current, { withFileTypes: true });
2276
+ } catch {
2277
+ continue;
2278
+ }
2279
+ for (const entry of entries) {
2280
+ const entryPath = path.join(current, entry.name);
2281
+ if (entry.isDirectory()) {
2282
+ if (entry.name !== "__tests__" && entry.name !== "node_modules") pending.push(entryPath);
2283
+ continue;
2284
+ }
2285
+ if (!/\.[cm]?tsx?$/.test(entry.name) || /(?:^|\.)test\.[cm]?tsx?$/.test(entry.name)) continue;
2286
+ let sourceText;
2287
+ try {
2288
+ sourceText = fs.readFileSync(entryPath, "utf8");
2289
+ } catch {
2290
+ continue;
2291
+ }
2292
+ const sourceFile = ts.createSourceFile(entryPath, sourceText, ts.ScriptTarget.Latest, true);
2293
+ const directImports = /* @__PURE__ */ new Set();
2294
+ const namespaceImports = /* @__PURE__ */ new Set();
2295
+ for (const statement of sourceFile.statements) {
2296
+ if (!ts.isImportDeclaration(statement) || !ts.isStringLiteralLike(statement.moduleSpecifier) || statement.moduleSpecifier.text !== "@open-mercato/shared/modules/overrides") continue;
2297
+ const bindings = statement.importClause?.namedBindings;
2298
+ if (bindings && ts.isNamespaceImport(bindings)) namespaceImports.add(bindings.name.text);
2299
+ if (bindings && ts.isNamedImports(bindings)) {
2300
+ for (const element of bindings.elements) {
2301
+ const importedName = element.propertyName?.text ?? element.name.text;
2302
+ if (importedName === "applyWorkerOverrides" || importedName === "applyCliOverrides") {
2303
+ directImports.add(element.name.text);
2304
+ }
2305
+ }
2306
+ }
2307
+ }
2308
+ let found = false;
2309
+ const visit = (node) => {
2310
+ if (found) return;
2311
+ if (ts.isCallExpression(node)) {
2312
+ if (ts.isIdentifier(node.expression) && directImports.has(node.expression.text)) {
2313
+ found = true;
2314
+ return;
2315
+ }
2316
+ if (ts.isPropertyAccessExpression(node.expression) && ts.isIdentifier(node.expression.expression) && namespaceImports.has(node.expression.expression.text) && ["applyWorkerOverrides", "applyCliOverrides"].includes(node.expression.name.text)) {
2317
+ found = true;
2318
+ return;
2319
+ }
2320
+ }
2321
+ ts.forEachChild(node, visit);
2322
+ };
2323
+ visit(sourceFile);
2324
+ if (found) return true;
2325
+ }
2326
+ }
2327
+ return false;
2328
+ }
2329
+ function renderAstI18nLocaleRegistryFile(options) {
2330
+ const sourceFile = createGeneratedSourceFile(options.fileName);
2331
+ addAutoGeneratedComment(sourceFile, "registry (locale-specific i18n version)");
2332
+ addImportSpec(sourceFile, {
2333
+ moduleSpecifier: "@open-mercato/shared/modules/registry",
2334
+ namedImports: [{ name: "Module", isTypeOnly: true }]
2335
+ });
2336
+ addImportStatements(sourceFile, options.imports);
2337
+ sourceFile.addVariableStatement({
2338
+ declarationKind: VariableDeclarationKind.Const,
2339
+ isExported: true,
2340
+ declarations: [{
2341
+ name: "modules",
2342
+ type: "Module[]",
2343
+ initializer: arrayLiteral(options.moduleEntries, writeValue)
2344
+ }]
2345
+ });
2346
+ sourceFile.addExportAssignment({
2347
+ isExportEquals: false,
2348
+ expression: "modules"
2349
+ });
2350
+ return getSourceText(sourceFile);
2351
+ }
2352
+ function buildI18nLocaleShardFileName(locale) {
2353
+ const safeLocale = locale.replace(/[^a-zA-Z0-9_-]/g, "_");
2354
+ return `modules.i18n.${safeLocale}.generated.ts`;
2355
+ }
2356
+ function renderI18nLocaleLoadersFile(locales) {
2357
+ const cases = locales.map((locale) => {
2358
+ const moduleSpecifier = `./${buildI18nLocaleShardFileName(locale).replace(/\.ts$/, "")}`;
2359
+ return ` case ${JSON.stringify(locale)}:
2360
+ return import(${JSON.stringify(moduleSpecifier)}).then((entry) => entry.modules)`;
2361
+ }).join("\n");
2362
+ return `// AUTO-GENERATED by mercato generate registry (locale-specific i18n loaders)
2363
+ import type { Module } from '@open-mercato/shared/modules/registry'
2364
+
2365
+ export async function loadI18nModules(locale: string): Promise<Module[]> {
2366
+ switch (locale) {
2367
+ ${cases ? `${cases}
2368
+ ` : ""} default:
2369
+ return []
2370
+ }
2371
+ }
2372
+ `;
2373
+ }
2374
+ function removeStaleI18nLocaleShards(outputDir, expectedFileNames) {
2375
+ if (!fs.existsSync(outputDir)) return;
2376
+ for (const entry of fs.readdirSync(outputDir, { withFileTypes: true })) {
2377
+ if (!entry.isFile()) continue;
2378
+ if (!/^modules\.i18n\..+\.generated\.(?:ts|checksum)$/.test(entry.name)) continue;
2379
+ if (entry.name.startsWith("modules.i18n.loaders.generated.")) continue;
2380
+ if (expectedFileNames.has(entry.name)) continue;
2381
+ fs.unlinkSync(path.join(outputDir, entry.name));
2382
+ }
2383
+ }
2146
2384
  function resolveConventionFile(resolved, prefix, modId, importIdRef, imports, extraImports, importStyle = "namespace") {
2147
2385
  if (!resolved) return null;
2148
2386
  const importName = `${prefix}_${toVar(modId)}_${importIdRef.value++}`;
@@ -2205,6 +2443,10 @@ async function generateModuleRegistryFromDiscovery(options) {
2205
2443
  const frontendRouteManifestDecls = [];
2206
2444
  const backendRouteManifestDecls = [];
2207
2445
  const apiRouteManifestDecls = [];
2446
+ const backendRouteShardEntries = [];
2447
+ const backendRouteMetadataEntries = [];
2448
+ const apiRouteShardEntries = [];
2449
+ const apiRouteMetadataEntries = [];
2208
2450
  const importIdRef = { value: 0 };
2209
2451
  const requiresByModule = /* @__PURE__ */ new Map();
2210
2452
  const commandLoaderEntries = [];
@@ -2370,6 +2612,8 @@ async function generateModuleRegistryFromDiscovery(options) {
2370
2612
  backendRoutes.push(...generatedBackendRoutes.eagerRoutes);
2371
2613
  runtimeBackendRoutes.push(...generatedBackendRoutes.runtimeRoutes);
2372
2614
  backendRouteManifestDecls.push(...generatedBackendRoutes.manifestRoutes);
2615
+ backendRouteShardEntries.push(...generatedBackendRoutes.manifestShardRoutes);
2616
+ backendRouteMetadataEntries.push(...generatedBackendRoutes.metadataRoutes);
2373
2617
  for (const pattern of generatedBackendRoutes.routePatterns) {
2374
2618
  assertUniqueBackendRoutePattern(seenBackendRoutePatterns, modId, pattern);
2375
2619
  }
@@ -2388,6 +2632,8 @@ async function generateModuleRegistryFromDiscovery(options) {
2388
2632
  apis.push(...generatedApis.eagerApis);
2389
2633
  runtimeApis.push(...generatedApis.runtimeApis);
2390
2634
  apiRouteManifestDecls.push(...generatedApis.manifestApis);
2635
+ apiRouteShardEntries.push(...generatedApis.manifestShardApis);
2636
+ apiRouteMetadataEntries.push(...generatedApis.metadataApis);
2391
2637
  }
2392
2638
  {
2393
2639
  const cliResolved = discovered.resolve("cli.ts");
@@ -2586,6 +2832,12 @@ async function generateModuleRegistryFromDiscovery(options) {
2586
2832
  exportName: "apiRoutes",
2587
2833
  entries: apiRouteManifestDecls
2588
2834
  });
2835
+ const routeManifestOutputs = [
2836
+ ...renderRouteManifestShardOutputs("backend", backendRouteShardEntries),
2837
+ ...renderRouteManifestShardOutputs("api", apiRouteShardEntries),
2838
+ renderRouteMetadataOutput("backend", backendRouteMetadataEntries),
2839
+ renderRouteMetadataOutput("api", apiRouteMetadataEntries)
2840
+ ];
2589
2841
  const legacySubscribersOutput = renderAstLegacyAliasFile({
2590
2842
  fileName: "subscribers.generated.ts",
2591
2843
  exportName: "moduleSubscribers",
@@ -2628,6 +2880,29 @@ async function generateModuleRegistryFromDiscovery(options) {
2628
2880
  writeGeneratedFile({ outFile: frontendRoutesOutFile, checksumFile: frontendRoutesChecksumFile, content: frontendRoutesOutput, structureChecksum, result, quiet });
2629
2881
  writeGeneratedFile({ outFile: backendRoutesOutFile, checksumFile: backendRoutesChecksumFile, content: backendRoutesOutput, structureChecksum, result, quiet });
2630
2882
  writeGeneratedFile({ outFile: apiRoutesOutFile, checksumFile: apiRoutesChecksumFile, content: apiRoutesOutput, structureChecksum, result, quiet });
2883
+ const expectedRouteManifestFiles = new Set(routeManifestOutputs.flatMap(({ fileName }) => [
2884
+ fileName,
2885
+ fileName.replace(/\.ts$/, ".checksum")
2886
+ ]));
2887
+ if (fs.existsSync(outputDir)) {
2888
+ for (const entry of fs.readdirSync(outputDir, { withFileTypes: true })) {
2889
+ if (!entry.isFile() || !routeManifestShardFilePattern.test(entry.name)) continue;
2890
+ if (expectedRouteManifestFiles.has(entry.name)) continue;
2891
+ const stalePath = path.join(outputDir, entry.name);
2892
+ fs.unlinkSync(stalePath);
2893
+ result.filesWritten.push(stalePath);
2894
+ }
2895
+ }
2896
+ for (const routeOutput of routeManifestOutputs) {
2897
+ writeGeneratedFile({
2898
+ outFile: path.join(outputDir, routeOutput.fileName),
2899
+ checksumFile: path.join(outputDir, routeOutput.fileName.replace(/\.ts$/, ".checksum")),
2900
+ content: routeOutput.content,
2901
+ structureChecksum,
2902
+ result,
2903
+ quiet
2904
+ });
2905
+ }
2631
2906
  writeGeneratedFile({ outFile: legacySubscribersOutFile, checksumFile: legacySubscribersChecksumFile, content: legacySubscribersOutput, structureChecksum, result, quiet });
2632
2907
  const commandLoadersOutput = renderCommandLoadersFile(commandLoaderEntries);
2633
2908
  writeGeneratedFile({ outFile: commandLoadersOutFile, checksumFile: commandLoadersChecksumFile, content: commandLoadersOutput, structureChecksum, result, quiet });
@@ -2656,14 +2931,14 @@ async function generateModuleRegistryFromDiscovery(options) {
2656
2931
  {
2657
2932
  const bootstrapPlugins = [...pluginRegistry.values()].filter((p) => p.bootstrapRegistration);
2658
2933
  const allEntryImports = [
2659
- buildImportStatement(`{ backendRoutes }`, `./backend-routes.generated`),
2934
+ buildImportStatement(`{ backendRouteFacades }`, `./backend-route-shards.generated`),
2660
2935
  buildImportStatement(`{ frontendRoutes }`, `./frontend-routes.generated`)
2661
2936
  ];
2662
2937
  const allRegImports = [
2663
2938
  `import { registerBackendRouteManifests, registerFrontendRouteManifests } from '@open-mercato/shared/modules/registry'`
2664
2939
  ];
2665
2940
  const allCalls = [
2666
- `registerBackendRouteManifests(backendRoutes)`,
2941
+ `registerBackendRouteManifests(backendRouteFacades)`,
2667
2942
  `registerFrontendRouteManifests(frontendRoutes)`
2668
2943
  ];
2669
2944
  for (const plugin of bootstrapPlugins) {
@@ -2698,6 +2973,8 @@ async function generateModuleRegistryAppFromDiscovery(options) {
2698
2973
  const bootstrapChecksumFile = path.join(outputDir, "modules.bootstrap.generated.checksum");
2699
2974
  const i18nOutFile = path.join(outputDir, "modules.i18n.generated.ts");
2700
2975
  const i18nChecksumFile = path.join(outputDir, "modules.i18n.generated.checksum");
2976
+ const i18nLoadersOutFile = path.join(outputDir, "modules.i18n.loaders.generated.ts");
2977
+ const i18nLoadersChecksumFile = path.join(outputDir, "modules.i18n.loaders.generated.checksum");
2701
2978
  const legacyOutFile = path.join(outputDir, "bootstrap-modules.generated.ts");
2702
2979
  const legacyChecksumFile = path.join(outputDir, "bootstrap-modules.generated.checksum");
2703
2980
  const enabledIdsOutFile = path.join(outputDir, "enabled-module-ids.generated.ts");
@@ -2711,6 +2988,7 @@ async function generateModuleRegistryAppFromDiscovery(options) {
2711
2988
  const moduleDecls = [];
2712
2989
  const bootstrapModuleDecls = [];
2713
2990
  const i18nModuleDecls = [];
2991
+ const i18nLocaleShards = /* @__PURE__ */ new Map();
2714
2992
  const importIdRef = { value: 0 };
2715
2993
  const requiresByModule = /* @__PURE__ */ new Map();
2716
2994
  const commandLoaderEntries = [];
@@ -2722,6 +3000,7 @@ async function generateModuleRegistryAppFromDiscovery(options) {
2722
3000
  const frontendRoutes = [];
2723
3001
  const backendRoutes = [];
2724
3002
  const translations = [];
3003
+ const localeTranslations = /* @__PURE__ */ new Map();
2725
3004
  const subscribers = [];
2726
3005
  const workers = [];
2727
3006
  let infoImportName = null;
@@ -2837,10 +3116,25 @@ async function generateModuleRegistryAppFromDiscovery(options) {
2837
3116
  appImportBase,
2838
3117
  pkgImportBase: imps.pkgBase,
2839
3118
  imports,
2840
- extraImports: translationImports
3119
+ extraImports: translationImports,
3120
+ localeOutputs: localeTranslations
2841
3121
  }));
2842
- bootstrapImports.push(...translationImports);
2843
3122
  i18nImports.push(...translationImports);
3123
+ for (const [locale, localeTranslation] of localeTranslations) {
3124
+ const shard = i18nLocaleShards.get(locale) ?? { imports: [], moduleDecls: [] };
3125
+ shard.imports.push(...localeTranslation.imports);
3126
+ shard.moduleDecls.push(objectLiteral([
3127
+ { name: "id", value: modId },
3128
+ {
3129
+ name: "translations",
3130
+ value: objectLiteral([{
3131
+ name: JSON.stringify(locale),
3132
+ value: localeTranslation.value
3133
+ }])
3134
+ }
3135
+ ]));
3136
+ i18nLocaleShards.set(locale, shard);
3137
+ }
2844
3138
  subscribers.push(...processSubscribersAst(await discovered.getSubscribers()));
2845
3139
  workers.push(...processWorkersAst(await discovered.getWorkers()));
2846
3140
  {
@@ -2949,7 +3243,9 @@ async function generateModuleRegistryAppFromDiscovery(options) {
2949
3243
  routeAwareModuleEntries.push({ name: "backendRoutes", value: arrayLiteral(backendRoutes, writeValue) });
2950
3244
  }
2951
3245
  moduleDecls.push(objectLiteral(routeAwareModuleEntries));
2952
- bootstrapModuleDecls.push(objectLiteral(moduleEntries));
3246
+ bootstrapModuleDecls.push(objectLiteral(moduleEntries.filter(
3247
+ (entry) => entry.kind === "spread" || entry.name !== "translations"
3248
+ )));
2953
3249
  i18nModuleDecls.push(objectLiteral(i18nModuleEntries));
2954
3250
  }
2955
3251
  const output = renderAstModuleRegistryFile({
@@ -3001,6 +3297,41 @@ async function generateModuleRegistryAppFromDiscovery(options) {
3001
3297
  writeGeneratedFile({ outFile, checksumFile, content: output, structureChecksum, result, quiet });
3002
3298
  writeGeneratedFile({ outFile: bootstrapOutFile, checksumFile: bootstrapChecksumFile, content: bootstrapOutput, structureChecksum, result, quiet });
3003
3299
  writeGeneratedFile({ outFile: i18nOutFile, checksumFile: i18nChecksumFile, content: i18nOutput, structureChecksum, result, quiet });
3300
+ const i18nLocales = [...i18nLocaleShards.keys()].sort((a, b) => a.localeCompare(b));
3301
+ const shardFileNames = /* @__PURE__ */ new Set();
3302
+ const expectedShardArtifacts = /* @__PURE__ */ new Set();
3303
+ for (const locale of i18nLocales) {
3304
+ const fileName = buildI18nLocaleShardFileName(locale);
3305
+ if (shardFileNames.has(fileName)) {
3306
+ throw new Error(`Locale names produce the same generated i18n shard file: ${locale}`);
3307
+ }
3308
+ shardFileNames.add(fileName);
3309
+ expectedShardArtifacts.add(fileName);
3310
+ expectedShardArtifacts.add(fileName.replace(/\.ts$/, ".checksum"));
3311
+ const shard = i18nLocaleShards.get(locale);
3312
+ const content = renderAstI18nLocaleRegistryFile({
3313
+ fileName,
3314
+ imports: shard.imports,
3315
+ moduleEntries: shard.moduleDecls
3316
+ });
3317
+ writeGeneratedFile({
3318
+ outFile: path.join(outputDir, fileName),
3319
+ checksumFile: path.join(outputDir, fileName.replace(/\.ts$/, ".checksum")),
3320
+ content,
3321
+ structureChecksum,
3322
+ result,
3323
+ quiet
3324
+ });
3325
+ }
3326
+ removeStaleI18nLocaleShards(outputDir, expectedShardArtifacts);
3327
+ writeGeneratedFile({
3328
+ outFile: i18nLoadersOutFile,
3329
+ checksumFile: i18nLoadersChecksumFile,
3330
+ content: renderI18nLocaleLoadersFile(i18nLocales),
3331
+ structureChecksum,
3332
+ result,
3333
+ quiet
3334
+ });
3004
3335
  writeGeneratedFile({ outFile: legacyOutFile, checksumFile: legacyChecksumFile, content: legacyOutput, structureChecksum, result, quiet });
3005
3336
  const enabledIdsOutput = renderEnabledModuleIdsFile(enabled.map((entry) => entry.id));
3006
3337
  writeGeneratedFile({ outFile: enabledIdsOutFile, checksumFile: enabledIdsChecksumFile, content: enabledIdsOutput, structureChecksum, result, quiet });
@@ -3019,14 +3350,19 @@ async function generateModuleRegistryCliFromDiscovery(options) {
3019
3350
  const legacyChecksumFile = path.join(outputDir, "cli-modules.generated.checksum");
3020
3351
  const commandLoadersOutFile = path.join(outputDir, "command-loaders.generated.ts");
3021
3352
  const commandLoadersChecksumFile = path.join(outputDir, "command-loaders.generated.checksum");
3353
+ const devSupervisorOutFile = path.join(outputDir, DEV_SUPERVISOR_MANIFEST_FILE);
3354
+ const devSupervisorChecksumFile = path.join(outputDir, "dev-supervisor.generated.checksum");
3022
3355
  const enabled = discovery.enabled;
3023
3356
  const imports = [];
3024
3357
  const moduleDecls = [];
3025
3358
  const importIdRef = { value: 0 };
3026
3359
  const requiresByModule = /* @__PURE__ */ new Map();
3027
3360
  const commandLoaderEntries = [];
3361
+ const devSupervisorWorkers = [];
3362
+ let schedulerStartStatus = "missing-module";
3363
+ let requiresFullBootstrap = enabled.some((entry) => entry.devSupervisorRequiresFullBootstrap === true) || appDeclaresProgrammaticDevSupervisorOverrides(resolver.getAppDir());
3028
3364
  for (const discovered of discovery.modules) {
3029
- const { modId, roots, imps, appImportBase } = discovered;
3365
+ const { modId, imps, appImportBase } = discovered;
3030
3366
  commandLoaderEntries.push(...discovered.commandLoaderEntries);
3031
3367
  let cliImportName = null;
3032
3368
  const translations = [];
@@ -3096,11 +3432,20 @@ async function generateModuleRegistryCliFromDiscovery(options) {
3096
3432
  if (fields) fieldsImportName = fields.importName;
3097
3433
  }
3098
3434
  {
3435
+ if (modId === "scheduler") schedulerStartStatus = "missing-cli";
3099
3436
  const cliResolved = discovered.resolve("cli.ts");
3100
3437
  if (cliResolved) {
3101
3438
  const importName = `CLI_${toVar(modId)}`;
3102
3439
  imports.push(buildImportStatement(importName, sanitizeGeneratedModuleSpecifier(cliResolved.importPath)));
3103
3440
  cliImportName = importName;
3441
+ if (modId === "scheduler") {
3442
+ if (sourceDeclaresCliCommand(cliResolved.absolutePath, "start")) {
3443
+ schedulerStartStatus = "ok";
3444
+ } else {
3445
+ schedulerStartStatus = "missing-command";
3446
+ requiresFullBootstrap = true;
3447
+ }
3448
+ }
3104
3449
  }
3105
3450
  }
3106
3451
  translations.push(...processTranslationsAst({
@@ -3111,7 +3456,10 @@ async function generateModuleRegistryCliFromDiscovery(options) {
3111
3456
  imports
3112
3457
  }));
3113
3458
  subscribers.push(...processSubscribersAst(await discovered.getSubscribers()));
3114
- workers.push(...processWorkersAst(await discovered.getWorkers()));
3459
+ const discoveredWorkers = await discovered.getWorkers();
3460
+ const workerGenerationEntries = collectWorkerGenerationEntries(discoveredWorkers, modId);
3461
+ workers.push(...processWorkersAst(discoveredWorkers));
3462
+ devSupervisorWorkers.push(...workerGenerationEntries.map(({ importPath: _importPath, ...worker }) => worker));
3115
3463
  {
3116
3464
  dashboardWidgetsValue = buildModuleDashboardWidgetsValue(discovered.dashboardWidgetEntries);
3117
3465
  }
@@ -3265,6 +3613,21 @@ async function generateModuleRegistryCliFromDiscovery(options) {
3265
3613
  const structureChecksum = discovery.getStructureChecksum();
3266
3614
  writeGeneratedFile({ outFile, checksumFile, content: output, structureChecksum, result, quiet });
3267
3615
  writeGeneratedFile({ outFile: legacyOutFile, checksumFile: legacyChecksumFile, content: legacyOutput, structureChecksum, result, quiet });
3616
+ const devSupervisorOutput = `${JSON.stringify({
3617
+ version: DEV_SUPERVISOR_MANIFEST_VERSION,
3618
+ workers: devSupervisorWorkers,
3619
+ schedulerStartStatus,
3620
+ requiresFullBootstrap
3621
+ }, null, 2)}
3622
+ `;
3623
+ writeGeneratedFile({
3624
+ outFile: devSupervisorOutFile,
3625
+ checksumFile: devSupervisorChecksumFile,
3626
+ content: devSupervisorOutput,
3627
+ structureChecksum,
3628
+ result,
3629
+ quiet
3630
+ });
3268
3631
  const commandLoadersOutput = renderCommandLoadersFile(commandLoaderEntries);
3269
3632
  writeGeneratedFile({ outFile: commandLoadersOutFile, checksumFile: commandLoadersChecksumFile, content: commandLoadersOutput, structureChecksum, result, quiet });
3270
3633
  return result;