@zenbujs/core 0.0.8 → 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.
- package/dist/advice-config-BiYhyeTz.d.mts +41 -0
- package/dist/advice.d.mts +2 -36
- package/dist/advice.mjs +2 -2
- package/dist/{base-window-BxBZ2md_.mjs → base-window-4P-fVvC_.mjs} +37 -26
- package/dist/{build-config-Dzg2frpk.d.mts → build-config-GF0XzR_Y.d.mts} +42 -18
- package/dist/{build-config-pWdmLnrk.mjs → build-config-HMMqpXI1.mjs} +0 -8
- package/dist/{build-electron-Dsbb1EMl.mjs → build-electron-Di_FE62r.mjs} +10 -6
- package/dist/{build-source-d1J3shV8.mjs → build-source-BIaWpaxE.mjs} +2 -2
- package/dist/cli/bin.mjs +7 -7
- package/dist/cli/build.d.mts +1 -1
- package/dist/cli/build.mjs +1 -1
- package/dist/cli/resolve-config.mjs +6 -1
- package/dist/{cli-kL6mPgBE.mjs → cli-5jFDJWM4.mjs} +4 -4
- package/dist/config.d.mts +3 -3
- package/dist/config.mjs +2 -2
- package/dist/{db-Bc292RYo.mjs → db-MkOccvBS.mjs} +2 -2
- package/dist/db.d.mts +3 -2
- package/dist/db.mjs +2 -10
- package/dist/{dev-B2emj0HZ.mjs → dev-BSDyzO4j.mjs} +3 -9
- package/dist/env-bootstrap.d.mts +1 -1
- package/dist/events.d.mts +0 -9
- package/dist/{host-version-BIrF8tX7.mjs → host-version-Cog_odmD.mjs} +4 -3
- package/dist/{index-w5QyDjuf.d.mts → index-C0mXKol5.d.mts} +189 -141
- package/dist/{index-DeDxePAa.d.mts → index-FaexRVl_.d.mts} +13 -1
- package/dist/index.d.mts +4 -4
- package/dist/index.mjs +2 -2
- package/dist/launcher.mjs +64 -6
- package/dist/link-Bt3LB_NW.mjs +586 -0
- package/dist/{load-config-C4Oe2qZO.mjs → load-config-C2XloBaQ.mjs} +68 -5
- package/dist/node-loader.mjs +1 -1
- package/dist/{publish-source-Dq2c0iOw.mjs → publish-source-v93eB9kA.mjs} +6 -2
- package/dist/react.d.mts +6 -6
- package/dist/react.mjs +4 -4
- package/dist/registry-generated.d.mts +19 -14
- package/dist/registry-saQDMUhT.d.mts +13 -0
- package/dist/registry.d.mts +1 -1
- package/dist/{reloader-B22UiNA2.mjs → reloader-CFzxYa67.mjs} +3 -3
- package/dist/{renderer-host-DD16MXhI.mjs → renderer-host-Cw38dSDe.mjs} +35 -24
- package/dist/{rpc-C4_NQmpT.mjs → rpc-Dg9zwZ33.mjs} +4 -4
- package/dist/rpc.d.mts +1 -1
- package/dist/rpc.mjs +1 -1
- package/dist/runtime-DYUONc3S.mjs +861 -0
- package/dist/{runtime-BQWntcOb.d.mts → runtime-fnPDZFYM.d.mts} +100 -3
- package/dist/runtime.d.mts +2 -2
- package/dist/runtime.mjs +2 -578
- package/dist/{schema-CjrMVk36.d.mts → schema-brYpUjYO.d.mts} +13 -25
- package/dist/schema.d.mts +2 -2
- package/dist/schema.mjs +9 -2
- package/dist/{server-CZLMF8Dj.mjs → server-BJ2ZC2z2.mjs} +2 -2
- package/dist/services/default.d.mts +1 -5
- package/dist/services/default.mjs +12 -16
- package/dist/services/index.d.mts +1 -1
- package/dist/services/index.mjs +7 -7
- package/dist/setup-gate.d.mts +1 -1
- package/dist/setup-gate.mjs +25 -11
- package/dist/{transport-F2hv_OEm.mjs → transport-Bqlv9pmJ.mjs} +1 -1
- package/dist/updater-Bs1Jtem6.mjs +480 -0
- package/dist/{vite-plugins-tt6KAtyE.mjs → vite-plugins-Df-cfldF.mjs} +2 -49
- package/dist/vite.d.mts +0 -5
- package/dist/vite.mjs +1 -1
- package/dist/{window-YFKvAM0l.mjs → window-DgB70qeZ.mjs} +113 -22
- package/dist/{write-DgIRjo23.mjs → write-7IfKa_nq.mjs} +1 -1
- package/dist/zenbu-bg-parse-CIyPkJOY.mjs +46 -0
- package/package.json +19 -18
- package/LICENSE +0 -11
- package/dist/advice-config-DXSIo0sg.mjs +0 -154
- package/dist/link-glX89NV5.mjs +0 -673
- package/dist/registry-CMp8FYgS.d.mts +0 -47
- package/dist/updater-DCkz9M1c.mjs +0 -1008
- /package/dist/{config-BK78JDRI.mjs → config-DfciRzDu.mjs} +0 -0
- /package/dist/{env-bootstrap-rTs8KR3-.d.mts → env-bootstrap-UBug-4Kw.d.mts} +0 -0
- /package/dist/{index-C-ALz_SH.d.mts → index-CSMHYi3u.d.mts} +0 -0
- /package/dist/{index-ClXLQ1fw.d.mts → index-DJOHDG5e.d.mts} +0 -0
- /package/dist/{log-6rzaCV0I.mjs → log-BkRqDwwB.mjs} +0 -0
- /package/dist/{mirror-sync-pYU6f3-c.mjs → mirror-sync-snqh9kEp.mjs} +0 -0
- /package/dist/{monorepo-Dct-kkbQ.mjs → monorepo-CBzK3l2i.mjs} +0 -0
- /package/dist/{node-BhfLKYCi.mjs → node-BuHlEsE4.mjs} +0 -0
- /package/dist/{schema-Ca7SxXgS.mjs → schema-C6k0SroY.mjs} +0 -0
- /package/dist/{setup-gate-BQq0QgZH.d.mts → setup-gate-DkysEZQO.d.mts} +0 -0
- /package/dist/{src-Cven45mq.mjs → src-BpZAt9zL.mjs} +0 -0
- /package/dist/{trace-BaVg0rnY.mjs → trace-BVcQSD59.mjs} +0 -0
- /package/dist/{transform-BzrwkEdf.mjs → transform-czrcGnVV.mjs} +0 -0
package/dist/launcher.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
|
-
import { BaseWindow, WebContentsView, app } from "electron";
|
|
2
|
+
import { BaseWindow, WebContentsView, app, nativeTheme } from "electron";
|
|
3
3
|
import fs, { existsSync } from "node:fs";
|
|
4
4
|
import fsp from "node:fs/promises";
|
|
5
5
|
import os from "node:os";
|
|
@@ -18808,9 +18808,10 @@ async function writeDepsSig(appsDir, sig) {
|
|
|
18808
18808
|
//#region src/shared/host-version.ts
|
|
18809
18809
|
/**
|
|
18810
18810
|
* Single source of truth for reading the .app's "host version" — the
|
|
18811
|
-
* concrete semver string
|
|
18812
|
-
* `
|
|
18813
|
-
*
|
|
18811
|
+
* concrete semver string `zen build:electron` baked into
|
|
18812
|
+
* `<bundle>/host.json` from the developer's `package.json#version` at
|
|
18813
|
+
* build time. Frozen into the .app so subsequent `git pull`s of the
|
|
18814
|
+
* source can't change it.
|
|
18814
18815
|
*
|
|
18815
18816
|
* Imported by both:
|
|
18816
18817
|
* - `packages/core/src/launcher.ts` (tsdown inlines this into
|
|
@@ -20393,6 +20394,51 @@ async function resolveTargetSha(input) {
|
|
|
20393
20394
|
};
|
|
20394
20395
|
}
|
|
20395
20396
|
//#endregion
|
|
20397
|
+
//#region src/shared/zenbu-bg-parse.ts
|
|
20398
|
+
const META_TAG_RE = /<meta\b([^>]*?)\/?>/gi;
|
|
20399
|
+
const ATTR_RE = /([\w-]+)\s*=\s*["']([^"']+)["']/g;
|
|
20400
|
+
/**
|
|
20401
|
+
* Parse all `<meta name="zenbu-bg">` tags from `html`. Mirrors the W3C
|
|
20402
|
+
* `<meta name="theme-color">` pattern: multiple tags carry a `media`
|
|
20403
|
+
* attribute (typically `(prefers-color-scheme: light|dark)`), and an
|
|
20404
|
+
* unmediated tag acts as the fallback.
|
|
20405
|
+
*
|
|
20406
|
+
* <meta name="zenbu-bg" content="#fafafa" media="(prefers-color-scheme: light)">
|
|
20407
|
+
* <meta name="zenbu-bg" content="#09090b" media="(prefers-color-scheme: dark)">
|
|
20408
|
+
* <meta name="zenbu-bg" content="#27272a"> <!-- default -->
|
|
20409
|
+
*/
|
|
20410
|
+
function parseZenbuBgEntries(html) {
|
|
20411
|
+
const out = [];
|
|
20412
|
+
for (const tag of html.matchAll(META_TAG_RE)) {
|
|
20413
|
+
const body = tag[1] ?? "";
|
|
20414
|
+
const attrs = {};
|
|
20415
|
+
for (const a of body.matchAll(ATTR_RE)) attrs[a[1].toLowerCase()] = a[2];
|
|
20416
|
+
if (attrs.name === "zenbu-bg" && attrs.content) out.push({
|
|
20417
|
+
color: attrs.content,
|
|
20418
|
+
media: attrs.media ?? null
|
|
20419
|
+
});
|
|
20420
|
+
}
|
|
20421
|
+
return out;
|
|
20422
|
+
}
|
|
20423
|
+
/**
|
|
20424
|
+
* Pick the right entry given the current dark-mode preference. Search
|
|
20425
|
+
* order:
|
|
20426
|
+
* 1. First entry whose `media` matches `(prefers-color-scheme: <dark|light>)`.
|
|
20427
|
+
* 2. First entry without a `media` attribute (the unconditional default).
|
|
20428
|
+
* 3. The first entry, regardless of `media`.
|
|
20429
|
+
*
|
|
20430
|
+
* Returns `null` only when `entries` is empty.
|
|
20431
|
+
*/
|
|
20432
|
+
function pickZenbuBgEntry(entries, dark) {
|
|
20433
|
+
for (const e of entries) {
|
|
20434
|
+
if (!e.media) continue;
|
|
20435
|
+
if (dark && /prefers-color-scheme:\s*dark/i.test(e.media)) return e.color;
|
|
20436
|
+
if (!dark && /prefers-color-scheme:\s*light/i.test(e.media)) return e.color;
|
|
20437
|
+
}
|
|
20438
|
+
for (const e of entries) if (!e.media) return e.color;
|
|
20439
|
+
return entries[0]?.color ?? null;
|
|
20440
|
+
}
|
|
20441
|
+
//#endregion
|
|
20396
20442
|
//#region src/launcher.ts
|
|
20397
20443
|
/**
|
|
20398
20444
|
* Zenbu launcher shim.
|
|
@@ -20419,6 +20465,9 @@ async function resolveTargetSha(input) {
|
|
|
20419
20465
|
* at runtime), and `isomorphic-git` (bundled into this file by tsdown — see
|
|
20420
20466
|
* `packages/core/tsdown.config.ts` `neverBundle: ["electron"]`).
|
|
20421
20467
|
*/
|
|
20468
|
+
/**
|
|
20469
|
+
* fixme this is nonsense
|
|
20470
|
+
*/
|
|
20422
20471
|
const _logDir = path.join(os.homedir(), ".zenbu", ".internal");
|
|
20423
20472
|
fs.mkdirSync(_logDir, { recursive: true });
|
|
20424
20473
|
const _logStream = fs.createWriteStream(path.join(_logDir, "launcher.log"), { flags: "a" });
|
|
@@ -20462,8 +20511,8 @@ const APP_PATH = app.getAppPath();
|
|
|
20462
20511
|
const RESOURCES_PATH = path.dirname(APP_PATH);
|
|
20463
20512
|
function readBgColor(htmlPath, fallback) {
|
|
20464
20513
|
try {
|
|
20465
|
-
const
|
|
20466
|
-
if (
|
|
20514
|
+
const picked = pickZenbuBgEntry(parseZenbuBgEntries(fs.readFileSync(htmlPath, "utf8")), nativeTheme.shouldUseDarkColors);
|
|
20515
|
+
if (picked) return picked;
|
|
20467
20516
|
} catch {}
|
|
20468
20517
|
return fallback;
|
|
20469
20518
|
}
|
|
@@ -20507,6 +20556,15 @@ async function maybeOpenInstallingWindow(cfg) {
|
|
|
20507
20556
|
};
|
|
20508
20557
|
layout();
|
|
20509
20558
|
win.on("resize", layout);
|
|
20559
|
+
const onThemeChange = () => {
|
|
20560
|
+
try {
|
|
20561
|
+
win.setBackgroundColor(readBgColor(htmlPath, "#F4F4F4"));
|
|
20562
|
+
} catch {}
|
|
20563
|
+
};
|
|
20564
|
+
nativeTheme.on("updated", onThemeChange);
|
|
20565
|
+
win.on("closed", () => {
|
|
20566
|
+
nativeTheme.removeListener("updated", onThemeChange);
|
|
20567
|
+
});
|
|
20510
20568
|
let ready = false;
|
|
20511
20569
|
const pending = [];
|
|
20512
20570
|
view.webContents.once("did-finish-load", () => {
|
|
@@ -0,0 +1,586 @@
|
|
|
1
|
+
import { n as __exportAll } from "./chunk-DsiFFCwN.mjs";
|
|
2
|
+
import { i as loadPluginManifest, n as loadConfig, r as loadPluginFromPath, t as findConfigPath } from "./load-config-C2XloBaQ.mjs";
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
//#region src/cli/commands/link.ts
|
|
6
|
+
var link_exports = /* @__PURE__ */ __exportAll({
|
|
7
|
+
linkProject: () => linkProject,
|
|
8
|
+
linkSinglePlugin: () => linkSinglePlugin,
|
|
9
|
+
runLink: () => runLink
|
|
10
|
+
});
|
|
11
|
+
const DOTZENBU_TYPES = path.join(".zenbu", "types");
|
|
12
|
+
const SERVICE_BASE_LITERAL = [
|
|
13
|
+
` | "evaluate"`,
|
|
14
|
+
` | "shutdown"`,
|
|
15
|
+
` | "constructor"`,
|
|
16
|
+
` | "effect"`,
|
|
17
|
+
` | "__cleanupAllEffects"`,
|
|
18
|
+
` | "__effectCleanups"`,
|
|
19
|
+
` | "ctx"`
|
|
20
|
+
].join("\n");
|
|
21
|
+
const EXTRACT_RPC_DECL = [
|
|
22
|
+
"type ExtractRpcMethods<T> = {",
|
|
23
|
+
" [K in Exclude<keyof T, ServiceBase | `_${string}`> as T[K] extends (",
|
|
24
|
+
" ...args: any[]",
|
|
25
|
+
" ) => any",
|
|
26
|
+
" ? K",
|
|
27
|
+
" : never]: T[K]",
|
|
28
|
+
"}"
|
|
29
|
+
].join("\n");
|
|
30
|
+
function expandGlob(baseDir, pattern) {
|
|
31
|
+
if (!pattern.includes("*")) {
|
|
32
|
+
const full = path.resolve(baseDir, pattern);
|
|
33
|
+
return fs.existsSync(full) ? [full] : [];
|
|
34
|
+
}
|
|
35
|
+
const dir = path.resolve(baseDir, path.dirname(pattern));
|
|
36
|
+
const filePattern = path.basename(pattern);
|
|
37
|
+
const regex = new RegExp("^" + filePattern.replace(/\./g, "\\.").replace(/\*/g, ".*") + "$");
|
|
38
|
+
try {
|
|
39
|
+
return fs.readdirSync(dir).filter((f) => regex.test(f)).map((f) => path.resolve(dir, f));
|
|
40
|
+
} catch {
|
|
41
|
+
return [];
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
const SERVICE_CLASS_KEY_RE = /export\s+class\s+(\w+)\s+extends\s+Service\.create\s*\(\s*\{[\s\S]*?\bkey\s*:\s*["']([^"']+)["']/;
|
|
45
|
+
function discoverServices(baseDir, serviceGlobs) {
|
|
46
|
+
const entries = [];
|
|
47
|
+
for (const glob of serviceGlobs) for (const filePath of expandGlob(baseDir, glob)) {
|
|
48
|
+
const match = fs.readFileSync(filePath, "utf8").match(SERVICE_CLASS_KEY_RE);
|
|
49
|
+
if (match) entries.push({
|
|
50
|
+
className: match[1],
|
|
51
|
+
key: match[2],
|
|
52
|
+
filePath
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
return entries;
|
|
56
|
+
}
|
|
57
|
+
function discoverOwnSurface(plugin) {
|
|
58
|
+
const serviceGlobs = plugin.services.map((abs) => path.relative(plugin.dir, abs).split(path.sep).join("/"));
|
|
59
|
+
return {
|
|
60
|
+
services: discoverServices(plugin.dir, serviceGlobs),
|
|
61
|
+
schemaPath: plugin.schemaPath,
|
|
62
|
+
eventsPath: plugin.eventsPath,
|
|
63
|
+
preloadPath: plugin.preloadPath
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
function relImport(from, to) {
|
|
67
|
+
let r = path.relative(from, to).split(path.sep).join("/");
|
|
68
|
+
if (!r.startsWith(".")) r = "./" + r;
|
|
69
|
+
return r.replace(/\.ts$/, "");
|
|
70
|
+
}
|
|
71
|
+
function quoteKey(name) {
|
|
72
|
+
return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name) ? name : `"${name}"`;
|
|
73
|
+
}
|
|
74
|
+
function sanitizeIdent(name) {
|
|
75
|
+
return name.replace(/[^a-zA-Z0-9_$]/g, "_");
|
|
76
|
+
}
|
|
77
|
+
function writeIfChanged(target, body, opts) {
|
|
78
|
+
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
79
|
+
let prev = null;
|
|
80
|
+
try {
|
|
81
|
+
prev = fs.readFileSync(target, "utf8");
|
|
82
|
+
} catch {}
|
|
83
|
+
if (prev === body) return false;
|
|
84
|
+
fs.writeFileSync(target, body);
|
|
85
|
+
if (!opts.quiet) console.log(` Wrote ${target}`);
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
/** jsonc-lite: strips // and /* * / comments and trailing commas. */
|
|
89
|
+
function readJsonLoose(raw) {
|
|
90
|
+
const stripped = raw.replace(/\/\*[\s\S]*?\*\//g, "").replace(/(^|[^:])\/\/.*$/gm, "$1").replace(/,\s*([\]}])/g, "$1");
|
|
91
|
+
return JSON.parse(stripped);
|
|
92
|
+
}
|
|
93
|
+
function generateServicesFile(surfaceDir, surface) {
|
|
94
|
+
const imports = [];
|
|
95
|
+
const usedNames = /* @__PURE__ */ new Map();
|
|
96
|
+
const lines = [];
|
|
97
|
+
const uniqueName = (base) => {
|
|
98
|
+
const count = usedNames.get(base) ?? 0;
|
|
99
|
+
usedNames.set(base, count + 1);
|
|
100
|
+
return count === 0 ? base : `${base}_${count}`;
|
|
101
|
+
};
|
|
102
|
+
for (const svc of surface.services) {
|
|
103
|
+
const alias = uniqueName(svc.className);
|
|
104
|
+
imports.push(`import type { ${svc.className}${alias !== svc.className ? ` as ${alias}` : ""} } from "${relImport(surfaceDir, svc.filePath)}"`);
|
|
105
|
+
lines.push(` ${quoteKey(svc.key)}: ExtractRpcMethods<${alias}>;`);
|
|
106
|
+
}
|
|
107
|
+
return [
|
|
108
|
+
"// Generated by: zen link",
|
|
109
|
+
"// DO NOT EDIT. Pointer-only file: imports resolve directly to source on disk.",
|
|
110
|
+
"",
|
|
111
|
+
...imports,
|
|
112
|
+
"",
|
|
113
|
+
`type ServiceBase =\n${SERVICE_BASE_LITERAL}`,
|
|
114
|
+
"",
|
|
115
|
+
EXTRACT_RPC_DECL,
|
|
116
|
+
"",
|
|
117
|
+
"export type SelfServiceMap = {",
|
|
118
|
+
...lines,
|
|
119
|
+
"}",
|
|
120
|
+
""
|
|
121
|
+
].join("\n");
|
|
122
|
+
}
|
|
123
|
+
function generateDbFile(surfaceDir, surface) {
|
|
124
|
+
if (!surface.schemaPath) return [
|
|
125
|
+
"// Generated by: zen link",
|
|
126
|
+
"",
|
|
127
|
+
"export type SelfDbSection = {}",
|
|
128
|
+
""
|
|
129
|
+
].join("\n");
|
|
130
|
+
return [
|
|
131
|
+
"// Generated by: zen link",
|
|
132
|
+
"",
|
|
133
|
+
`import type { InferSchemaRoot } from "@zenbujs/core/db"`,
|
|
134
|
+
`import type schema from "${relImport(surfaceDir, surface.schemaPath)}"`,
|
|
135
|
+
"",
|
|
136
|
+
"export type SelfDbSection = InferSchemaRoot<typeof schema>",
|
|
137
|
+
""
|
|
138
|
+
].join("\n");
|
|
139
|
+
}
|
|
140
|
+
function generateEventsFile(surfaceDir, surface) {
|
|
141
|
+
if (!surface.eventsPath) return [
|
|
142
|
+
"// Generated by: zen link",
|
|
143
|
+
"",
|
|
144
|
+
"export type SelfEvents = {}",
|
|
145
|
+
""
|
|
146
|
+
].join("\n");
|
|
147
|
+
return [
|
|
148
|
+
"// Generated by: zen link",
|
|
149
|
+
"",
|
|
150
|
+
`import type { Events } from "${relImport(surfaceDir, surface.eventsPath)}"`,
|
|
151
|
+
"",
|
|
152
|
+
"export type SelfEvents = Events",
|
|
153
|
+
""
|
|
154
|
+
].join("\n");
|
|
155
|
+
}
|
|
156
|
+
function generatePreloadsFile(surfaceDir, surface) {
|
|
157
|
+
if (!surface.preloadPath) return [
|
|
158
|
+
"// Generated by: zen link",
|
|
159
|
+
"",
|
|
160
|
+
"export type SelfPreload = unknown",
|
|
161
|
+
""
|
|
162
|
+
].join("\n");
|
|
163
|
+
return [
|
|
164
|
+
"// Generated by: zen link",
|
|
165
|
+
"",
|
|
166
|
+
`import type { default as preload } from "${relImport(surfaceDir, surface.preloadPath)}"`,
|
|
167
|
+
"",
|
|
168
|
+
"export type SelfPreload = Awaited<ReturnType<typeof preload>>",
|
|
169
|
+
""
|
|
170
|
+
].join("\n");
|
|
171
|
+
}
|
|
172
|
+
function generateIndexFile() {
|
|
173
|
+
return [
|
|
174
|
+
"// Generated by: zen link",
|
|
175
|
+
"",
|
|
176
|
+
`import type { SelfServiceMap } from "./services"`,
|
|
177
|
+
`import type { SelfDbSection } from "./db-sections"`,
|
|
178
|
+
`import type { SelfEvents } from "./events"`,
|
|
179
|
+
`import type { SelfPreload } from "./preloads"`,
|
|
180
|
+
"",
|
|
181
|
+
"export type Own = {",
|
|
182
|
+
" services: SelfServiceMap",
|
|
183
|
+
" db: SelfDbSection",
|
|
184
|
+
" events: SelfEvents",
|
|
185
|
+
" preloads: SelfPreload",
|
|
186
|
+
"}",
|
|
187
|
+
""
|
|
188
|
+
].join("\n");
|
|
189
|
+
}
|
|
190
|
+
function writeSurface(surfaceDir, surface, opts) {
|
|
191
|
+
fs.mkdirSync(surfaceDir, { recursive: true });
|
|
192
|
+
writeIfChanged(path.join(surfaceDir, "services.ts"), generateServicesFile(surfaceDir, surface), opts);
|
|
193
|
+
writeIfChanged(path.join(surfaceDir, "db-sections.ts"), generateDbFile(surfaceDir, surface), opts);
|
|
194
|
+
writeIfChanged(path.join(surfaceDir, "events.ts"), generateEventsFile(surfaceDir, surface), opts);
|
|
195
|
+
writeIfChanged(path.join(surfaceDir, "preloads.ts"), generatePreloadsFile(surfaceDir, surface), opts);
|
|
196
|
+
writeIfChanged(path.join(surfaceDir, "index.ts"), generateIndexFile(), opts);
|
|
197
|
+
}
|
|
198
|
+
function generateCompositeFile(args) {
|
|
199
|
+
const lines = [
|
|
200
|
+
"// Generated by: zen link",
|
|
201
|
+
"// DO NOT EDIT. Composite augmentation (own + deps) for this plugin.",
|
|
202
|
+
"",
|
|
203
|
+
`import type {} from "@zenbujs/core/registry"`,
|
|
204
|
+
`import type { CoreServiceRouter, CoreEvents, CoreDbSections } from "@zenbujs/core/registry-generated"`
|
|
205
|
+
];
|
|
206
|
+
if (args.selfName && args.selfOwnImport) lines.push(`import type { Own as Self_${sanitizeIdent(args.selfName)} } from "${args.selfOwnImport}"`);
|
|
207
|
+
for (const d of args.deps) lines.push(`import type { Own as Dep_${sanitizeIdent(d.name)} } from "${d.ownImport}"`);
|
|
208
|
+
lines.push("");
|
|
209
|
+
const rpcEntries = [];
|
|
210
|
+
const evtEntries = [];
|
|
211
|
+
const dbEntries = [];
|
|
212
|
+
if (args.selfName && args.selfOwnImport) {
|
|
213
|
+
const k = quoteKey(args.selfName);
|
|
214
|
+
const a = sanitizeIdent(args.selfName);
|
|
215
|
+
rpcEntries.push(` ${k}: Self_${a}["services"];`);
|
|
216
|
+
evtEntries.push(` ${k}: Self_${a}["events"];`);
|
|
217
|
+
dbEntries.push(` ${k}: Self_${a}["db"];`);
|
|
218
|
+
}
|
|
219
|
+
for (const d of args.deps) {
|
|
220
|
+
const k = quoteKey(d.name);
|
|
221
|
+
const a = sanitizeIdent(d.name);
|
|
222
|
+
rpcEntries.push(` ${k}: Dep_${a}["services"];`);
|
|
223
|
+
evtEntries.push(` ${k}: Dep_${a}["events"];`);
|
|
224
|
+
dbEntries.push(` ${k}: Dep_${a}["db"];`);
|
|
225
|
+
}
|
|
226
|
+
lines.push(`declare module "@zenbujs/core/registry" {`);
|
|
227
|
+
lines.push(` interface ZenbuRegister {`);
|
|
228
|
+
lines.push(` rpc: CoreServiceRouter & {`);
|
|
229
|
+
if (rpcEntries.length === 0) lines.push(` // (no plugins)`);
|
|
230
|
+
lines.push(...rpcEntries);
|
|
231
|
+
lines.push(` };`);
|
|
232
|
+
lines.push(` events: CoreEvents & {`);
|
|
233
|
+
if (evtEntries.length === 0) lines.push(` // (no plugins)`);
|
|
234
|
+
lines.push(...evtEntries);
|
|
235
|
+
lines.push(` };`);
|
|
236
|
+
lines.push(` db: CoreDbSections & {`);
|
|
237
|
+
if (dbEntries.length === 0) lines.push(` // (no plugins)`);
|
|
238
|
+
lines.push(...dbEntries);
|
|
239
|
+
lines.push(` };`);
|
|
240
|
+
lines.push(` }`);
|
|
241
|
+
lines.push(`}`);
|
|
242
|
+
lines.push("");
|
|
243
|
+
lines.push("export {}");
|
|
244
|
+
lines.push("");
|
|
245
|
+
return lines.join("\n");
|
|
246
|
+
}
|
|
247
|
+
const REGISTER_INCLUDE = "./.zenbu/types/zenbu-register.ts";
|
|
248
|
+
function bootstrapTsconfigJson(pluginDir, opts) {
|
|
249
|
+
const tsconfigPath = path.join(pluginDir, "tsconfig.json");
|
|
250
|
+
if (!fs.existsSync(tsconfigPath)) return;
|
|
251
|
+
const raw = fs.readFileSync(tsconfigPath, "utf8");
|
|
252
|
+
let parsed;
|
|
253
|
+
try {
|
|
254
|
+
parsed = readJsonLoose(raw);
|
|
255
|
+
} catch {
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
const includeArr = Array.isArray(parsed.include) ? [...parsed.include] : [];
|
|
259
|
+
if (includeArr.includes(REGISTER_INCLUDE)) return;
|
|
260
|
+
includeArr.push(REGISTER_INCLUDE);
|
|
261
|
+
parsed.include = includeArr;
|
|
262
|
+
const next = JSON.stringify(parsed, null, 2) + "\n";
|
|
263
|
+
if (next === raw) return;
|
|
264
|
+
fs.writeFileSync(tsconfigPath, next);
|
|
265
|
+
if (!opts.quiet) console.log(` Updated ${tsconfigPath}`);
|
|
266
|
+
}
|
|
267
|
+
const GITIGNORE_MARKER = "# zen link: generated types";
|
|
268
|
+
const GITIGNORE_RULE = ".zenbu/types/";
|
|
269
|
+
const GITIGNORE_BROAD_RULES = new Set([
|
|
270
|
+
".zenbu",
|
|
271
|
+
".zenbu/",
|
|
272
|
+
"/.zenbu",
|
|
273
|
+
"/.zenbu/",
|
|
274
|
+
".zenbu/*",
|
|
275
|
+
".zenbu/**",
|
|
276
|
+
".zenbu/**/*",
|
|
277
|
+
".zenbu/types",
|
|
278
|
+
".zenbu/types/",
|
|
279
|
+
".zenbu/types/**",
|
|
280
|
+
".zenbu/types/**/*"
|
|
281
|
+
]);
|
|
282
|
+
function bootstrapGitignore(pluginDir, opts) {
|
|
283
|
+
const gitignorePath = path.join(pluginDir, ".gitignore");
|
|
284
|
+
let raw = "";
|
|
285
|
+
try {
|
|
286
|
+
raw = fs.readFileSync(gitignorePath, "utf8");
|
|
287
|
+
} catch {
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
const lines = raw.split(/\r?\n/);
|
|
291
|
+
for (const line of lines) {
|
|
292
|
+
const trimmed = line.trim();
|
|
293
|
+
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
294
|
+
if (GITIGNORE_BROAD_RULES.has(trimmed)) return;
|
|
295
|
+
if (trimmed === GITIGNORE_RULE) return;
|
|
296
|
+
}
|
|
297
|
+
const append = `${raw.endsWith("\n") ? "" : "\n"}\n${GITIGNORE_MARKER}\n${GITIGNORE_RULE}\n`;
|
|
298
|
+
fs.writeFileSync(gitignorePath, raw + append);
|
|
299
|
+
if (!opts.quiet) console.log(` Updated ${gitignorePath}`);
|
|
300
|
+
}
|
|
301
|
+
function generateCoreSurfaceFile(args) {
|
|
302
|
+
const sorted = [...args.services].sort((a, b) => a.className.localeCompare(b.className));
|
|
303
|
+
const importedNames = sorted.map((s) => ` ${s.className},`).join("\n");
|
|
304
|
+
const routerEntries = sorted.map((s) => ` ${quoteKey(s.key)}: ExtractRpcMethods<${s.className}>;`).join("\n");
|
|
305
|
+
const lines = [
|
|
306
|
+
"// Generated by: pnpm link:types",
|
|
307
|
+
"// DO NOT EDIT. Regenerated automatically (also wired into `prebuild`).",
|
|
308
|
+
""
|
|
309
|
+
];
|
|
310
|
+
if (sorted.length > 0) {
|
|
311
|
+
lines.push("import type {");
|
|
312
|
+
lines.push(importedNames);
|
|
313
|
+
lines.push(`} from "@zenbujs/core/services"`);
|
|
314
|
+
}
|
|
315
|
+
if (args.hasEvents) lines.push(`import type { Events as Events_core } from "@zenbujs/core/events"`);
|
|
316
|
+
if (args.hasSchema) {
|
|
317
|
+
lines.push(`import type schema_core from "@zenbujs/core/schema"`);
|
|
318
|
+
lines.push(`import type { InferSchemaRoot } from "@zenbujs/core/db"`);
|
|
319
|
+
}
|
|
320
|
+
lines.push("");
|
|
321
|
+
lines.push(`type ServiceBase =\n${SERVICE_BASE_LITERAL}`);
|
|
322
|
+
lines.push("");
|
|
323
|
+
lines.push(EXTRACT_RPC_DECL);
|
|
324
|
+
lines.push("");
|
|
325
|
+
lines.push("export type CoreServiceRouter = {");
|
|
326
|
+
lines.push(" core: {");
|
|
327
|
+
if (routerEntries.length > 0) lines.push(routerEntries);
|
|
328
|
+
lines.push(" };");
|
|
329
|
+
lines.push("}");
|
|
330
|
+
lines.push("");
|
|
331
|
+
lines.push(`export type CoreEvents = { core: ${args.hasEvents ? "Events_core" : "{}"} }`);
|
|
332
|
+
lines.push("");
|
|
333
|
+
lines.push("export type CoreDbSections = {");
|
|
334
|
+
if (args.hasSchema) lines.push(" core: InferSchemaRoot<typeof schema_core>;");
|
|
335
|
+
lines.push("}");
|
|
336
|
+
lines.push("");
|
|
337
|
+
lines.push("export type CorePreloads = {}");
|
|
338
|
+
lines.push("");
|
|
339
|
+
return lines.join("\n");
|
|
340
|
+
}
|
|
341
|
+
function generateCoreAugmentFile() {
|
|
342
|
+
return [
|
|
343
|
+
"// Generated by: pnpm link:types",
|
|
344
|
+
"// DO NOT EDIT. Local-only augmentation (NOT shipped via package.json#files).",
|
|
345
|
+
"// Drives core's own typecheck so useRpc()/useEvents()/useDb() resolve",
|
|
346
|
+
"// to the registered surface inside packages/core/src/.",
|
|
347
|
+
"",
|
|
348
|
+
`import type {} from "@zenbujs/core/registry"`,
|
|
349
|
+
`import type {`,
|
|
350
|
+
` CoreServiceRouter,`,
|
|
351
|
+
` CoreEvents,`,
|
|
352
|
+
` CoreDbSections,`,
|
|
353
|
+
`} from "../src/registry-generated"`,
|
|
354
|
+
"",
|
|
355
|
+
`declare module "@zenbujs/core/registry" {`,
|
|
356
|
+
" interface ZenbuRegister {",
|
|
357
|
+
" rpc: CoreServiceRouter",
|
|
358
|
+
" events: CoreEvents",
|
|
359
|
+
" db: CoreDbSections",
|
|
360
|
+
" }",
|
|
361
|
+
"}",
|
|
362
|
+
"",
|
|
363
|
+
"export {}",
|
|
364
|
+
""
|
|
365
|
+
].join("\n");
|
|
366
|
+
}
|
|
367
|
+
function writeCoreSurfaceFiles(args) {
|
|
368
|
+
writeIfChanged(args.surfaceOut, generateCoreSurfaceFile({
|
|
369
|
+
services: args.services,
|
|
370
|
+
hasEvents: args.hasEvents,
|
|
371
|
+
hasSchema: args.hasSchema
|
|
372
|
+
}), args.opts);
|
|
373
|
+
writeIfChanged(args.augmentOut, generateCoreAugmentFile(), args.opts);
|
|
374
|
+
}
|
|
375
|
+
function parseLinkArgs(argv) {
|
|
376
|
+
let manifestArg = null;
|
|
377
|
+
let typesConfigArg = null;
|
|
378
|
+
let surfaceOutArg = null;
|
|
379
|
+
let augmentOutArg = null;
|
|
380
|
+
let pluginMode = false;
|
|
381
|
+
let pluginDirArg = null;
|
|
382
|
+
for (let i = 0; i < argv.length; i++) {
|
|
383
|
+
const arg = argv[i];
|
|
384
|
+
if (arg === "--types-config" && i + 1 < argv.length) typesConfigArg = argv[++i];
|
|
385
|
+
else if (arg.startsWith("--types-config=")) typesConfigArg = arg.slice(15);
|
|
386
|
+
else if (arg === "--out" && i + 1 < argv.length) surfaceOutArg = argv[++i];
|
|
387
|
+
else if (arg.startsWith("--out=")) surfaceOutArg = arg.slice(6);
|
|
388
|
+
else if (arg === "--augment-out" && i + 1 < argv.length) augmentOutArg = argv[++i];
|
|
389
|
+
else if (arg.startsWith("--augment-out=")) augmentOutArg = arg.slice(14);
|
|
390
|
+
else if (arg === "--plugin") {
|
|
391
|
+
pluginMode = true;
|
|
392
|
+
const next = argv[i + 1];
|
|
393
|
+
if (next && !next.startsWith("-")) {
|
|
394
|
+
pluginDirArg = next;
|
|
395
|
+
i++;
|
|
396
|
+
}
|
|
397
|
+
} else if (arg.startsWith("--plugin=")) {
|
|
398
|
+
pluginMode = true;
|
|
399
|
+
pluginDirArg = arg.slice(9);
|
|
400
|
+
} else if (!arg.startsWith("-") && !manifestArg) manifestArg = arg;
|
|
401
|
+
}
|
|
402
|
+
return {
|
|
403
|
+
manifestArg,
|
|
404
|
+
typesConfigArg,
|
|
405
|
+
surfaceOutArg,
|
|
406
|
+
augmentOutArg,
|
|
407
|
+
pluginMode,
|
|
408
|
+
pluginDirArg
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
/**
|
|
412
|
+
* Per-plugin link pipeline. Used by both `linkProject` (host context) and
|
|
413
|
+
* `linkSinglePlugin` (standalone). Writes the plugin's own surface, each
|
|
414
|
+
* declared dep surface, the composite augmentation, and bootstraps
|
|
415
|
+
* `tsconfig.json` / `.gitignore`. Stale `deps/<name>/` dirs that aren't in
|
|
416
|
+
* the current `dependsOn` set are pruned.
|
|
417
|
+
*/
|
|
418
|
+
async function processOnePlugin(plugin, writeOpts, log) {
|
|
419
|
+
const surface = discoverOwnSurface(plugin);
|
|
420
|
+
log(`Linking own surface "${plugin.name}" at ${plugin.dir}`);
|
|
421
|
+
log(` ${surface.services.length} service(s)`);
|
|
422
|
+
if (surface.schemaPath) log(` schema: ${surface.schemaPath}`);
|
|
423
|
+
if (surface.eventsPath) log(` events: ${surface.eventsPath}`);
|
|
424
|
+
if (surface.preloadPath) log(` preload: ${surface.preloadPath}`);
|
|
425
|
+
writeSurface(path.join(plugin.dir, DOTZENBU_TYPES, "own"), surface, writeOpts);
|
|
426
|
+
const deps = [];
|
|
427
|
+
for (const dep of plugin.dependsOn ?? []) {
|
|
428
|
+
const upstream = await loadPluginFromPath({
|
|
429
|
+
fromPath: dep.fromPath,
|
|
430
|
+
name: dep.name
|
|
431
|
+
});
|
|
432
|
+
const surfaceDir = path.join(plugin.dir, DOTZENBU_TYPES, "deps", dep.name);
|
|
433
|
+
const upstreamSurface = discoverOwnSurface(upstream);
|
|
434
|
+
log(`Linking dep "${dep.name}" into "${plugin.name}" (${upstream.dir})`);
|
|
435
|
+
writeSurface(surfaceDir, upstreamSurface, writeOpts);
|
|
436
|
+
deps.push({
|
|
437
|
+
depName: dep.name,
|
|
438
|
+
ownImportFromComposite: relImport(path.join(plugin.dir, DOTZENBU_TYPES), path.join(surfaceDir, "index.ts"))
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
const wantedDepNames = new Set(deps.map((d) => d.depName));
|
|
442
|
+
const depsRoot = path.join(plugin.dir, DOTZENBU_TYPES, "deps");
|
|
443
|
+
if (fs.existsSync(depsRoot)) for (const entry of fs.readdirSync(depsRoot)) {
|
|
444
|
+
if (wantedDepNames.has(entry)) continue;
|
|
445
|
+
const stale = path.join(depsRoot, entry);
|
|
446
|
+
try {
|
|
447
|
+
fs.rmSync(stale, {
|
|
448
|
+
recursive: true,
|
|
449
|
+
force: true
|
|
450
|
+
});
|
|
451
|
+
if (!writeOpts.quiet) console.log(` Pruned ${stale}`);
|
|
452
|
+
} catch {}
|
|
453
|
+
}
|
|
454
|
+
const compositePath = path.join(plugin.dir, DOTZENBU_TYPES, "zenbu-register.ts");
|
|
455
|
+
const selfOwnImport = relImport(path.dirname(compositePath), path.join(plugin.dir, DOTZENBU_TYPES, "own", "index.ts"));
|
|
456
|
+
writeIfChanged(compositePath, generateCompositeFile({
|
|
457
|
+
selfName: plugin.name,
|
|
458
|
+
selfOwnImport,
|
|
459
|
+
deps: deps.map((d) => ({
|
|
460
|
+
name: d.depName,
|
|
461
|
+
ownImport: d.ownImportFromComposite
|
|
462
|
+
}))
|
|
463
|
+
}), writeOpts);
|
|
464
|
+
bootstrapTsconfigJson(plugin.dir, writeOpts);
|
|
465
|
+
bootstrapGitignore(plugin.dir, writeOpts);
|
|
466
|
+
}
|
|
467
|
+
async function linkProject(projectDir, opts = {}) {
|
|
468
|
+
const writeOpts = { quiet: !!opts.quiet };
|
|
469
|
+
const log = opts.quiet ? () => {} : (msg) => console.log(msg);
|
|
470
|
+
const { resolved, pluginSourceFiles } = await loadConfig(projectDir);
|
|
471
|
+
const inlinePlugins = resolved.plugins.filter((p) => p.dir === resolved.projectDir);
|
|
472
|
+
if (inlinePlugins.length > 1) throw new Error(`zen link: ${resolved.configPath} declares ${inlinePlugins.length} inline plugins (${inlinePlugins.map((p) => `"${p.name}"`).join(", ")}). Move all but one into separate zenbu.plugin.ts files so each owns its own .zenbu/types/ dir.`);
|
|
473
|
+
for (const plugin of resolved.plugins) await processOnePlugin(plugin, writeOpts, log);
|
|
474
|
+
if (inlinePlugins.length === 0) {
|
|
475
|
+
bootstrapTsconfigJson(resolved.projectDir, writeOpts);
|
|
476
|
+
bootstrapGitignore(resolved.projectDir, writeOpts);
|
|
477
|
+
}
|
|
478
|
+
return {
|
|
479
|
+
registryDir: path.join(resolved.projectDir, DOTZENBU_TYPES),
|
|
480
|
+
resolvedConfigPath: resolved.configPath,
|
|
481
|
+
pluginSourceFiles,
|
|
482
|
+
resolved
|
|
483
|
+
};
|
|
484
|
+
}
|
|
485
|
+
/**
|
|
486
|
+
* Standalone plugin link. Used by `zen link --plugin <dir>` when there's no
|
|
487
|
+
* host context — for example, right after `create-zenbu-app --plugin`
|
|
488
|
+
* scaffolds a plugin folder that hasn't been wired into any host yet.
|
|
489
|
+
*
|
|
490
|
+
* The plugin's `zenbu.plugin.ts` is loaded directly (no `zenbu.config.ts`
|
|
491
|
+
* required), and we run the same per-plugin pipeline `linkProject` uses.
|
|
492
|
+
*/
|
|
493
|
+
async function linkSinglePlugin(pluginDir, opts = {}) {
|
|
494
|
+
const writeOpts = { quiet: !!opts.quiet };
|
|
495
|
+
const log = opts.quiet ? () => {} : (msg) => console.log(msg);
|
|
496
|
+
const candidates = [
|
|
497
|
+
"zenbu.plugin.ts",
|
|
498
|
+
"zenbu.plugin.mts",
|
|
499
|
+
"zenbu.plugin.js",
|
|
500
|
+
"zenbu.plugin.mjs"
|
|
501
|
+
];
|
|
502
|
+
let manifestPath = null;
|
|
503
|
+
for (const name of candidates) {
|
|
504
|
+
const candidate = path.join(pluginDir, name);
|
|
505
|
+
if (fs.existsSync(candidate)) {
|
|
506
|
+
manifestPath = candidate;
|
|
507
|
+
break;
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
if (!manifestPath) throw new Error(`zen link --plugin: no zenbu.plugin.ts found in ${pluginDir}. Expected one of: ${candidates.join(", ")}.`);
|
|
511
|
+
await processOnePlugin(await loadPluginManifest(manifestPath), writeOpts, log);
|
|
512
|
+
}
|
|
513
|
+
const CONFIG_NAMES = [
|
|
514
|
+
"zenbu.config.ts",
|
|
515
|
+
"zenbu.config.mts",
|
|
516
|
+
"zenbu.config.js",
|
|
517
|
+
"zenbu.config.mjs"
|
|
518
|
+
];
|
|
519
|
+
function findProjectDir(from) {
|
|
520
|
+
let dir = path.resolve(from);
|
|
521
|
+
while (true) {
|
|
522
|
+
for (const name of CONFIG_NAMES) if (fs.existsSync(path.join(dir, name))) return dir;
|
|
523
|
+
const parent = path.dirname(dir);
|
|
524
|
+
if (parent === dir) return null;
|
|
525
|
+
dir = parent;
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
async function runLink(argv) {
|
|
529
|
+
const args = parseLinkArgs(argv);
|
|
530
|
+
if (args.typesConfigArg) {
|
|
531
|
+
const typeConfigPath = path.resolve(args.typesConfigArg);
|
|
532
|
+
const rootManifest = JSON.parse(fs.readFileSync(typeConfigPath, "utf8"));
|
|
533
|
+
const baseDir = path.dirname(typeConfigPath);
|
|
534
|
+
const surfaceOut = args.surfaceOutArg ? path.resolve(args.surfaceOutArg) : path.join(baseDir, "src", "registry-generated.ts");
|
|
535
|
+
const augmentOut = args.augmentOutArg ? path.resolve(args.augmentOutArg) : path.join(baseDir, "types", "zenbu-register.ts");
|
|
536
|
+
try {
|
|
537
|
+
console.log(`Linking core types from ${baseDir}`);
|
|
538
|
+
const services = discoverServices(baseDir, rootManifest.services ?? []);
|
|
539
|
+
console.log(` Found ${services.length} service(s)`);
|
|
540
|
+
const hasEvents = !!rootManifest.events;
|
|
541
|
+
const hasSchema = !!rootManifest.schema;
|
|
542
|
+
if (rootManifest.events) console.log(` Events: ${path.resolve(baseDir, rootManifest.events)}`);
|
|
543
|
+
if (rootManifest.schema) console.log(` Schema: ${path.resolve(baseDir, rootManifest.schema)}`);
|
|
544
|
+
writeCoreSurfaceFiles({
|
|
545
|
+
services,
|
|
546
|
+
hasEvents,
|
|
547
|
+
hasSchema,
|
|
548
|
+
surfaceOut,
|
|
549
|
+
augmentOut,
|
|
550
|
+
opts: { quiet: false }
|
|
551
|
+
});
|
|
552
|
+
console.log("Done.");
|
|
553
|
+
} catch (err) {
|
|
554
|
+
console.error(err instanceof Error ? err.message : err);
|
|
555
|
+
process.exit(1);
|
|
556
|
+
}
|
|
557
|
+
return;
|
|
558
|
+
}
|
|
559
|
+
if (args.pluginMode) {
|
|
560
|
+
const pluginDir = path.resolve(args.pluginDirArg ?? process.cwd());
|
|
561
|
+
try {
|
|
562
|
+
await linkSinglePlugin(pluginDir);
|
|
563
|
+
console.log("Done.");
|
|
564
|
+
} catch (err) {
|
|
565
|
+
console.error(err instanceof Error ? err.message : err);
|
|
566
|
+
process.exit(1);
|
|
567
|
+
}
|
|
568
|
+
return;
|
|
569
|
+
}
|
|
570
|
+
const projectDir = args.manifestArg ? path.resolve(args.manifestArg) : findProjectDir(process.cwd());
|
|
571
|
+
if (!projectDir) {
|
|
572
|
+
console.error("zen link: could not find zenbu.config.ts in current directory or any parent.");
|
|
573
|
+
console.error(" For internal framework types, pass --types-config <path>.");
|
|
574
|
+
process.exit(1);
|
|
575
|
+
}
|
|
576
|
+
try {
|
|
577
|
+
findConfigPath(projectDir);
|
|
578
|
+
await linkProject(projectDir);
|
|
579
|
+
console.log("Done.");
|
|
580
|
+
} catch (err) {
|
|
581
|
+
console.error(err instanceof Error ? err.message : err);
|
|
582
|
+
process.exit(1);
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
//#endregion
|
|
586
|
+
export { link_exports as n, linkProject as t };
|