@zenbujs/core 0.0.9 → 0.0.12

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 (82) hide show
  1. package/dist/advice-config-BiYhyeTz.d.mts +41 -0
  2. package/dist/advice.d.mts +2 -36
  3. package/dist/advice.mjs +2 -2
  4. package/dist/{base-window-BxBZ2md_.mjs → base-window-4P-fVvC_.mjs} +37 -26
  5. package/dist/{build-config-Dzg2frpk.d.mts → build-config-GF0XzR_Y.d.mts} +42 -18
  6. package/dist/{build-config-pWdmLnrk.mjs → build-config-HMMqpXI1.mjs} +0 -8
  7. package/dist/{build-electron-Dsbb1EMl.mjs → build-electron-Di_FE62r.mjs} +10 -6
  8. package/dist/{build-source-d1J3shV8.mjs → build-source-BIaWpaxE.mjs} +2 -2
  9. package/dist/cli/bin.mjs +7 -7
  10. package/dist/cli/build.d.mts +1 -1
  11. package/dist/cli/build.mjs +1 -1
  12. package/dist/cli/resolve-config.mjs +6 -1
  13. package/dist/{cli-kL6mPgBE.mjs → cli-5jFDJWM4.mjs} +4 -4
  14. package/dist/config.d.mts +3 -3
  15. package/dist/config.mjs +2 -2
  16. package/dist/{db-Bc292RYo.mjs → db-MkOccvBS.mjs} +2 -2
  17. package/dist/db.d.mts +3 -2
  18. package/dist/db.mjs +2 -10
  19. package/dist/{dev-B2emj0HZ.mjs → dev-BSDyzO4j.mjs} +3 -9
  20. package/dist/env-bootstrap.d.mts +1 -1
  21. package/dist/events.d.mts +0 -9
  22. package/dist/{host-version-BIrF8tX7.mjs → host-version-Cog_odmD.mjs} +4 -3
  23. package/dist/{index-CVF768Xs.d.mts → index-C0mXKol5.d.mts} +188 -143
  24. package/dist/{index-DeDxePAa.d.mts → index-FaexRVl_.d.mts} +13 -1
  25. package/dist/index.d.mts +4 -4
  26. package/dist/index.mjs +2 -2
  27. package/dist/launcher.mjs +64 -6
  28. package/dist/link-Bt3LB_NW.mjs +586 -0
  29. package/dist/{load-config-C4Oe2qZO.mjs → load-config-C2XloBaQ.mjs} +68 -5
  30. package/dist/node-loader.mjs +1 -1
  31. package/dist/{publish-source-Dq2c0iOw.mjs → publish-source-v93eB9kA.mjs} +6 -2
  32. package/dist/react.d.mts +6 -6
  33. package/dist/react.mjs +4 -4
  34. package/dist/registry-generated.d.mts +19 -14
  35. package/dist/registry-saQDMUhT.d.mts +13 -0
  36. package/dist/registry.d.mts +1 -1
  37. package/dist/{reloader-B22UiNA2.mjs → reloader-CFzxYa67.mjs} +3 -3
  38. package/dist/{renderer-host-DD16MXhI.mjs → renderer-host-Cw38dSDe.mjs} +35 -24
  39. package/dist/{rpc-C4_NQmpT.mjs → rpc-Dg9zwZ33.mjs} +4 -4
  40. package/dist/rpc.d.mts +1 -1
  41. package/dist/rpc.mjs +1 -1
  42. package/dist/runtime-DYUONc3S.mjs +861 -0
  43. package/dist/{runtime-BQWntcOb.d.mts → runtime-fnPDZFYM.d.mts} +100 -3
  44. package/dist/runtime.d.mts +2 -2
  45. package/dist/runtime.mjs +2 -578
  46. package/dist/{schema-CjrMVk36.d.mts → schema-brYpUjYO.d.mts} +13 -25
  47. package/dist/schema.d.mts +2 -2
  48. package/dist/schema.mjs +9 -2
  49. package/dist/{server-CZLMF8Dj.mjs → server-BJ2ZC2z2.mjs} +2 -2
  50. package/dist/services/default.d.mts +1 -5
  51. package/dist/services/default.mjs +12 -16
  52. package/dist/services/index.d.mts +1 -1
  53. package/dist/services/index.mjs +7 -7
  54. package/dist/setup-gate.d.mts +1 -1
  55. package/dist/setup-gate.mjs +20 -12
  56. package/dist/{transport-F2hv_OEm.mjs → transport-Bqlv9pmJ.mjs} +1 -1
  57. package/dist/updater-Bs1Jtem6.mjs +480 -0
  58. package/dist/{vite-plugins-tt6KAtyE.mjs → vite-plugins-Df-cfldF.mjs} +2 -49
  59. package/dist/vite.d.mts +0 -5
  60. package/dist/vite.mjs +1 -1
  61. package/dist/{window-YFKvAM0l.mjs → window-DgB70qeZ.mjs} +113 -22
  62. package/dist/{write-DgIRjo23.mjs → write-7IfKa_nq.mjs} +1 -1
  63. package/dist/zenbu-bg-parse-CIyPkJOY.mjs +46 -0
  64. package/package.json +19 -18
  65. package/LICENSE +0 -11
  66. package/dist/advice-config-DXSIo0sg.mjs +0 -154
  67. package/dist/link-glX89NV5.mjs +0 -673
  68. package/dist/registry-CMp8FYgS.d.mts +0 -47
  69. package/dist/updater-BtB_Ki1r.mjs +0 -1011
  70. /package/dist/{config-BK78JDRI.mjs → config-DfciRzDu.mjs} +0 -0
  71. /package/dist/{env-bootstrap-rTs8KR3-.d.mts → env-bootstrap-UBug-4Kw.d.mts} +0 -0
  72. /package/dist/{index-C-ALz_SH.d.mts → index-CSMHYi3u.d.mts} +0 -0
  73. /package/dist/{index-ClXLQ1fw.d.mts → index-DJOHDG5e.d.mts} +0 -0
  74. /package/dist/{log-6rzaCV0I.mjs → log-BkRqDwwB.mjs} +0 -0
  75. /package/dist/{mirror-sync-pYU6f3-c.mjs → mirror-sync-snqh9kEp.mjs} +0 -0
  76. /package/dist/{monorepo-Dct-kkbQ.mjs → monorepo-CBzK3l2i.mjs} +0 -0
  77. /package/dist/{node-BhfLKYCi.mjs → node-BuHlEsE4.mjs} +0 -0
  78. /package/dist/{schema-Ca7SxXgS.mjs → schema-C6k0SroY.mjs} +0 -0
  79. /package/dist/{setup-gate-BQq0QgZH.d.mts → setup-gate-DkysEZQO.d.mts} +0 -0
  80. /package/dist/{src-Cven45mq.mjs → src-BpZAt9zL.mjs} +0 -0
  81. /package/dist/{trace-BaVg0rnY.mjs → trace-BVcQSD59.mjs} +0 -0
  82. /package/dist/{transform-BzrwkEdf.mjs → transform-czrcGnVV.mjs} +0 -0
@@ -1,23 +1,19 @@
1
1
  //#region src/services/default.ts
2
2
  /**
3
- * Loads and registers all built-in services. Kept separate from
4
- * `./index.ts` (which statically re-exports the service classes for
5
- * `Service.withDeps(...)` consumers) so that `setup-gate` can import it
6
- * without eagerly loading every service module before `setupGate()` has
7
- * had a chance to bootstrap env vars and `process.chdir(projectRoot)`.
3
+ * parallelize? i forgor is it serial no matter what?
8
4
  */
9
5
  async function defaultServices() {
10
- await import("../server-CZLMF8Dj.mjs").then((n) => n.n);
11
- await import("../reloader-B22UiNA2.mjs").then((n) => n.n);
12
- await import("../renderer-host-DD16MXhI.mjs").then((n) => n.n);
13
- await import("../renderer-host-DD16MXhI.mjs").then((n) => n.c);
14
- await import("../renderer-host-DD16MXhI.mjs").then((n) => n.o);
15
- await import("../base-window-BxBZ2md_.mjs").then((n) => n.r);
16
- await import("../rpc-C4_NQmpT.mjs").then((n) => n.n);
17
- await import("../renderer-host-DD16MXhI.mjs").then((n) => n.i);
18
- await import("../window-YFKvAM0l.mjs").then((n) => n.n);
19
- await import("../advice-config-DXSIo0sg.mjs").then((n) => n.t);
20
- await import("../updater-BtB_Ki1r.mjs").then((n) => n.n);
6
+ await import("../server-BJ2ZC2z2.mjs").then((n) => n.n);
7
+ await import("../reloader-CFzxYa67.mjs").then((n) => n.n);
8
+ await import("../renderer-host-Cw38dSDe.mjs").then((n) => n.n);
9
+ await import("../renderer-host-Cw38dSDe.mjs").then((n) => n.c);
10
+ await import("../renderer-host-Cw38dSDe.mjs").then((n) => n.o);
11
+ await import("../base-window-4P-fVvC_.mjs").then((n) => n.r);
12
+ await import("../rpc-Dg9zwZ33.mjs").then((n) => n.n);
13
+ await import("../renderer-host-Cw38dSDe.mjs").then((n) => n.i);
14
+ await import("../window-DgB70qeZ.mjs").then((n) => n.n);
15
+ await import("../runtime-DYUONc3S.mjs").then((n) => n.h);
16
+ await import("../updater-Bs1Jtem6.mjs").then((n) => n.n);
21
17
  }
22
18
  //#endregion
23
19
  export { defaultServices };
@@ -1,2 +1,2 @@
1
- import { a as MAIN_WINDOW_ID, c as DbService, d as ServerService, i as BaseWindowService, l as HttpService, n as WindowService, o as RendererHostService, r as RpcService, s as ViewRegistryService, t as UpdaterService, u as ReloaderService } from "../index-CVF768Xs.mjs";
1
+ import { a as MAIN_WINDOW_ID, c as DbService, d as ServerService, i as BaseWindowService, l as HttpService, n as WindowService, o as RendererHostService, r as RpcService, s as ViewRegistryService, t as UpdaterService, u as ReloaderService } from "../index-C0mXKol5.mjs";
2
2
  export { BaseWindowService, DbService, HttpService, MAIN_WINDOW_ID, ReloaderService, RendererHostService, RpcService, ServerService, UpdaterService, ViewRegistryService, WindowService };
@@ -1,8 +1,8 @@
1
- import { t as ServerService } from "../server-CZLMF8Dj.mjs";
2
- import { t as ReloaderService } from "../reloader-B22UiNA2.mjs";
3
- import { a as DbService, r as ViewRegistryService, s as HttpService, t as RendererHostService } from "../renderer-host-DD16MXhI.mjs";
4
- import { n as MAIN_WINDOW_ID, t as BaseWindowService } from "../base-window-BxBZ2md_.mjs";
5
- import { t as RpcService } from "../rpc-C4_NQmpT.mjs";
6
- import { t as WindowService } from "../window-YFKvAM0l.mjs";
7
- import { t as UpdaterService } from "../updater-BtB_Ki1r.mjs";
1
+ import { t as ServerService } from "../server-BJ2ZC2z2.mjs";
2
+ import { t as ReloaderService } from "../reloader-CFzxYa67.mjs";
3
+ import { a as DbService, r as ViewRegistryService, s as HttpService, t as RendererHostService } from "../renderer-host-Cw38dSDe.mjs";
4
+ import { n as MAIN_WINDOW_ID, t as BaseWindowService } from "../base-window-4P-fVvC_.mjs";
5
+ import { t as RpcService } from "../rpc-Dg9zwZ33.mjs";
6
+ import { t as WindowService } from "../window-DgB70qeZ.mjs";
7
+ import { t as UpdaterService } from "../updater-Bs1Jtem6.mjs";
8
8
  export { BaseWindowService, DbService, HttpService, MAIN_WINDOW_ID, ReloaderService, RendererHostService, RpcService, ServerService, UpdaterService, ViewRegistryService, WindowService };
@@ -1,2 +1,2 @@
1
- import { t as setupGate } from "./setup-gate-BQq0QgZH.mjs";
1
+ import { t as setupGate } from "./setup-gate-DkysEZQO.mjs";
2
2
  export { setupGate };
@@ -1,4 +1,5 @@
1
1
  import { bootstrapEnv } from "./env-bootstrap.mjs";
2
+ import { n as pickZenbuBgEntry, t as parseZenbuBgEntries } from "./zenbu-bg-parse-CIyPkJOY.mjs";
2
3
  import { createRequire, register } from "node:module";
3
4
  import fs from "node:fs";
4
5
  import os from "node:os";
@@ -87,16 +88,23 @@ async function closeRegisteredWatchers() {
87
88
  await (await import("@zenbujs/hmr/pause")).closeAllWatchers?.();
88
89
  }
89
90
  /**
90
- * Extract the splash's intended background color from a
91
- * `<meta name="zenbu-bg" content="#xxx">` tag. Used as the BaseWindow's
92
- * `backgroundColor` so the OS doesn't paint a single white frame before
93
- * the WebContentsView's pixels reach the screen. Convention only —
94
- * defaults to `#F4F4F4` when unset.
91
+ * Extract the splash's intended background color from `<meta name="zenbu-bg">`
92
+ * tag(s). Used as the BaseWindow's `backgroundColor` so the OS doesn't
93
+ * paint a single mismatched frame before the WebContentsView's pixels
94
+ * reach the screen.
95
+ *
96
+ * Supports the `media` attribute (mirrors the W3C `theme-color` pattern),
97
+ * so the splash can declare separate colors per system theme:
98
+ *
99
+ * <meta name="zenbu-bg" content="#fafafa" media="(prefers-color-scheme: light)">
100
+ * <meta name="zenbu-bg" content="#09090b" media="(prefers-color-scheme: dark)">
101
+ *
102
+ * Defaults to `#F4F4F4` when no tag matches.
95
103
  */
96
- function readSplashBgColor(splashPath) {
104
+ function readSplashBgColor(splashPath, dark) {
97
105
  try {
98
- const match = fs.readFileSync(splashPath, "utf8").match(/<meta\s+name=["']zenbu-bg["']\s+content=["']([^"']+)["']/i);
99
- if (match?.[1]) return match[1];
106
+ const picked = pickZenbuBgEntry(parseZenbuBgEntries(fs.readFileSync(splashPath, "utf8")), dark);
107
+ if (picked) return picked;
100
108
  } catch {}
101
109
  return "#F4F4F4";
102
110
  }
@@ -125,7 +133,7 @@ async function spawnSplashWindow(splashPath) {
125
133
  }
126
134
  const slot = globalThis;
127
135
  const electron = await import("electron");
128
- const backgroundColor = readSplashBgColor(splashPath);
136
+ const backgroundColor = readSplashBgColor(splashPath, electron.nativeTheme.shouldUseDarkColors);
129
137
  const existing = slot.__zenbu_boot_windows__?.find((b) => b.windowId === "main");
130
138
  let win;
131
139
  if (existing) {
@@ -186,10 +194,10 @@ async function spawnSplashWindow(splashPath) {
186
194
  */
187
195
  async function loadConfigPhase(tsconfig, projectRoot) {
188
196
  register$1({ tsconfig });
189
- const { loadConfig } = await import("./load-config-C4Oe2qZO.mjs").then((n) => n.n);
197
+ const { loadConfig } = await import("./load-config-C2XloBaQ.mjs").then((n) => n.a);
190
198
  const { resolved, pluginSourceFiles } = await loadConfig(projectRoot);
191
199
  try {
192
- const { linkProject } = await import("./link-glX89NV5.mjs").then((n) => n.n);
200
+ const { linkProject } = await import("./link-Bt3LB_NW.mjs").then((n) => n.n);
193
201
  await linkProject(projectRoot, { quiet: true });
194
202
  } catch (err) {
195
203
  console.warn(`[setup-gate] zen link failed (non-fatal): ${err instanceof Error ? err.message : String(err)}`);
@@ -225,7 +233,7 @@ async function loadConfigPhase(tsconfig, projectRoot) {
225
233
  async function registerLoadersPhase(projectRoot, loaderData) {
226
234
  registerLoader(import.meta.resolve("@zenbujs/core/loaders/zenbu"), { data: loaderData });
227
235
  process.env.ZENBU_ADVICE_ROOT = projectRoot;
228
- await import("./node-BhfLKYCi.mjs");
236
+ await import("./node-BuHlEsE4.mjs");
229
237
  const dynohot = await import(pathToFileURL(createRequire(import.meta.url).resolve("@zenbujs/hmr/register")).href);
230
238
  if (typeof dynohot.register === "function") dynohot.register({ ignore: /[/\\](?:node_modules|dist)[/\\]/ });
231
239
  }
@@ -1,4 +1,4 @@
1
- import { t as traceKyju } from "./trace-BaVg0rnY.mjs";
1
+ import { t as traceKyju } from "./trace-BVcQSD59.mjs";
2
2
  import * as Effect from "effect/Effect";
3
3
  import * as Ref from "effect/Ref";
4
4
  import * as Context from "effect/Context";
@@ -0,0 +1,480 @@
1
+ import { n as __exportAll } from "./chunk-DsiFFCwN.mjs";
2
+ import { f as runtime, n as Service } from "./runtime-DYUONc3S.mjs";
3
+ import { t as createLogger } from "./log-BkRqDwwB.mjs";
4
+ import { n as tryReadHostVersion } from "./host-version-Cog_odmD.mjs";
5
+ import fs, { existsSync } from "node:fs";
6
+ import os from "node:os";
7
+ import path from "node:path";
8
+ import { spawn } from "node:child_process";
9
+ import crypto from "node:crypto";
10
+ import fsp from "node:fs/promises";
11
+ import { app } from "electron";
12
+ import * as git from "isomorphic-git";
13
+ import http from "isomorphic-git/http/node";
14
+ //#region src/shared/pm-install.ts
15
+ /**
16
+ * Bundled-toolchain `<pm> install` helpers.
17
+ *
18
+ * Imported by both:
19
+ * - `packages/core/src/launcher.ts` (tsdown inlines this into
20
+ * `dist/launcher.mjs`; the launcher cannot `import "@zenbujs/core"`)
21
+ * - `packages/core/src/services/updater.ts` (resolved through normal
22
+ * `@zenbujs/core/...` resolution at runtime)
23
+ *
24
+ * Both call sites operate on the apps-dir (`~/.zenbu/apps/<name>/`) and
25
+ * the .app's `Resources/` (where `provisionToolchain` staged
26
+ * `bun`, `pnpm`, etc.). The launcher kicks off the FIRST install at
27
+ * launch; the updater service runs the SAME logic when an `update()`
28
+ * lockfile-diff says deps drifted.
29
+ */
30
+ function lockfileFor(type) {
31
+ switch (type) {
32
+ case "pnpm": return "pnpm-lock.yaml";
33
+ case "npm": return "package-lock.json";
34
+ case "yarn": return "yarn.lock";
35
+ case "bun": return "bun.lock";
36
+ }
37
+ }
38
+ function isYarnBerry(version) {
39
+ const major = parseInt(version.split(".")[0] ?? "", 10);
40
+ return Number.isFinite(major) && major >= 2;
41
+ }
42
+ function bundledToolPath(name, resourcesPath) {
43
+ const candidates = [path.join(resourcesPath, "toolchain", "bin", name), path.join(resourcesPath, "toolchain", name)];
44
+ for (const candidate of candidates) if (existsSync(candidate)) return candidate;
45
+ return null;
46
+ }
47
+ /**
48
+ * Resolve the entrypoint we'll exec for a given PM, mirroring the layout
49
+ * `provisionToolchain` writes into the bundle's `Resources/toolchain/`.
50
+ */
51
+ function bundledPmEntry(pm, resourcesPath) {
52
+ switch (pm.type) {
53
+ case "pnpm": {
54
+ const p = path.join(resourcesPath, "toolchain", "pnpm", "bin", "pnpm.cjs");
55
+ if (!existsSync(p)) throw new Error(`bundled pnpm entry not found at ${p}. The .app's toolchain is incomplete.`);
56
+ return {
57
+ kind: "js",
58
+ path: p
59
+ };
60
+ }
61
+ case "npm": {
62
+ const p = path.join(resourcesPath, "toolchain", "npm", "bin", "npm-cli.js");
63
+ if (!existsSync(p)) throw new Error(`bundled npm entry not found at ${p}. The .app's toolchain is incomplete.`);
64
+ return {
65
+ kind: "js",
66
+ path: p
67
+ };
68
+ }
69
+ case "yarn": {
70
+ if (isYarnBerry(pm.version)) {
71
+ const p = path.join(resourcesPath, "toolchain", "yarn.cjs");
72
+ if (!existsSync(p)) throw new Error(`bundled yarn (berry) entry not found at ${p}. The .app's toolchain is incomplete.`);
73
+ return {
74
+ kind: "js",
75
+ path: p
76
+ };
77
+ }
78
+ const p = path.join(resourcesPath, "toolchain", "yarn", "bin", "yarn.js");
79
+ if (!existsSync(p)) throw new Error(`bundled yarn (classic) entry not found at ${p}. The .app's toolchain is incomplete.`);
80
+ return {
81
+ kind: "js",
82
+ path: p
83
+ };
84
+ }
85
+ case "bun": return { kind: "bun" };
86
+ }
87
+ }
88
+ function electronTargetVersion(appsDir) {
89
+ if (process.versions.electron) return process.versions.electron;
90
+ try {
91
+ const pkg = JSON.parse(fs.readFileSync(path.join(appsDir, "package.json"), "utf8"));
92
+ return (pkg.devDependencies?.electron ?? pkg.dependencies?.electron ?? "").replace(/^[^\d]*/, "") || "42.0.0";
93
+ } catch {
94
+ return "42.0.0";
95
+ }
96
+ }
97
+ function buildInstallEnv(appsDir) {
98
+ const target = electronTargetVersion(appsDir);
99
+ return {
100
+ ...process.env,
101
+ CI: "true",
102
+ HOME: path.join(appsDir, ".zenbu", ".node-gyp"),
103
+ npm_config_runtime: "electron",
104
+ npm_config_target: target,
105
+ npm_config_disturl: "https://electronjs.org/headers",
106
+ npm_config_arch: process.arch
107
+ };
108
+ }
109
+ /**
110
+ * Best-effort progress regex per package manager. We pass each stdout line
111
+ * through these and return a `progress` payload when one matches; otherwise
112
+ * `null`. Failing to match is fine — the UI just won't show fine-grained
113
+ * progress for that PM.
114
+ */
115
+ const PNPM_RESOLVED_RE = /Progress:\s+resolved\s+(\d+),\s+reused\s+(\d+),\s+downloaded\s+(\d+)/i;
116
+ const PNPM_PROGRESS_RE = /(\d+)\s*\/\s*(\d+)/;
117
+ function parseInstallProgress(pm, line) {
118
+ if (pm === "pnpm") {
119
+ const m = line.match(PNPM_RESOLVED_RE);
120
+ if (m) {
121
+ const resolved = parseInt(m[1], 10);
122
+ const reused = parseInt(m[2], 10);
123
+ const downloaded = parseInt(m[3], 10);
124
+ return {
125
+ phase: "resolve",
126
+ loaded: reused + downloaded,
127
+ total: resolved,
128
+ ratio: resolved > 0 ? (reused + downloaded) / resolved : void 0
129
+ };
130
+ }
131
+ }
132
+ const m = line.match(PNPM_PROGRESS_RE);
133
+ if (m) {
134
+ const loaded = parseInt(m[1], 10);
135
+ const total = parseInt(m[2], 10);
136
+ if (total > 0) return {
137
+ loaded,
138
+ total,
139
+ ratio: loaded / total
140
+ };
141
+ }
142
+ return null;
143
+ }
144
+ function spawnInstall(args) {
145
+ const { bin, cliArgs, cwd, env, label, pmType, reporter, signal } = args;
146
+ return new Promise((resolve, reject) => {
147
+ if (signal?.aborted) {
148
+ reject(/* @__PURE__ */ new Error(`${label} aborted before start`));
149
+ return;
150
+ }
151
+ const usePiped = reporter != null;
152
+ const child = spawn(bin, cliArgs, {
153
+ cwd,
154
+ stdio: usePiped ? [
155
+ "inherit",
156
+ "pipe",
157
+ "pipe"
158
+ ] : "inherit",
159
+ env
160
+ });
161
+ const onAbort = () => {
162
+ try {
163
+ child.kill("SIGTERM");
164
+ } catch {}
165
+ };
166
+ signal?.addEventListener("abort", onAbort, { once: true });
167
+ if (usePiped) {
168
+ const wireStream = (stream, which) => {
169
+ if (!stream) return;
170
+ let buf = "";
171
+ stream.setEncoding("utf8");
172
+ stream.on("data", (chunk) => {
173
+ buf += chunk;
174
+ let nl;
175
+ while ((nl = buf.indexOf("\n")) >= 0) {
176
+ const rawLine = buf.slice(0, nl);
177
+ buf = buf.slice(nl + 1);
178
+ reporter?.rawLine?.(which, rawLine);
179
+ const line = rawLine.replace(/\r/g, "").trimEnd();
180
+ if (!line) continue;
181
+ reporter?.message?.(line);
182
+ const progress = parseInstallProgress(pmType, line);
183
+ if (progress) reporter?.progress?.(progress);
184
+ }
185
+ });
186
+ stream.on("end", () => {
187
+ if (buf.length > 0) {
188
+ reporter?.rawLine?.(which, buf);
189
+ const line = buf.replace(/\r/g, "").trimEnd();
190
+ if (line) reporter?.message?.(line);
191
+ }
192
+ });
193
+ };
194
+ wireStream(child.stdout, "stdout");
195
+ wireStream(child.stderr, "stderr");
196
+ }
197
+ child.on("error", (err) => {
198
+ signal?.removeEventListener("abort", onAbort);
199
+ reject(err);
200
+ });
201
+ child.on("close", (code, sig) => {
202
+ signal?.removeEventListener("abort", onAbort);
203
+ if (code === 0) resolve();
204
+ else if (signal?.aborted) reject(/* @__PURE__ */ new Error(`${label} aborted (${sig ?? code})`));
205
+ else reject(/* @__PURE__ */ new Error(`${label} exited with code ${code}`));
206
+ });
207
+ });
208
+ }
209
+ async function runInstall(opts) {
210
+ const { appsDir, resourcesPath, pm, reporter = null, signal } = opts;
211
+ const env = buildInstallEnv(appsDir);
212
+ const entry = bundledPmEntry(pm, resourcesPath);
213
+ switch (pm.type) {
214
+ case "pnpm": {
215
+ if (entry.kind !== "js") throw new Error("internal: pnpm entry shape");
216
+ const bun = bundledToolPath("bun", resourcesPath);
217
+ if (!bun) throw new Error(`bundled bun not found in ${resourcesPath}/toolchain (required to host the pnpm.cjs entry)`);
218
+ await spawnInstall({
219
+ bin: bun,
220
+ cliArgs: [
221
+ entry.path,
222
+ "install",
223
+ "--reporter=append-only"
224
+ ],
225
+ cwd: appsDir,
226
+ env,
227
+ label: "pnpm install",
228
+ pmType: pm.type,
229
+ reporter,
230
+ signal
231
+ });
232
+ return;
233
+ }
234
+ case "npm": {
235
+ if (entry.kind !== "js") throw new Error("internal: npm entry shape");
236
+ const bun = bundledToolPath("bun", resourcesPath);
237
+ if (!bun) throw new Error(`bundled bun not found in ${resourcesPath}/toolchain (required to host the npm-cli.js entry)`);
238
+ await spawnInstall({
239
+ bin: bun,
240
+ cliArgs: [
241
+ entry.path,
242
+ "install",
243
+ "--no-audit",
244
+ "--no-fund",
245
+ "--no-progress"
246
+ ],
247
+ cwd: appsDir,
248
+ env,
249
+ label: "npm install",
250
+ pmType: pm.type,
251
+ reporter,
252
+ signal
253
+ });
254
+ return;
255
+ }
256
+ case "yarn": {
257
+ if (entry.kind !== "js") throw new Error("internal: yarn entry shape");
258
+ const bun = bundledToolPath("bun", resourcesPath);
259
+ if (!bun) throw new Error(`bundled bun not found in ${resourcesPath}/toolchain (required to host the yarn.js entry)`);
260
+ if (isYarnBerry(pm.version)) await spawnInstall({
261
+ bin: bun,
262
+ cliArgs: [entry.path, "install"],
263
+ cwd: appsDir,
264
+ env: {
265
+ ...env,
266
+ YARN_ENABLE_IMMUTABLE_INSTALLS: "false"
267
+ },
268
+ label: `yarn install (${pm.version})`,
269
+ pmType: pm.type,
270
+ reporter,
271
+ signal
272
+ });
273
+ else {
274
+ const rcPath = path.join(appsDir, ".zenbu", "yarn-classic-bun.yarnrc");
275
+ await fsp.mkdir(path.dirname(rcPath), { recursive: true });
276
+ await fsp.writeFile(rcPath, "strict-ssl false\n");
277
+ await spawnInstall({
278
+ bin: bun,
279
+ cliArgs: [
280
+ entry.path,
281
+ "install",
282
+ "--non-interactive",
283
+ "--no-progress",
284
+ "--network-timeout",
285
+ "600000",
286
+ "--use-yarnrc",
287
+ rcPath,
288
+ "--registry",
289
+ "https://registry.npmjs.org/"
290
+ ],
291
+ cwd: appsDir,
292
+ env,
293
+ label: `yarn install (${pm.version})`,
294
+ pmType: pm.type,
295
+ reporter,
296
+ signal
297
+ });
298
+ }
299
+ return;
300
+ }
301
+ case "bun": {
302
+ const bun = bundledToolPath("bun", resourcesPath);
303
+ if (!bun) throw new Error(`bundled bun not found in ${resourcesPath}/toolchain. The .app is missing required toolchain binaries.`);
304
+ await spawnInstall({
305
+ bin: bun,
306
+ cliArgs: ["install", "--no-progress"],
307
+ cwd: appsDir,
308
+ env,
309
+ label: "bun install",
310
+ pmType: pm.type,
311
+ reporter,
312
+ signal
313
+ });
314
+ return;
315
+ }
316
+ }
317
+ }
318
+ async function fileHash(hash, filePath) {
319
+ hash.update(filePath);
320
+ hash.update("\0");
321
+ try {
322
+ hash.update(await fsp.readFile(filePath));
323
+ } catch {}
324
+ hash.update("\0");
325
+ }
326
+ async function depsSignature(appsDir, pm) {
327
+ const hash = crypto.createHash("sha256");
328
+ await fileHash(hash, path.join(appsDir, "package.json"));
329
+ await fileHash(hash, path.join(appsDir, lockfileFor(pm.type)));
330
+ hash.update(`${pm.type}@${pm.version}`);
331
+ hash.update("\0");
332
+ hash.update(process.versions.electron ?? "no-electron");
333
+ hash.update("\0");
334
+ hash.update(process.platform);
335
+ hash.update("\0");
336
+ hash.update(process.arch);
337
+ return hash.digest("hex");
338
+ }
339
+ /**
340
+ * Read `<appsDir>/.zenbu/deps-sig` (the signature recorded after the
341
+ * last successful install). Returns `null` when missing.
342
+ */
343
+ async function readDepsSig(appsDir) {
344
+ const sigPath = path.join(appsDir, ".zenbu", "deps-sig");
345
+ try {
346
+ return await fsp.readFile(sigPath, "utf8");
347
+ } catch {
348
+ return null;
349
+ }
350
+ }
351
+ async function writeDepsSig(appsDir, sig) {
352
+ const sigPath = path.join(appsDir, ".zenbu", "deps-sig");
353
+ await fsp.mkdir(path.dirname(sigPath), { recursive: true });
354
+ await fsp.writeFile(sigPath, sig);
355
+ }
356
+ //#endregion
357
+ //#region src/services/updater.ts
358
+ /**
359
+ * Atomic, thin wrappers over `isomorphic-git` plus a single `install()`
360
+ * primitive over `runInstall`. Each public method is one underlying
361
+ * call; callers compose update flows themselves.
362
+ *
363
+ * `getAppContext()` is a read-only convenience that surfaces the
364
+ * running .app's `app-config.json` + `host.json` so callers don't have
365
+ * to re-parse them. It returns `null` in dev or when the bundle is
366
+ * missing those files.
367
+ */
368
+ var updater_exports = /* @__PURE__ */ __exportAll({ UpdaterService: () => UpdaterService });
369
+ const log = createLogger("updater");
370
+ const LEGACY_PACKAGE_MANAGER = {
371
+ type: "pnpm",
372
+ version: "10.33.0"
373
+ };
374
+ function isBundleMode() {
375
+ return process.env.ZENBU_LAUNCHED_FROM_BUNDLE === "1";
376
+ }
377
+ function readAppConfig(appPath) {
378
+ const configPath = path.join(appPath, "app-config.json");
379
+ try {
380
+ return JSON.parse(fs.readFileSync(configPath, "utf8"));
381
+ } catch {
382
+ return null;
383
+ }
384
+ }
385
+ function appsDirFor(name) {
386
+ if (process.env.ZENBU_APPS_DIR) return path.resolve(process.env.ZENBU_APPS_DIR);
387
+ return path.join(os.homedir(), ".zenbu", "apps", name);
388
+ }
389
+ var UpdaterService = class extends Service.create({ key: "updater" }) {
390
+ evaluate() {
391
+ log.verbose(`updater service ready (mode=${isBundleMode() ? "bundle" : "dev"})`);
392
+ }
393
+ /**
394
+ * Snapshot of the running .app's mirror + toolchain. Returns `null`
395
+ * in dev (no bundle) or when `app-config.json` / `host.json` are
396
+ * missing. No side effects.
397
+ */
398
+ async getAppContext() {
399
+ if (!isBundleMode()) return null;
400
+ const appPath = app.getAppPath();
401
+ const cfg = readAppConfig(appPath);
402
+ if (!cfg || !cfg.mirrorUrl) return null;
403
+ const host = tryReadHostVersion(appPath);
404
+ if (!host) return null;
405
+ return {
406
+ appsDir: appsDirFor(cfg.name),
407
+ resourcesPath: path.dirname(appPath),
408
+ mirror: {
409
+ url: cfg.mirrorUrl,
410
+ branch: cfg.branch ?? "main"
411
+ },
412
+ packageManager: cfg.packageManager ?? LEGACY_PACKAGE_MANAGER,
413
+ hostVersion: host.version,
414
+ appName: cfg.name
415
+ };
416
+ }
417
+ async fetch(opts) {
418
+ return git.fetch({
419
+ fs,
420
+ http,
421
+ ...opts
422
+ });
423
+ }
424
+ async clone(opts) {
425
+ await git.clone({
426
+ fs,
427
+ http,
428
+ ...opts
429
+ });
430
+ }
431
+ async checkout(opts) {
432
+ await git.checkout({
433
+ fs,
434
+ ...opts
435
+ });
436
+ }
437
+ async resolveRef(opts) {
438
+ return git.resolveRef({
439
+ fs,
440
+ ...opts
441
+ });
442
+ }
443
+ async statusMatrix(opts) {
444
+ return git.statusMatrix({
445
+ fs,
446
+ ...opts
447
+ });
448
+ }
449
+ async log(opts) {
450
+ return git.log({
451
+ fs,
452
+ ...opts
453
+ });
454
+ }
455
+ /**
456
+ * Run `<pm> install` in `dir` using the bundled toolchain at
457
+ * `resourcesPath`. Always runs; no signature gating. Compose with
458
+ * `getDepsSignature` / `readDepsSignature` / `writeDepsSignature`
459
+ * if you want a skip-when-clean gate.
460
+ */
461
+ async install(opts) {
462
+ await runInstall({
463
+ appsDir: opts.dir,
464
+ resourcesPath: opts.resourcesPath,
465
+ pm: opts.pm
466
+ });
467
+ }
468
+ async getDepsSignature(opts) {
469
+ return depsSignature(opts.dir, opts.pm);
470
+ }
471
+ async readDepsSignature(opts) {
472
+ return readDepsSig(opts.dir);
473
+ }
474
+ async writeDepsSignature(opts) {
475
+ await writeDepsSig(opts.dir, opts.sig);
476
+ }
477
+ };
478
+ runtime.register(UpdaterService, import.meta);
479
+ //#endregion
480
+ export { updater_exports as n, UpdaterService as t };
@@ -1,6 +1,5 @@
1
- import { getPlugins } from "./runtime.mjs";
2
- import { n as require_lib, t as zenbuAdviceTransform$1 } from "./transform-BzrwkEdf.mjs";
3
- import { a as getAllTypes, i as getAllContentScriptPaths, n as getAdvice, o as getContentScripts } from "./advice-config-DXSIo0sg.mjs";
1
+ import { b as getContentScripts, g as getAdvice, v as getAllContentScriptPaths, y as getAllTypes } from "./runtime-DYUONc3S.mjs";
2
+ import { n as require_lib, t as zenbuAdviceTransform$1 } from "./transform-czrcGnVV.mjs";
4
3
  import path from "node:path";
5
4
  import { fileURLToPath } from "node:url";
6
5
  //#region ../advice/src/vite.ts
@@ -99,47 +98,6 @@ function zenbuFrameworkResolve() {
99
98
  ] },
100
99
  server: { fs: { allow: [CORE_PACKAGE_ROOT] } }
101
100
  };
102
- },
103
- /**
104
- * Vite's built-in tsconfig watcher (`reloadOnTsconfigChange` in
105
- * `plugins/esbuild.ts`) only triggers a cache-clear + full reload when
106
- * the changed path ends in exactly `/tsconfig.json` — non-canonical
107
- * names like `tsconfig.local.json` are silently ignored even though the
108
- * underlying chokidar watcher does fire on them. We use that pattern
109
- * (a committed `tsconfig.json` that extends a generated, gitignored
110
- * `tsconfig.local.json`) so plugin sources can `#registry/*`-import
111
- * the host's typed registry without a host-specific path leaking into
112
- * a committed file.
113
- *
114
- * Without this hook, every `zen link` run would silently leave esbuild
115
- * with a stale "extends target missing" cache and plugin sources would
116
- * fail to load until the dev process is killed by hand. This watches
117
- * the plugin directories declared in the host's `config.json` and
118
- * proactively calls `server.restart()` on add/change/unlink of any
119
- * `tsconfig.local.json`.
120
- */
121
- configureServer(server) {
122
- const tsconfigPaths = getPlugins().map((p) => path.join(p.dir, "tsconfig.local.json"));
123
- if (tsconfigPaths.length === 0) return;
124
- server.watcher.add(tsconfigPaths);
125
- let restarting = false;
126
- const handle = (file) => {
127
- if (!file.endsWith("tsconfig.local.json")) return;
128
- if (restarting) return;
129
- restarting = true;
130
- server.config.logger.info(`[zenbu] ${file} changed — restarting Vite to refresh tsconfig (vite's built-in watcher only fires on /tsconfig.json)`, {
131
- timestamp: true,
132
- clear: false
133
- });
134
- server.restart().catch((err) => {
135
- server.config.logger.error(`[zenbu] vite restart failed: ${err instanceof Error ? err.message : String(err)}`);
136
- }).finally(() => {
137
- restarting = false;
138
- });
139
- };
140
- server.watcher.on("add", handle);
141
- server.watcher.on("change", handle);
142
- server.watcher.on("unlink", handle);
143
101
  }
144
102
  };
145
103
  }
@@ -294,11 +252,6 @@ function zenbuAdviceTransform() {
294
252
  };
295
253
  }
296
254
  /**
297
- * Returns the framework Vite plugins in the canonical order. Auto-injected
298
- * by `ReloaderService` for every renderer; exported for advanced users who
299
- * want to compose them into a custom Vite stack.
300
- *
301
- * Order matters:
302
255
  * 1. `zenbuFrameworkResolve` — `enforce: "pre"`, runs first so it gets
303
256
  * `react` / `@zenbujs/core/*` *before* Vite's default resolver walks
304
257
  * up and finds plugin-local copies.