@zenbujs/core 0.0.4 → 0.0.8

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/dist/{advice-config-BLXjqjGN.mjs → advice-config-DXSIo0sg.mjs} +49 -38
  2. package/dist/advice.d.mts +8 -8
  3. package/dist/advice.mjs +2 -2
  4. package/dist/base-window-BxBZ2md_.mjs +143 -0
  5. package/dist/build-config-Dzg2frpk.d.mts +215 -0
  6. package/dist/build-config-pWdmLnrk.mjs +53 -0
  7. package/dist/{build-electron-C3Beey84.mjs → build-electron-Dsbb1EMl.mjs} +308 -120
  8. package/dist/{build-source-BvC4bPqH.mjs → build-source-d1J3shV8.mjs} +62 -27
  9. package/dist/chunk-DsiFFCwN.mjs +16 -0
  10. package/dist/cli/bin.mjs +7 -7
  11. package/dist/cli/build.d.mts +2 -2
  12. package/dist/cli/build.mjs +2 -3
  13. package/dist/cli/resolve-config.mjs +3 -2
  14. package/dist/{cli-F0B4dvSg.mjs → cli-kL6mPgBE.mjs} +4 -4
  15. package/dist/{config-BlRXeUXx.mjs → config-BK78JDRI.mjs} +1 -1
  16. package/dist/config.d.mts +3 -2
  17. package/dist/config.mjs +3 -3
  18. package/dist/{db-Cd5ETuPG.mjs → db-Bc292RYo.mjs} +2 -2
  19. package/dist/db.d.mts +1 -1
  20. package/dist/db.mjs +2 -2
  21. package/dist/dev-B2emj0HZ.mjs +301 -0
  22. package/dist/env-bootstrap.d.mts +1 -1
  23. package/dist/env-bootstrap.mjs +52 -1
  24. package/dist/events.d.mts +19 -0
  25. package/dist/events.mjs +1 -0
  26. package/dist/host-version-BIrF8tX7.mjs +65 -0
  27. package/dist/index-w5QyDjuf.d.mts +780 -0
  28. package/dist/index.d.mts +5 -6
  29. package/dist/index.mjs +5 -5
  30. package/dist/installing-preload.cjs +60 -0
  31. package/dist/launcher.mjs +2615 -122
  32. package/dist/{link-BJmsKgPa.mjs → link-glX89NV5.mjs} +215 -89
  33. package/dist/{load-config-BG2tPIfF.mjs → load-config-C4Oe2qZO.mjs} +22 -3
  34. package/dist/loaders/zenbu.d.mts +1 -0
  35. package/dist/loaders/zenbu.mjs +108 -86
  36. package/dist/{monorepo-DCruz9Jx.mjs → monorepo-Dct-kkbQ.mjs} +3 -0
  37. package/dist/node-loader.mjs +1 -1
  38. package/dist/{publish-source-34Hn9zb0.mjs → publish-source-Dq2c0iOw.mjs} +2 -2
  39. package/dist/react.d.mts +56 -7
  40. package/dist/react.mjs +118 -7
  41. package/dist/registry-CMp8FYgS.d.mts +47 -0
  42. package/dist/registry-generated.d.mts +26 -0
  43. package/dist/registry-generated.mjs +1 -0
  44. package/dist/registry.d.mts +2 -2
  45. package/dist/{reloader-DJoCB0bC.mjs → reloader-B22UiNA2.mjs} +7 -7
  46. package/dist/{renderer-host-ztaSIOGx.mjs → renderer-host-DD16MXhI.mjs} +178 -57
  47. package/dist/{rpc-CsgWnlZx.mjs → rpc-C4_NQmpT.mjs} +11 -8
  48. package/dist/rpc.d.mts +1 -1
  49. package/dist/rpc.mjs +1 -1
  50. package/dist/runtime-BQWntcOb.d.mts +218 -0
  51. package/dist/runtime.d.mts +2 -2
  52. package/dist/runtime.mjs +578 -2
  53. package/dist/{schema-DvT61x2_.d.mts → schema-CjrMVk36.d.mts} +3 -3
  54. package/dist/schema.d.mts +1 -1
  55. package/dist/schema.mjs +27 -1
  56. package/dist/{server-DB3Eki_G.mjs → server-CZLMF8Dj.mjs} +6 -6
  57. package/dist/services/default.d.mts +3 -3
  58. package/dist/services/default.mjs +14 -13
  59. package/dist/services/index.d.mts +2 -276
  60. package/dist/services/index.mjs +8 -7
  61. package/dist/setup-gate.d.mts +1 -1
  62. package/dist/setup-gate.mjs +341 -1
  63. package/dist/{transform-DJH3vN4b.mjs → transform-BzrwkEdf.mjs} +23 -917
  64. package/dist/{transport-BMSzG2-F.mjs → transport-F2hv_OEm.mjs} +1 -1
  65. package/dist/updater-DCkz9M1c.mjs +1008 -0
  66. package/dist/{vite-plugins-t4MlFcz3.mjs → vite-plugins-tt6KAtyE.mjs} +27 -26
  67. package/dist/vite.d.mts +3 -3
  68. package/dist/vite.mjs +1 -1
  69. package/dist/{window-DUvMTons.mjs → window-YFKvAM0l.mjs} +36 -19
  70. package/dist/{write-9dRFczGJ.mjs → write-DgIRjo23.mjs} +1 -1
  71. package/package.json +18 -5
  72. package/dist/advice-config-D6K_a7e9.mjs +0 -2
  73. package/dist/base-window-D8CpxMU3.mjs +0 -94
  74. package/dist/base-window-OXg2KSyP.mjs +0 -2
  75. package/dist/build-config-BwnnfrN-.mjs +0 -23
  76. package/dist/chunk-Dm34NbLt.mjs +0 -6
  77. package/dist/config-Ch1FreWU.mjs +0 -2
  78. package/dist/db-Bz_CDIWg.mjs +0 -2
  79. package/dist/dev-DLutFPyo.mjs +0 -85
  80. package/dist/env-bootstrap-rj7I-59x.mjs +0 -53
  81. package/dist/http-B36qtsm0.mjs +0 -2
  82. package/dist/load-config-CQG4297M.mjs +0 -2
  83. package/dist/registry-CioEYLI5.d.mts +0 -61
  84. package/dist/reloader-FeHKV2jd.mjs +0 -2
  85. package/dist/renderer-host-BQpS0ZM2.mjs +0 -2
  86. package/dist/rpc-D_s7-WZe.mjs +0 -2
  87. package/dist/runtime-C95iyVn6.mjs +0 -461
  88. package/dist/runtime-CsiDppGF.d.mts +0 -149
  89. package/dist/schema-dGK6qkfR.mjs +0 -28
  90. package/dist/server-CgzQOPSW.mjs +0 -2
  91. package/dist/setup-gate-D8XfYY52.mjs +0 -140
  92. package/dist/transforms-DVoy8dCu.mjs +0 -47
  93. package/dist/transforms-EVd5Fgyk.d.mts +0 -136
  94. package/dist/view-registry-2zePxTEg.mjs +0 -2
  95. package/dist/window-S3TlTXlK.mjs +0 -2
  96. /package/dist/{env-bootstrap-uCKbw2q8.d.mts → env-bootstrap-rTs8KR3-.d.mts} +0 -0
  97. /package/dist/{index-CE0iPntP.d.mts → index-C-ALz_SH.d.mts} +0 -0
  98. /package/dist/{index-CKKoxA9V.d.mts → index-ClXLQ1fw.d.mts} +0 -0
  99. /package/dist/{index-UK58xuoR.d.mts → index-DeDxePAa.d.mts} +0 -0
  100. /package/dist/{log-CyKv8hQg.mjs → log-6rzaCV0I.mjs} +0 -0
  101. /package/dist/{mirror-sync-EiWvdzTJ.mjs → mirror-sync-pYU6f3-c.mjs} +0 -0
  102. /package/dist/{node-CvZnTx53.mjs → node-BhfLKYCi.mjs} +0 -0
  103. /package/dist/{schema-CIg4GzHQ.mjs → schema-Ca7SxXgS.mjs} +0 -0
  104. /package/dist/{setup-gate-D62nX5lk.d.mts → setup-gate-BQq0QgZH.d.mts} +0 -0
  105. /package/dist/{src-pELM4_iH.mjs → src-Cven45mq.mjs} +0 -0
  106. /package/dist/{trace-DCB7qFzT.mjs → trace-BaVg0rnY.mjs} +0 -0
@@ -1,7 +1,12 @@
1
- import { n as loadConfig } from "./load-config-BG2tPIfF.mjs";
1
+ import { n as __exportAll } from "./chunk-DsiFFCwN.mjs";
2
+ import { t as loadConfig } from "./load-config-C4Oe2qZO.mjs";
2
3
  import fs from "node:fs";
3
4
  import path from "node:path";
4
5
  //#region src/cli/commands/link.ts
6
+ var link_exports = /* @__PURE__ */ __exportAll({
7
+ linkProject: () => linkProject,
8
+ runLink: () => runLink
9
+ });
5
10
  const CONFIG_NAMES = [
6
11
  "zenbu.config.ts",
7
12
  "zenbu.config.mts",
@@ -79,13 +84,7 @@ function resolveRegistryDir(opts) {
79
84
  if (opts.manifest.devAppPath) return path.resolve(manifestDir, opts.manifest.devAppPath, "types");
80
85
  const appRoot = findAppRoot(manifestDir);
81
86
  if (appRoot) return path.join(appRoot, "types");
82
- console.error(`zen link: could not determine target types directory for ${opts.manifestPath}.`);
83
- console.error(` Try one of:`);
84
- console.error(` - run from inside an app dir (with a zenbu.config.ts),`);
85
- console.error(` - add a "devAppPath" field to ${path.basename(opts.manifestPath)} pointing at the host app,`);
86
- console.error(` - create a tsconfig.local.json with a "#registry/*" path mapping,`);
87
- console.error(` - or pass --registry <dir>.`);
88
- process.exit(1);
87
+ throw new Error(`zen link: could not determine target types directory for ${opts.manifestPath}.\n Try one of:\n - run from inside an app dir (with a zenbu.config.ts),\n - add a "devAppPath" field to ${path.basename(opts.manifestPath)} pointing at the host app,\n - create a tsconfig.local.json with a "#registry/*" path mapping,\n - or pass --registry <dir>.`);
89
88
  }
90
89
  function expandGlob(baseDir, pattern) {
91
90
  if (!pattern.includes("*")) {
@@ -103,15 +102,12 @@ function expandGlob(baseDir, pattern) {
103
102
  }
104
103
  function discoverServices(baseDir, serviceGlobs) {
105
104
  const entries = [];
106
- const classRe = /export\s+class\s+(\w+)\s+extends\s+(?:Service\b|serviceWithDeps\s*\()/;
107
- const keyRe = /static\s+key\s*=\s*["']([^"']+)["']/;
105
+ const classKeyRe = /export\s+class\s+(\w+)\s+extends\s+Service\.create\s*\(\s*\{[\s\S]*?\bkey\s*:\s*["']([^"']+)["']/;
108
106
  for (const glob of serviceGlobs) for (const filePath of expandGlob(baseDir, glob)) {
109
- const content = fs.readFileSync(filePath, "utf8");
110
- const classMatch = content.match(classRe);
111
- const keyMatch = content.match(keyRe);
112
- if (classMatch && keyMatch) entries.push({
113
- className: classMatch[1],
114
- key: keyMatch[1],
107
+ const match = fs.readFileSync(filePath, "utf8").match(classKeyRe);
108
+ if (match) entries.push({
109
+ className: match[1],
110
+ key: match[2],
115
111
  filePath
116
112
  });
117
113
  }
@@ -150,7 +146,7 @@ function generateServicesFile(registryDir, allServices) {
150
146
  return [
151
147
  "// Generated by: zen link",
152
148
  "",
153
- `import type { CoreServiceRouter } from "@zenbujs/core/registry"`,
149
+ `import type { CoreServiceRouter } from "@zenbujs/core/registry-generated"`,
154
150
  ...imports,
155
151
  "",
156
152
  `type ServiceBase =\n${SERVICE_BASE_LITERAL}`,
@@ -190,7 +186,7 @@ function generatePreloadsFile(registryDir, allPreloads) {
190
186
  return [
191
187
  "// Generated by: zen link",
192
188
  "",
193
- `import type { CorePreloads } from "@zenbujs/core/registry"`,
189
+ `import type { CorePreloads } from "@zenbujs/core/registry-generated"`,
194
190
  ...imports,
195
191
  "",
196
192
  "export type PluginPreloads = {",
@@ -220,7 +216,7 @@ function generateEventsFile(registryDir, allEvents) {
220
216
  return [
221
217
  "// Generated by: zen link",
222
218
  "",
223
- `import type { CoreEvents } from "@zenbujs/core/registry"`,
219
+ `import type { CoreEvents } from "@zenbujs/core/registry-generated"`,
224
220
  ...imports,
225
221
  "",
226
222
  "/**",
@@ -245,6 +241,7 @@ function generateRegisterFile() {
245
241
  return [
246
242
  "// Generated by: zen link",
247
243
  "",
244
+ `import type {} from "@zenbujs/core/registry"`,
248
245
  `import type { DbRoot } from "./db-sections"`,
249
246
  `import type { ServiceRouter } from "./services"`,
250
247
  `import type { PluginEvents } from "./events"`,
@@ -280,7 +277,7 @@ function generateDbSectionsFile(registryDir, allSchemas) {
280
277
  return [
281
278
  "// Generated by: zen link",
282
279
  "",
283
- `import type { CoreDbSections } from "@zenbujs/core/registry"`,
280
+ `import type { CoreDbSections } from "@zenbujs/core/registry-generated"`,
284
281
  ...imports,
285
282
  "",
286
283
  "export type PluginDbSections = {",
@@ -367,18 +364,26 @@ function parseLinkArgs(argv) {
367
364
  let manifestArg = null;
368
365
  let typesConfigArg = null;
369
366
  let registryOverride = null;
367
+ let surfaceOutArg = null;
368
+ let augmentOutArg = null;
370
369
  for (let i = 0; i < argv.length; i++) {
371
370
  const arg = argv[i];
372
371
  if (arg === "--registry" && i + 1 < argv.length) registryOverride = argv[++i];
373
372
  else if (arg.startsWith("--registry=")) registryOverride = arg.slice(11);
374
373
  else if (arg === "--types-config" && i + 1 < argv.length) typesConfigArg = argv[++i];
375
374
  else if (arg.startsWith("--types-config=")) typesConfigArg = arg.slice(15);
375
+ else if (arg === "--out" && i + 1 < argv.length) surfaceOutArg = argv[++i];
376
+ else if (arg.startsWith("--out=")) surfaceOutArg = arg.slice(6);
377
+ else if (arg === "--augment-out" && i + 1 < argv.length) augmentOutArg = argv[++i];
378
+ else if (arg.startsWith("--augment-out=")) augmentOutArg = arg.slice(14);
376
379
  else if (!arg.startsWith("-") && !manifestArg) manifestArg = arg;
377
380
  }
378
381
  return {
379
382
  manifestArg,
380
383
  typesConfigArg,
381
- registryOverride
384
+ registryOverride,
385
+ surfaceOutArg,
386
+ augmentOutArg
382
387
  };
383
388
  }
384
389
  /**
@@ -386,26 +391,27 @@ function parseLinkArgs(argv) {
386
391
  * export is a `definePlugin({...})`). Resolved upstream by `loadConfig` so
387
392
  * we just consume the resolved record here.
388
393
  */
389
- function linkResolvedPlugin(plugin, existing) {
390
- console.log(`Linking types "${plugin.name}" from ${plugin.dir}`);
394
+ function linkResolvedPlugin(plugin, existing, opts) {
395
+ const log = opts.quiet ? () => {} : (msg) => console.log(msg);
396
+ log(`Linking types "${plugin.name}" from ${plugin.dir}`);
391
397
  const serviceGlobs = plugin.services.map((abs) => path.relative(plugin.dir, abs).split(path.sep).join("/"));
392
398
  const serviceEntries = discoverServices(plugin.dir, serviceGlobs);
393
- console.log(` Found ${serviceEntries.length} service(s)`);
399
+ log(` Found ${serviceEntries.length} service(s)`);
394
400
  const schemaEntry = plugin.schemaPath ? {
395
401
  name: plugin.name,
396
402
  schemaPath: plugin.schemaPath
397
403
  } : null;
398
- if (schemaEntry) console.log(` Schema: ${schemaEntry.schemaPath}`);
404
+ if (schemaEntry) log(` Schema: ${schemaEntry.schemaPath}`);
399
405
  const preloadEntry = plugin.preloadPath ? {
400
406
  name: plugin.name,
401
407
  preloadPath: plugin.preloadPath
402
408
  } : null;
403
- if (preloadEntry) console.log(` Preload: ${preloadEntry.preloadPath}`);
409
+ if (preloadEntry) log(` Preload: ${preloadEntry.preloadPath}`);
404
410
  const eventsEntry = plugin.eventsPath ? {
405
411
  name: plugin.name,
406
412
  eventsPath: plugin.eventsPath
407
413
  } : null;
408
- if (eventsEntry) console.log(` Events: ${eventsEntry.eventsPath}`);
414
+ if (eventsEntry) log(` Events: ${eventsEntry.eventsPath}`);
409
415
  existing.services.set(plugin.name, serviceEntries);
410
416
  if (schemaEntry) existing.schemas.set(plugin.name, schemaEntry);
411
417
  if (preloadEntry) existing.preloads.set(plugin.name, preloadEntry);
@@ -414,39 +420,116 @@ function linkResolvedPlugin(plugin, existing) {
414
420
  else existing.events.delete(plugin.name);
415
421
  }
416
422
  /**
417
- * Variant for the framework-internal `--types-config <path>` flow where the
418
- * input is a small JSON file (e.g. `packages/core/zenbu-types.config.json`).
419
- * Used by `pnpm link:types` inside core to bake its own services/registry
420
- * types without going through a `zenbu.config.ts`.
423
+ * Generator: `<core>/src/registry-generated.ts` the publishable
424
+ * type surface that downstream apps' `zen link`-generated files
425
+ * import from `@zenbujs/core/registry-generated`.
426
+ *
427
+ * Imports use public package exports (`@zenbujs/core/services`,
428
+ * `/events`, `/schema`) so the file resolves in any consumer
429
+ * regardless of how `@zenbujs/core` is installed.
421
430
  */
422
- function linkTypesConfig(jsonPath, existing) {
423
- const manifest = JSON.parse(fs.readFileSync(jsonPath, "utf8"));
424
- const pluginName = manifest.name;
425
- const baseDir = path.dirname(jsonPath);
426
- console.log(`Linking types "${pluginName}" from ${baseDir}`);
427
- const serviceEntries = discoverServices(baseDir, manifest.services ?? []);
428
- console.log(` Found ${serviceEntries.length} service(s)`);
429
- const schemaEntry = manifest.schema ? {
430
- name: pluginName,
431
- schemaPath: path.resolve(baseDir, manifest.schema)
432
- } : null;
433
- if (schemaEntry) console.log(` Schema: ${schemaEntry.schemaPath}`);
434
- const preloadEntry = manifest.preload ? {
435
- name: pluginName,
436
- preloadPath: path.resolve(baseDir, manifest.preload)
437
- } : null;
438
- if (preloadEntry) console.log(` Preload: ${preloadEntry.preloadPath}`);
439
- const eventsEntry = manifest.events ? {
440
- name: pluginName,
441
- eventsPath: path.resolve(baseDir, manifest.events)
442
- } : null;
443
- if (eventsEntry) console.log(` Events: ${eventsEntry.eventsPath}`);
444
- existing.services.set(pluginName, serviceEntries);
445
- if (schemaEntry) existing.schemas.set(pluginName, schemaEntry);
446
- if (preloadEntry) existing.preloads.set(pluginName, preloadEntry);
447
- else existing.preloads.delete(pluginName);
448
- if (eventsEntry) existing.events.set(pluginName, eventsEntry);
449
- else existing.events.delete(pluginName);
431
+ function generateCoreSurfaceFile(args) {
432
+ const sorted = [...args.services].sort((a, b) => a.className.localeCompare(b.className));
433
+ const importedNames = sorted.map((s) => ` ${s.className},`).join("\n");
434
+ const routerEntries = sorted.map((s) => {
435
+ return ` ${/^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(s.key) ? s.key : `"${s.key}"`}: ExtractRpcMethods<${s.className}>;`;
436
+ }).join("\n");
437
+ const lines = [
438
+ "// Generated by: pnpm link:types",
439
+ "// DO NOT EDIT. Regenerated automatically (also wired into `prebuild`).",
440
+ ""
441
+ ];
442
+ if (sorted.length > 0) {
443
+ lines.push("import type {");
444
+ lines.push(importedNames);
445
+ lines.push(`} from "@zenbujs/core/services"`);
446
+ }
447
+ if (args.hasEvents) lines.push(`import type { Events as Events_core } from "@zenbujs/core/events"`);
448
+ if (args.hasSchema) lines.push(`import type { SchemaRoot as SchemaRoot_core } from "@zenbujs/core/schema"`);
449
+ lines.push("");
450
+ lines.push(`type ServiceBase =\n${SERVICE_BASE_LITERAL}`);
451
+ lines.push("");
452
+ lines.push("type ExtractRpcMethods<T> = {");
453
+ lines.push(" [K in Exclude<keyof T, ServiceBase | `_${string}`> as T[K] extends (");
454
+ lines.push(" ...args: any[]");
455
+ lines.push(" ) => any");
456
+ lines.push(" ? K");
457
+ lines.push(" : never]: T[K]");
458
+ lines.push("}");
459
+ lines.push("");
460
+ lines.push("export type CoreServiceRouter = {");
461
+ if (routerEntries.length > 0) lines.push(routerEntries);
462
+ lines.push("}");
463
+ lines.push("");
464
+ lines.push(`export type CoreEvents = ${args.hasEvents ? "Events_core" : "{}"}`);
465
+ lines.push("");
466
+ lines.push("export type CoreDbSections = {");
467
+ if (args.hasSchema) lines.push(" core: SchemaRoot_core;");
468
+ lines.push("}");
469
+ lines.push("");
470
+ lines.push("export type CorePreloads = {}");
471
+ lines.push("");
472
+ return lines.join("\n");
473
+ }
474
+ /**
475
+ * Generator: `<core>/types/zenbu-register.ts` — local-only
476
+ * augmentation that drives core's OWN typecheck. Pulls
477
+ * `Core*` types from the relative path `../src/registry-generated`
478
+ * (so it works without depending on package self-resolution) and
479
+ * declares the `ZenbuRegister` augmentation. NOT in
480
+ * `package.json#files`; never reaches downstream consumers (where
481
+ * it would conflict with their own augmentation).
482
+ */
483
+ function generateCoreAugmentFile() {
484
+ return [
485
+ "// Generated by: pnpm link:types",
486
+ "// DO NOT EDIT. Local-only augmentation (NOT shipped via package.json#files).",
487
+ "// Drives core's own typecheck so useRpc()/useEvents()/useDb() resolve",
488
+ "// to the registered surface inside packages/core/src/.",
489
+ "",
490
+ `import type {} from "@zenbujs/core/registry"`,
491
+ `import type {`,
492
+ ` CoreServiceRouter,`,
493
+ ` CoreEvents,`,
494
+ ` CoreDbSections,`,
495
+ `} from "../src/registry-generated"`,
496
+ "",
497
+ `declare module "@zenbujs/core/registry" {`,
498
+ " interface ZenbuRegister {",
499
+ " rpc: CoreServiceRouter",
500
+ " events: CoreEvents",
501
+ " db: { plugin: CoreDbSections }",
502
+ " }",
503
+ "}",
504
+ "",
505
+ "export {}",
506
+ ""
507
+ ].join("\n");
508
+ }
509
+ /**
510
+ * Two-file write for the `--types-config` flow: the publishable
511
+ * surface (`registry-generated.ts`) plus the local-only
512
+ * augmentation (`zenbu-register.ts`). Skips writes when content is
513
+ * identical so downstream watchers (Vite, tsc --watch) don't see
514
+ * spurious mtime bumps.
515
+ */
516
+ function writeCoreSurfaceFiles(args) {
517
+ const surface = generateCoreSurfaceFile({
518
+ services: args.services,
519
+ hasEvents: args.hasEvents,
520
+ hasSchema: args.hasSchema
521
+ });
522
+ const augment = generateCoreAugmentFile();
523
+ for (const [target, body] of [[args.surfaceOut, surface], [args.augmentOut, augment]]) {
524
+ fs.mkdirSync(path.dirname(target), { recursive: true });
525
+ let prev = null;
526
+ try {
527
+ prev = fs.readFileSync(target, "utf8");
528
+ } catch {}
529
+ if (prev === body) continue;
530
+ fs.writeFileSync(target, body);
531
+ if (!args.quiet) console.log(` Wrote ${target}`);
532
+ }
450
533
  }
451
534
  /**
452
535
  * Per-install bootstrap for a plugin. The plugin ships a portable
@@ -472,7 +555,7 @@ function linkTypesConfig(jsonPath, existing) {
472
555
  * `"extends": "./tsconfig.local.json"`. The generated file then carries
473
556
  * `paths` + `include`, which TS merges into the IDE's resolved program.
474
557
  */
475
- function writePluginTsconfigLocal(pluginDir, registryDir) {
558
+ function writePluginTsconfigLocal(pluginDir, registryDir, opts) {
476
559
  const ownTsconfig = path.join(pluginDir, "tsconfig.json");
477
560
  if (!fs.existsSync(ownTsconfig)) return;
478
561
  for (const name of CONFIG_NAMES) if (fs.existsSync(path.join(pluginDir, name))) return;
@@ -490,23 +573,67 @@ function writePluginTsconfigLocal(pluginDir, registryDir) {
490
573
  } catch {}
491
574
  if (prev === next) return;
492
575
  fs.writeFileSync(target, next);
493
- console.log(` Wrote ${target}`);
576
+ if (!opts.quiet) console.log(` Wrote ${target}`);
577
+ }
578
+ /**
579
+ * Programmatic variant of `zen link` for the host-project flow. Throws on
580
+ * any error instead of `process.exit`. Used by:
581
+ * - `runLink` (CLI entry)
582
+ * - `link-watcher.ts` (file watcher used by `zen dev`)
583
+ *
584
+ * `quiet: true` suppresses the per-step console output the CLI emits — the
585
+ * watcher uses this so the dev terminal stays clean across rapid edits.
586
+ */
587
+ async function linkProject(projectDir, opts = {}) {
588
+ const log = opts.quiet ? () => {} : (msg) => console.log(msg);
589
+ const { resolved, pluginSourceFiles } = await loadConfig(projectDir);
590
+ const registryDir = resolveRegistryDir({
591
+ manifestPath: resolved.configPath,
592
+ manifest: {},
593
+ registryOverride: opts.registryOverride ?? null
594
+ });
595
+ log(`Registry: ${registryDir}`);
596
+ fs.mkdirSync(registryDir, { recursive: true });
597
+ const existing = readExistingRegistry(registryDir);
598
+ for (const plugin of resolved.plugins) linkResolvedPlugin(plugin, existing, { quiet: !!opts.quiet });
599
+ writeRegistryFiles(registryDir, existing, { quiet: !!opts.quiet });
600
+ for (const plugin of resolved.plugins) writePluginTsconfigLocal(plugin.dir, registryDir, { quiet: !!opts.quiet });
601
+ return {
602
+ registryDir,
603
+ resolvedConfigPath: resolved.configPath,
604
+ pluginSourceFiles,
605
+ resolved
606
+ };
494
607
  }
495
608
  async function runLink(argv) {
496
- const { manifestArg, typesConfigArg, registryOverride } = parseLinkArgs(argv);
609
+ const { manifestArg, typesConfigArg, registryOverride, surfaceOutArg, augmentOutArg } = parseLinkArgs(argv);
497
610
  if (typesConfigArg) {
498
611
  const typeConfigPath = path.resolve(typesConfigArg);
499
- const registryDir = resolveRegistryDir({
500
- manifestPath: typeConfigPath,
501
- manifest: JSON.parse(fs.readFileSync(typeConfigPath, "utf8")),
502
- registryOverride
503
- });
504
- console.log(`Registry: ${registryDir}`);
505
- fs.mkdirSync(registryDir, { recursive: true });
506
- const existing = readExistingRegistry(registryDir);
507
- linkTypesConfig(typeConfigPath, existing);
508
- writeRegistryFiles(registryDir, existing);
509
- console.log("Done.");
612
+ const rootManifest = JSON.parse(fs.readFileSync(typeConfigPath, "utf8"));
613
+ const baseDir = path.dirname(typeConfigPath);
614
+ const surfaceOut = surfaceOutArg ? path.resolve(surfaceOutArg) : path.join(baseDir, "src", "registry-generated.ts");
615
+ const augmentOut = augmentOutArg ? path.resolve(augmentOutArg) : path.join(baseDir, "types", "zenbu-register.ts");
616
+ try {
617
+ console.log(`Linking core types from ${baseDir}`);
618
+ const services = discoverServices(baseDir, rootManifest.services ?? []);
619
+ console.log(` Found ${services.length} service(s)`);
620
+ const hasEvents = !!rootManifest.events;
621
+ const hasSchema = !!rootManifest.schema;
622
+ if (rootManifest.events) console.log(` Events: ${path.resolve(baseDir, rootManifest.events)}`);
623
+ if (rootManifest.schema) console.log(` Schema: ${path.resolve(baseDir, rootManifest.schema)}`);
624
+ writeCoreSurfaceFiles({
625
+ services,
626
+ hasEvents,
627
+ hasSchema,
628
+ surfaceOut,
629
+ augmentOut,
630
+ quiet: false
631
+ });
632
+ console.log("Done.");
633
+ } catch (err) {
634
+ console.error(err instanceof Error ? err.message : err);
635
+ process.exit(1);
636
+ }
510
637
  return;
511
638
  }
512
639
  const projectDir = manifestArg ? path.resolve(manifestArg) : findProjectDir(process.cwd());
@@ -515,21 +642,15 @@ async function runLink(argv) {
515
642
  console.error(" For internal framework types, pass --types-config <path>.");
516
643
  process.exit(1);
517
644
  }
518
- const { resolved } = await loadConfig(projectDir);
519
- const registryDir = resolveRegistryDir({
520
- manifestPath: resolved.configPath,
521
- manifest: {},
522
- registryOverride
523
- });
524
- console.log(`Registry: ${registryDir}`);
525
- fs.mkdirSync(registryDir, { recursive: true });
526
- const existing = readExistingRegistry(registryDir);
527
- for (const plugin of resolved.plugins) linkResolvedPlugin(plugin, existing);
528
- writeRegistryFiles(registryDir, existing);
529
- for (const plugin of resolved.plugins) writePluginTsconfigLocal(plugin.dir, registryDir);
530
- console.log("Done.");
645
+ try {
646
+ await linkProject(projectDir, { registryOverride });
647
+ console.log("Done.");
648
+ } catch (err) {
649
+ console.error(err instanceof Error ? err.message : err);
650
+ process.exit(1);
651
+ }
531
652
  }
532
- function writeRegistryFiles(registryDir, existing) {
653
+ function writeRegistryFiles(registryDir, existing, opts) {
533
654
  const writes = [
534
655
  ["services.ts", generateServicesFile(registryDir, existing.services)],
535
656
  ["db-sections.ts", generateDbSectionsFile(registryDir, existing.schemas)],
@@ -539,9 +660,14 @@ function writeRegistryFiles(registryDir, existing) {
539
660
  ];
540
661
  for (const [name, body] of writes) {
541
662
  const target = path.join(registryDir, name);
663
+ let prev = null;
664
+ try {
665
+ prev = fs.readFileSync(target, "utf8");
666
+ } catch {}
667
+ if (prev === body) continue;
542
668
  fs.writeFileSync(target, body);
543
- console.log(` Wrote ${target}`);
669
+ if (!opts.quiet) console.log(` Wrote ${target}`);
544
670
  }
545
671
  }
546
672
  //#endregion
547
- export { runLink };
673
+ export { link_exports as n, linkProject as t };
@@ -1,9 +1,14 @@
1
- import { i as resolveBuildConfig } from "./build-config-BwnnfrN-.mjs";
1
+ import { n as __exportAll } from "./chunk-DsiFFCwN.mjs";
2
+ import { i as resolveBuildConfig } from "./build-config-pWdmLnrk.mjs";
2
3
  import { createRequire } from "node:module";
3
4
  import fs from "node:fs";
4
5
  import path from "node:path";
5
6
  import { pathToFileURL } from "node:url";
6
7
  //#region src/cli/lib/load-config.ts
8
+ var load_config_exports = /* @__PURE__ */ __exportAll({
9
+ findConfigPath: () => findConfigPath,
10
+ loadConfig: () => loadConfig
11
+ });
7
12
  const localRequire = createRequire(import.meta.url);
8
13
  const CONFIG_NAMES = [
9
14
  "zenbu.config.ts",
@@ -95,11 +100,22 @@ async function loadConfig(projectDir) {
95
100
  const config = await importFresh(configPath);
96
101
  if (!config || typeof config !== "object") throw new Error(`${configPath} default export is not a Config object.`);
97
102
  if (typeof config.db !== "string" || config.db.length === 0) throw new Error(`${configPath}: missing required \`db\` field (path to the database directory).`);
98
- if (typeof config.uiEntrypoint !== "string" || config.uiEntrypoint.length === 0) throw new Error(`${configPath}: missing required \`uiEntrypoint\` field (path to the boot-window HTML file).`);
103
+ if (typeof config.uiEntrypoint !== "string" || config.uiEntrypoint.length === 0) throw new Error(`${configPath}: missing required \`uiEntrypoint\` field (directory holding index.html + splash.html).`);
99
104
  if (!Array.isArray(config.plugins)) throw new Error(`${configPath}: \`plugins\` must be an array.`);
100
105
  const configDir = path.dirname(configPath);
101
106
  const dbPath = path.isAbsolute(config.db) ? config.db : path.resolve(configDir, config.db);
102
107
  const uiEntrypointPath = path.isAbsolute(config.uiEntrypoint) ? config.uiEntrypoint : path.resolve(configDir, config.uiEntrypoint);
108
+ if (!(() => {
109
+ try {
110
+ return fs.statSync(uiEntrypointPath);
111
+ } catch {
112
+ return null;
113
+ }
114
+ })()?.isDirectory()) throw new Error(`${configPath}: uiEntrypoint must point at a directory; got ${config.uiEntrypoint}.`);
115
+ const splashPath = path.join(uiEntrypointPath, "splash.html");
116
+ if (!fs.existsSync(splashPath)) throw new Error(`${configPath}: uiEntrypoint directory ${config.uiEntrypoint} is missing required \`splash.html\`. The splash file is shown raw (no Vite) during the brief window between Electron startup and the app's first paint.`);
117
+ const installingCandidate = path.join(uiEntrypointPath, "installing.html");
118
+ const installingPath = fs.existsSync(installingCandidate) ? installingCandidate : void 0;
103
119
  const plugins = [];
104
120
  const pluginSourceFiles = [];
105
121
  for (const entry of config.plugins) {
@@ -113,8 +129,11 @@ async function loadConfig(projectDir) {
113
129
  projectDir: configDir,
114
130
  dbPath,
115
131
  uiEntrypointPath,
132
+ splashPath,
133
+ installingPath,
116
134
  plugins,
117
135
  build: resolveBuildConfig(config.build ?? {
136
+ hostVersion: "0.0.0",
118
137
  source: ".",
119
138
  include: ["**/*"]
120
139
  })
@@ -123,4 +142,4 @@ async function loadConfig(projectDir) {
123
142
  };
124
143
  }
125
144
  //#endregion
126
- export { loadConfig as n, findConfigPath as t };
145
+ export { load_config_exports as n, loadConfig as t };
@@ -31,6 +31,7 @@ interface ResolvedPluginRecord {
31
31
  interface RegistryPayload {
32
32
  plugins: ResolvedPluginRecord[];
33
33
  appEntrypoint: string;
34
+ splashPath: string;
34
35
  }
35
36
  declare function resolve(specifier: string, context: LoaderContext, nextResolve: NextResolve): unknown;
36
37
  declare function load(url: string, context: LoaderContext, nextLoad: NextLoad): unknown;