zelari-code 1.3.0 → 1.5.0

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 (42) hide show
  1. package/README.md +67 -3
  2. package/dist/cli/components/PluginGate.js +195 -0
  3. package/dist/cli/components/PluginGate.js.map +1 -0
  4. package/dist/cli/diagnostics/engine.js +2 -10
  5. package/dist/cli/diagnostics/engine.js.map +1 -1
  6. package/dist/cli/hooks/useSlashDispatch.js +17 -0
  7. package/dist/cli/hooks/useSlashDispatch.js.map +1 -1
  8. package/dist/cli/lsp/tools.js +3 -12
  9. package/dist/cli/lsp/tools.js.map +1 -1
  10. package/dist/cli/main.bundled.js +1460 -551
  11. package/dist/cli/main.bundled.js.map +4 -4
  12. package/dist/cli/main.js +124 -6
  13. package/dist/cli/main.js.map +1 -1
  14. package/dist/cli/plugins/installer.js +103 -0
  15. package/dist/cli/plugins/installer.js.map +1 -0
  16. package/dist/cli/plugins/prefs.js +96 -0
  17. package/dist/cli/plugins/prefs.js.map +1 -0
  18. package/dist/cli/plugins/registry.js +209 -0
  19. package/dist/cli/plugins/registry.js.map +1 -0
  20. package/dist/cli/slashCommands.js +18 -1
  21. package/dist/cli/slashCommands.js.map +1 -1
  22. package/dist/cli/slashHandlers/plugins.js +75 -0
  23. package/dist/cli/slashHandlers/plugins.js.map +1 -0
  24. package/dist/cli/slashHandlers/updater.js +27 -3
  25. package/dist/cli/slashHandlers/updater.js.map +1 -1
  26. package/dist/cli/updater.js +1 -1
  27. package/dist/cli/updater.js.map +1 -1
  28. package/dist/cli/utils/doctor.js +66 -4
  29. package/dist/cli/utils/doctor.js.map +1 -1
  30. package/dist/cli/utils/fixPath.js +119 -0
  31. package/dist/cli/utils/fixPath.js.map +1 -0
  32. package/dist/cli/utils/paths.js +47 -0
  33. package/dist/cli/utils/paths.js.map +1 -1
  34. package/dist/cli/utils/prereqChecks.js +362 -0
  35. package/dist/cli/utils/prereqChecks.js.map +1 -0
  36. package/package.json +4 -2
  37. package/scripts/diagnose-path.ps1 +22 -0
  38. package/scripts/dump-path.ps1 +13 -0
  39. package/scripts/fix-path.ps1 +26 -0
  40. package/scripts/path-length.ps1 +15 -0
  41. package/scripts/postinstall.mjs +78 -1
  42. package/scripts/repair-path.mjs +104 -0
package/dist/cli/main.js CHANGED
@@ -8,6 +8,7 @@ import { render } from "ink";
8
8
  // @ts-ignore
9
9
  import { App } from "./app.js";
10
10
  import { SplashGate } from "./components/SplashScreen.js";
11
+ import { PluginGate } from "./components/PluginGate.js";
11
12
  import { getMetricsLogger } from "./metrics.js";
12
13
  import { getProviderConfigPath } from "./providerConfig.js";
13
14
  import { parseWizardFlags, shouldRunWizard } from "./wizard/firstRun.js";
@@ -36,6 +37,69 @@ export const VERSION = getCurrentVersion();
36
37
  * Disabled in dev mode (`ANATHEMA_DEV=1`) to avoid noise during local
37
38
  * development where the bundled version is the source repo.
38
39
  */
40
+ /**
41
+ * Boot-time prerequisite gate (v1.4.0).
42
+ *
43
+ * Probes node/git/bash THROUGH the agent's resolved shell — not the main
44
+ * process — because the agent runs `npm`/`tsc`/build scripts inside the
45
+ * resolved bash (Git Bash on Windows), which inherits a different PATH
46
+ * than this Node process. A user can have node visible to the main process
47
+ * yet invisible to the agent's bash; without this check zelari-code boots
48
+ * happily and the failure surfaces only mid-task (`node: not found`), which
49
+ * is exactly what blocked the Anathema-Studio council run on 2026-07-07.
50
+ *
51
+ * Severity:
52
+ * - node unreachable from agent shell → hard-fail (exit 1). Without node
53
+ * the agent cannot run npm/build/tsc — there is nothing useful it can do.
54
+ * - git / bash missing → warn to stderr, continue. Features degrade but
55
+ * the agent still works for non-git, non-POSIX tasks.
56
+ *
57
+ * Bypass: `ZELARI_SKIP_PREFLIGHT=1` or `--skip-checks`. Intended for CI,
58
+ * sandboxes, and emergency recovery — not normal use.
59
+ *
60
+ * Runs AFTER `pickRootComponent()` (so `--version`/`--help`/`--doctor` keep
61
+ * working on a broken install) but BEFORE skill loading and the TUI render.
62
+ * Never throws — `runPrereqChecks` already swallows per-check errors.
63
+ *
64
+ * @see src/cli/utils/prereqChecks.ts — the probe implementation.
65
+ */
66
+ function runPreflight() {
67
+ if (process.env.ZELARI_SKIP_PREFLIGHT === "1")
68
+ return;
69
+ if (process.argv.includes("--skip-checks"))
70
+ return;
71
+ if (process.env.ANATHEMA_DEV === "1")
72
+ return; // dev: avoid noise on a source checkout.
73
+ const { runPrereqChecks } =
74
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
75
+ require("./utils/prereqChecks.js");
76
+ const { results, hasCriticalFail, warnings } = runPrereqChecks({
77
+ mode: "preflight",
78
+ });
79
+ for (const w of warnings) {
80
+ // eslint-disable-next-line no-console
81
+ console.error(`\x1b[33m[zelari-code] ⚠ ${w.tool}: ${w.message}\x1b[0m`);
82
+ }
83
+ if (hasCriticalFail) {
84
+ const critical = results.find((r) => !r.ok && r.severity === "critical");
85
+ // eslint-disable-next-line no-console
86
+ console.error("");
87
+ // eslint-disable-next-line no-console
88
+ console.error("\x1b[31m" +
89
+ "==============================================================\n" +
90
+ " zelari-code cannot start: a critical prerequisite is missing.\n" +
91
+ "==============================================================\x1b[0m");
92
+ if (critical) {
93
+ // eslint-disable-next-line no-console
94
+ console.error(`\n ${critical.tool}: ${critical.message}`);
95
+ }
96
+ // eslint-disable-next-line no-console
97
+ console.error("\n Run `zelari-code --doctor` for the full diagnostic report.\n" +
98
+ " Bypass this check with ZELARI_SKIP_PREFLIGHT=1 (NOT recommended —\n" +
99
+ " the agent will still fail when it tries to run npm/build/tsc).");
100
+ process.exit(1);
101
+ }
102
+ }
39
103
  async function backgroundUpdateCheck() {
40
104
  if (process.env.ANATHEMA_DEV === "1")
41
105
  return;
@@ -101,10 +165,45 @@ function pickRootComponent() {
101
165
  // v1.0.3: install-health diagnostic. Runs BEFORE the bundle is loaded
102
166
  // and before any provider / config work, so it works on a broken
103
167
  // install (missing bundle, missing shim, wrong PATH, etc.).
168
+ // v1.5.0: async — the optional-plugins check delegates to
169
+ // detectMissingPlugins (dynamic import + async detection).
104
170
  // eslint-disable-next-line @typescript-eslint/no-require-imports
105
171
  const { runDoctor } = require("./utils/doctor.js");
106
- const healthy = runDoctor();
107
- process.exit(healthy ? 0 : 1);
172
+ void runDoctor().then((healthy) => process.exit(healthy ? 0 : 1));
173
+ return { kind: "done" };
174
+ }
175
+ if (argv.includes("--fix-path") || argv.includes("fix-path")) {
176
+ // v1.4.2: runtime PATH repair. Companion to the install-time auto-fix
177
+ // in scripts/postinstall.mjs. Handles the "PATH lost AFTER install"
178
+ // case that postinstall can't reach retroactively. Windows-only at the
179
+ // effect level; POSIX prints an advisory and exits 1.
180
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
181
+ const { repairWindowsUserPath } = require("./utils/fixPath.js");
182
+ const result = repairWindowsUserPath();
183
+ const green = "\x1b[32m";
184
+ const red = "\x1b[31m";
185
+ const dim = "\x1b[2m";
186
+ const reset = "\x1b[0m";
187
+ if (result.ok) {
188
+ if (result.alreadyOk) {
189
+ // eslint-disable-next-line no-console
190
+ console.log(`${green}✔${reset} npm prefix already on user PATH: ${result.prefix}`);
191
+ }
192
+ else {
193
+ // eslint-disable-next-line no-console
194
+ console.log(`${green}✔${reset} added npm prefix to user PATH: ${result.prefix}`);
195
+ // eslint-disable-next-line no-console
196
+ console.log(`${dim}open a NEW terminal for the change to take effect, then run: zelari-code --version${reset}`);
197
+ }
198
+ process.exit(0);
199
+ }
200
+ // eslint-disable-next-line no-console
201
+ console.error(`${red}✗${reset} ${result.error}`);
202
+ if (result.prefix) {
203
+ // eslint-disable-next-line no-console
204
+ console.error(`${dim}prefix: ${result.prefix}${reset}`);
205
+ }
206
+ process.exit(1);
108
207
  }
109
208
  if (argv.includes("--help") || argv.includes("-h")) {
110
209
  // eslint-disable-next-line no-console
@@ -115,7 +214,12 @@ function pickRootComponent() {
115
214
  "Options:\n" +
116
215
  " --version, -v Print version and exit\n" +
117
216
  " --help, -h Print this help and exit\n" +
118
- " --doctor Diagnose install health (shim, bundle, PATH, deps)\n" +
217
+ " --doctor Diagnose install health (shim, bundle, PATH, deps,\n" +
218
+ " node/git/bash in the agent shell)\n" +
219
+ " --fix-path Add the npm global prefix to the user PATH\n" +
220
+ " (Windows only; fixes 'command not found' after install)\n" +
221
+ " --skip-checks Skip the boot-time prerequisite check\n" +
222
+ " (alias for ZELARI_SKIP_PREFLIGHT=1)\n" +
119
223
  " --no-wizard Skip the first-run wizard\n" +
120
224
  " --reset-config Re-run the wizard (clears provider.json on commit)\n" +
121
225
  " --headless Run a single task without mounting the TUI\n" +
@@ -126,8 +230,10 @@ function pickRootComponent() {
126
230
  " --model <id> Model override (default: provider default)\n" +
127
231
  "\n" +
128
232
  "Environment:\n" +
129
- " ZELARI_NO_WIZARD=1 Skip the first-run wizard\n" +
130
- " ANATHEMA_DEV=1 Disable background update check\n");
233
+ " ZELARI_NO_WIZARD=1 Skip the first-run wizard\n" +
234
+ " ZELARI_SKIP_PREFLIGHT=1 Skip the boot prerequisite check\n" +
235
+ " ZELARI_NO_PLUGIN_PROMPT=1 Skip the boot plugin-install prompt\n" +
236
+ " ANATHEMA_DEV=1 Disable background update check + preflight\n");
131
237
  process.exit(0);
132
238
  }
133
239
  // Headless mode: short-circuit TUI entirely. Must be checked BEFORE
@@ -157,9 +263,16 @@ function pickRootComponent() {
157
263
  // v0.7.8: one-shot startup splash (ASCII emblem, ~2s or any-key skip),
158
264
  // then the App mounts. Skipped automatically for non-TTY stdout, small
159
265
  // terminals, or ZELARI_NO_SPLASH=1 — see components/SplashScreen.tsx.
266
+ // v1.5.0: PluginGate wraps App inside SplashGate — after the splash, it
267
+ // detects missing optional plugins (Playwright, eslint, ruff, LSP servers)
268
+ // and offers to install them before the App mounts. Skips on non-TTY,
269
+ // ZELARI_NO_PLUGIN_PROMPT=1, or when nothing is missing.
160
270
  return {
161
271
  kind: "app",
162
- element: React.createElement(SplashGate, { version: VERSION }, React.createElement(App)),
272
+ element: React.createElement(SplashGate, { version: VERSION }, React.createElement(PluginGate, {
273
+ cwd: process.cwd(),
274
+ children: React.createElement(App),
275
+ })),
163
276
  };
164
277
  }
165
278
  /**
@@ -189,6 +302,11 @@ function main() {
189
302
  const picked = pickRootComponent();
190
303
  if (picked.kind === "done")
191
304
  return; // --version or --help printed + exited
305
+ // v1.4.0: verify node/git/bash BEFORE mounting the TUI or running a headless
306
+ // task. Hard-fails on missing node (the agent cannot run npm/build without it),
307
+ // warns on missing git/bash. Skipped for --version/--help/--doctor (handled
308
+ // above) so a broken install can still be diagnosed. See `runPreflight`.
309
+ runPreflight();
192
310
  loadUserSkills();
193
311
  if (picked.kind === "headless") {
194
312
  void runHeadless(picked.headlessOpts).then((code) => {
@@ -1 +1 @@
1
- {"version":3,"file":"main.js","sourceRoot":"","sources":["../../src/cli/main.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"main.js","sourceRoot":"","sources":["../../src/cli/main.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,103 @@
1
+ /**
2
+ * plugins/installer — spawn `npm install` for a plugin, buffered.
3
+ *
4
+ * Mirrors updater.ts:performUpdate (the self-update install path) with two
5
+ * differences:
6
+ * 1. The install scope is per-plugin: `-D` (project-local) for linters +
7
+ * Playwright (that's how diagnostics/engine.ts + browser/driver.ts
8
+ * resolve them via node_modules/.bin / dynamic import), `-g` (global)
9
+ * for LSP servers (cross-project dev tools).
10
+ * 2. No `@latest` pinning — plugins don't self-update, so we install
11
+ * whatever npm resolves as current.
12
+ *
13
+ * Everything else is identical and reuses the updater's hard-won platform
14
+ * handling: buildCmdLine + shell:true on win32 for the `.cmd` shim, and the
15
+ * broken-shim fallback to the npm bundled next to Node (rescues
16
+ * Volta/nvm-windows/fnm where the global npm shim is broken).
17
+ *
18
+ * Output is BUFFERED (stdout+stderr concatenated), surfaced as a single
19
+ * string after exit — same UX as /update. This keeps the install gate simple
20
+ * (no streaming-log component needed) and matches the house style.
21
+ *
22
+ * Contract: never throws. Errors → { ok: false, error }.
23
+ *
24
+ * @see src/cli/updater.ts — performUpdate / runNpm, the template this mirrors
25
+ * @see src/cli/utils/cmdline.ts — buildCmdLine (win32 DEP0190-safe quoting)
26
+ */
27
+ import { spawn } from 'node:child_process';
28
+ import { buildCmdLine } from '../utils/cmdline.js';
29
+ import { resolveBundledNpmCli, looksLikeBrokenShim, } from '../updater.js';
30
+ /**
31
+ * Install a plugin via npm. Respects PluginSpec.installScope (-D vs -g).
32
+ *
33
+ * @param spec The plugin to install.
34
+ * @param cwd Working directory (matters for -D installs; ignored by -g
35
+ * except as the spawn cwd).
36
+ * @param executor Injected spawn (tests). Defaults to node:child_process.spawn.
37
+ */
38
+ export async function installPlugin(spec, cwd, executor = spawn) {
39
+ const scopeFlag = spec.installScope === 'global' ? '-g' : '-D';
40
+ const args = ['install', scopeFlag, spec.npmPackage];
41
+ // Attempt 1: PATH-resolved npm (shell on win32 for the .cmd shim).
42
+ const primary = await runNpm(executor, args, cwd, 'shim');
43
+ if (primary.ok)
44
+ return primary;
45
+ // Attempt 2: if attempt 1 died like a broken bin shim (Volta/nvm/fnm),
46
+ // retry via the npm bundled with Node. No shell, no .cmd in the way.
47
+ const npmCli = resolveBundledNpmCli();
48
+ if (npmCli && looksLikeBrokenShim(primary.exitCode, primary.output)) {
49
+ const fallback = await runNpm(executor, args, cwd, 'bundled', npmCli);
50
+ return {
51
+ ...fallback,
52
+ output: `[plugins] npm shim failed (${primary.error ?? 'exit ' + primary.exitCode}); ` +
53
+ `retried via bundled npm (${npmCli}).\n${fallback.output}`,
54
+ };
55
+ }
56
+ return primary;
57
+ }
58
+ /**
59
+ * Spawn one npm invocation and collect its buffered result.
60
+ *
61
+ * `mode: 'shim'` runs the PATH-resolved `npm` (shell on Windows for `.cmd`).
62
+ * `mode: 'bundled'` runs `node <npmCliPath> ...` directly, bypassing shims.
63
+ *
64
+ * Direct copy of updater.ts:runNpm with cwd threaded through. Keeping the two
65
+ * in lockstep means platform fixes (DEP0190, broken-shim detection) apply to
66
+ * both — diverging would let one rot while the other gets fixed.
67
+ */
68
+ function runNpm(executor, args, cwd, mode, npmCliPath) {
69
+ return new Promise((resolve) => {
70
+ let stdout = '';
71
+ let stderr = '';
72
+ const stdio = ['ignore', 'pipe', 'pipe'];
73
+ const child = mode === 'bundled' && npmCliPath
74
+ ? executor(process.execPath, [npmCliPath, ...args], { stdio, cwd })
75
+ : process.platform === 'win32'
76
+ ? executor(buildCmdLine('npm', args), { stdio, shell: true, cwd })
77
+ : executor('npm', args, { stdio, cwd });
78
+ child.stdout?.on('data', (chunk) => {
79
+ stdout += chunk.toString();
80
+ });
81
+ child.stderr?.on('data', (chunk) => {
82
+ stderr += chunk.toString();
83
+ });
84
+ child.on('error', (err) => {
85
+ resolve({
86
+ ok: false,
87
+ output: stdout + stderr,
88
+ error: err.message,
89
+ exitCode: null,
90
+ });
91
+ });
92
+ child.on('close', (code) => {
93
+ const ok = code === 0;
94
+ resolve({
95
+ ok,
96
+ output: stdout + stderr,
97
+ exitCode: code,
98
+ error: ok ? undefined : `npm exited with code ${code}`,
99
+ });
100
+ });
101
+ });
102
+ }
103
+ //# sourceMappingURL=installer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"installer.js","sourceRoot":"","sources":["../../../src/cli/plugins/installer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,EAAE,KAAK,EAAqB,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EACL,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,eAAe,CAAC;AAavB;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,IAAgB,EAChB,GAAW,EACX,WAAyB,KAAK;IAE9B,MAAM,SAAS,GAAG,IAAI,CAAC,YAAY,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;IAC/D,MAAM,IAAI,GAAG,CAAC,SAAS,EAAE,SAAS,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;IAErD,mEAAmE;IACnE,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,QAAQ,EAAE,IAAI,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;IAC1D,IAAI,OAAO,CAAC,EAAE;QAAE,OAAO,OAAO,CAAC;IAE/B,uEAAuE;IACvE,qEAAqE;IACrE,MAAM,MAAM,GAAG,oBAAoB,EAAE,CAAC;IACtC,IAAI,MAAM,IAAI,mBAAmB,CAAC,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QACpE,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,QAAQ,EAAE,IAAI,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;QACtE,OAAO;YACL,GAAG,QAAQ;YACX,MAAM,EACJ,8BAA8B,OAAO,CAAC,KAAK,IAAI,OAAO,GAAG,OAAO,CAAC,QAAQ,KAAK;gBAC9E,4BAA4B,MAAM,OAAO,QAAQ,CAAC,MAAM,EAAE;SAC7D,CAAC;IACJ,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;;;;;;GASG;AACH,SAAS,MAAM,CACb,QAAsB,EACtB,IAAuB,EACvB,GAAW,EACX,IAAwB,EACxB,UAAmB;IAEnB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,IAAI,MAAM,GAAG,EAAE,CAAC;QAChB,IAAI,MAAM,GAAG,EAAE,CAAC;QAChB,MAAM,KAAK,GAA+B,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;QAErE,MAAM,KAAK,GACT,IAAI,KAAK,SAAS,IAAI,UAAU;YAC9B,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,UAAU,EAAE,GAAG,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC;YACnE,CAAC,CAAC,OAAO,CAAC,QAAQ,KAAK,OAAO;gBAC5B,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC;gBAClE,CAAC,CAAC,QAAQ,CAAC,KAAK,EAAE,IAAgB,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;QAE1D,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE;YACzC,MAAM,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;QAC7B,CAAC,CAAC,CAAC;QACH,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE;YACzC,MAAM,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;QAC7B,CAAC,CAAC,CAAC;QAEH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;YACxB,OAAO,CAAC;gBACN,EAAE,EAAE,KAAK;gBACT,MAAM,EAAE,MAAM,GAAG,MAAM;gBACvB,KAAK,EAAE,GAAG,CAAC,OAAO;gBAClB,QAAQ,EAAE,IAAI;aACf,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;YACzB,MAAM,EAAE,GAAG,IAAI,KAAK,CAAC,CAAC;YACtB,OAAO,CAAC;gBACN,EAAE;gBACF,MAAM,EAAE,MAAM,GAAG,MAAM;gBACvB,QAAQ,EAAE,IAAI;gBACd,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,wBAAwB,IAAI,EAAE;aACvD,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,96 @@
1
+ /**
2
+ * plugins/prefs — persistence of plugin-installation preferences.
3
+ *
4
+ * Stores the "don't ask me again about plugin X" dismissal so the boot gate
5
+ * doesn't nag users who've already decided. Modeled on providerConfig.ts:
6
+ * - JSON file in ~/.tmp/zelari-code/ alongside provider.json / keys.json
7
+ * - existsSync + JSON.parse + validate, graceful fallback to defaults on
8
+ * corrupt/missing file (a broken prefs file must never block boot)
9
+ * - read-modify-write mutators, mode 0o600 (owner-only) on write
10
+ *
11
+ * Shape:
12
+ * { version: 1, dontAskAgain: { "<pluginId>": true } }
13
+ *
14
+ * `version` is reserved for forward migration — bumping it lets a future
15
+ * release rewrite the schema without a silent data loss.
16
+ *
17
+ * Env override: ZELARI_PLUGINS_PREFS_FILE (tests + CI isolate the file).
18
+ *
19
+ * @see src/cli/providerConfig.ts — the canonical read-modify-write template
20
+ */
21
+ import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'node:fs';
22
+ import path from 'node:path';
23
+ import os from 'node:os';
24
+ const DEFAULTS = {
25
+ version: 1,
26
+ dontAskAgain: {},
27
+ };
28
+ /** Path to the prefs file. Env-overridable for tests. */
29
+ export function getPluginPrefsPath() {
30
+ return process.env.ZELARI_PLUGINS_PREFS_FILE
31
+ ?? path.join(os.homedir(), '.tmp', 'zelari-code', 'plugins.json');
32
+ }
33
+ /** Read prefs, falling back to defaults on missing/corrupt file. Never throws. */
34
+ export function getPluginPrefs() {
35
+ const file = getPluginPrefsPath();
36
+ try {
37
+ if (!existsSync(file))
38
+ return { ...DEFAULTS, dontAskAgain: {} };
39
+ const raw = readFileSync(file, 'utf-8');
40
+ const parsed = JSON.parse(raw);
41
+ if (parsed &&
42
+ typeof parsed === 'object' &&
43
+ parsed.dontAskAgain &&
44
+ typeof parsed.dontAskAgain === 'object') {
45
+ // Sanitize: keep only boolean-true entries with a non-empty id; drop junk.
46
+ const clean = {};
47
+ for (const [k, v] of Object.entries(parsed.dontAskAgain)) {
48
+ if (typeof k === 'string' && k.length > 0 && v === true)
49
+ clean[k] = true;
50
+ }
51
+ return { version: 1, dontAskAgain: clean };
52
+ }
53
+ }
54
+ catch {
55
+ // Corrupt JSON or unreadable — fall through to defaults.
56
+ }
57
+ return { ...DEFAULTS, dontAskAgain: {} };
58
+ }
59
+ function writePluginPrefs(prefs) {
60
+ const file = getPluginPrefsPath();
61
+ mkdirSync(path.dirname(file), { recursive: true });
62
+ writeFileSync(file, JSON.stringify(prefs, null, 2), {
63
+ encoding: 'utf-8',
64
+ mode: 0o600,
65
+ });
66
+ }
67
+ /**
68
+ * Mark a plugin as "don't ask again" (user picked 'Don't ask again' in the
69
+ * boot prompt, or `ZELARI_NO_PLUGIN_PROMPT` style dismissal). Idempotent.
70
+ */
71
+ export function markDontAskAgain(pluginId) {
72
+ try {
73
+ const prefs = getPluginPrefs();
74
+ prefs.dontAskAgain[pluginId] = true;
75
+ writePluginPrefs(prefs);
76
+ }
77
+ catch {
78
+ // A failed write (read-only home, full disk) must never block boot.
79
+ }
80
+ }
81
+ /** Clear the "don't ask again" flag for a plugin (so /plugins can re-offer). */
82
+ export function clearDontAskAgain(pluginId) {
83
+ try {
84
+ const prefs = getPluginPrefs();
85
+ delete prefs.dontAskAgain[pluginId];
86
+ writePluginPrefs(prefs);
87
+ }
88
+ catch {
89
+ // Same fail-safe contract.
90
+ }
91
+ }
92
+ /** Has the user muted this plugin at the boot prompt? */
93
+ export function isMuted(pluginId) {
94
+ return getPluginPrefs().dontAskAgain[pluginId] === true;
95
+ }
96
+ //# sourceMappingURL=prefs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prefs.js","sourceRoot":"","sources":["../../../src/cli/plugins/prefs.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,209 @@
1
+ /**
2
+ * plugins/registry — catalog of optional tool plugins zelari-code can offer
3
+ * to install when missing.
4
+ *
5
+ * A "plugin" here is an OPTIONAL dependency of an edge feature: Playwright
6
+ * powers `browser_check`, typescript-language-server / pyright power the LSP
7
+ * navigation tools, eslint / ruff power the post-edit diagnostics loop. None
8
+ * are required to boot — every one of these features degrades silently when
9
+ * its binary is absent (see browser/driver.ts, lsp/manager.ts,
10
+ * diagnostics/engine.ts). The plugin manager is a DISCOVERY layer on top: it
11
+ * detects absence and offers to install, without changing how the tools
12
+ * register or degrade.
13
+ *
14
+ * The binary names are NOT redeclared here — they're sourced from the
15
+ * existing registries the features already use, so a single source of truth
16
+ * is preserved:
17
+ * - DEFAULT_PROVIDERS (diagnostics/engine.ts) → eslint, ruff
18
+ * - LSP_SERVERS (lsp/servers.ts) → typescript-language-server,
19
+ * pyright-langserver
20
+ * - defaultPlaywrightLoader (browser/driver) → playwright
21
+ *
22
+ * Detection mirrors how each feature actually resolves its binary:
23
+ * - project-local linters (eslint/ruff) → resolveBin() walk of node_modules/.bin
24
+ * - LSP servers → PATH probe via `<bin> --version`
25
+ * (they're global dev tools, conventionally installed once)
26
+ * - Playwright → the same dynamic-import loader the
27
+ * browser_check tool uses, so "installed" means "importable + has chromium"
28
+ *
29
+ * Contract: detect() is async, never throws, returns Promise<boolean>. The
30
+ * caller (PluginGate / doctor / /plugins) treats false as "missing, offer to
31
+ * install" and true as "present, leave alone."
32
+ *
33
+ * @see scripts/postinstall.mjs — required install-time deps (this file is
34
+ * the OPTIONAL complement: tools we recommend but don't mandate)
35
+ */
36
+ import { spawnSync } from 'node:child_process';
37
+ import { resolveBin } from '../diagnostics/engine.js';
38
+ import { defaultPlaywrightLoader } from '../browser/driver.js';
39
+ import { DEFAULT_PROVIDERS } from '../diagnostics/engine.js';
40
+ import { LSP_SERVERS } from '../lsp/servers.js';
41
+ import { isMuted } from './prefs.js';
42
+ // ---------------------------------------------------------------------------
43
+ // Detection primitives — wrap the existing resolution mechanisms.
44
+ // ---------------------------------------------------------------------------
45
+ /**
46
+ * Detect a project-local binary (eslint, ruff). resolveBin walks up to 6
47
+ * parent dirs looking for `node_modules/.bin/<bin>`; on miss it returns the
48
+ * bare name, which we treat as "not found locally". This matches how
49
+ * diagnostics/engine.ts actually resolves the linter at call time.
50
+ */
51
+ function detectLocalBin(bin) {
52
+ return (cwd) => {
53
+ try {
54
+ const resolved = resolveBin(bin, cwd);
55
+ // resolveBin returns the bare name when nothing is found.
56
+ return Promise.resolve(resolved !== bin);
57
+ }
58
+ catch {
59
+ return Promise.resolve(false);
60
+ }
61
+ };
62
+ }
63
+ /**
64
+ * Detect a globally-installed binary (LSP servers). Spawn `<bin> --version`
65
+ * synchronously through the default shell; a non-zero / errored spawn means
66
+ * "not on PATH". This is the pattern prereqChecks.ts uses for node/git/bash,
67
+ * adapted for a generic binary. Synchronous because detection runs at boot
68
+ * gate / doctor time where blocking briefly is acceptable.
69
+ */
70
+ function detectGlobalBin(bin) {
71
+ return () => {
72
+ try {
73
+ // On win32 a bare binary name needs shell:true so .cmd shims resolve;
74
+ // on POSIX a direct spawn is fine.
75
+ const res = spawnSync(bin, ['--version'], {
76
+ stdio: ['ignore', 'pipe', 'ignore'],
77
+ shell: process.platform === 'win32',
78
+ timeout: 4000,
79
+ });
80
+ return Promise.resolve(res.status === 0 || (res.stdout != null && res.stdout.toString().trim().length > 0 && res.error === undefined));
81
+ }
82
+ catch {
83
+ return Promise.resolve(false);
84
+ }
85
+ };
86
+ }
87
+ /** Detect Playwright via the exact loader browser_check uses. */
88
+ async function detectPlaywright() {
89
+ try {
90
+ const mod = await defaultPlaywrightLoader();
91
+ return mod !== null;
92
+ }
93
+ catch {
94
+ return false;
95
+ }
96
+ }
97
+ // ---------------------------------------------------------------------------
98
+ // Plugin catalog.
99
+ //
100
+ // IDs are stable forever (persisted to plugins.json). Derived from the feature
101
+ // registries so the binary names stay in lockstep — if diagnostics/engine.ts
102
+ // renames `eslint` to something else, this catalog follows automatically.
103
+ // ---------------------------------------------------------------------------
104
+ /** The canonical plugin list. Order = display order in prompts + doctor. */
105
+ export const PLUGINS = [
106
+ {
107
+ id: 'eslint',
108
+ label: 'ESLint (diagnostics for JS/TS)',
109
+ npmPackage: 'eslint',
110
+ installScope: 'dev',
111
+ detect: detectLocalBin(binForProvider('eslint')),
112
+ featureGate: 'ZELARI_DIAGNOSTICS',
113
+ description: 'Enables the post-edit diagnostics loop for .js/.jsx/.ts/.tsx/.mjs/.cjs files.',
114
+ },
115
+ {
116
+ id: 'ruff',
117
+ label: 'Ruff (diagnostics for Python)',
118
+ npmPackage: 'ruff',
119
+ installScope: 'dev',
120
+ detect: detectLocalBin(binForProvider('ruff')),
121
+ featureGate: 'ZELARI_DIAGNOSTICS',
122
+ description: 'Enables the post-edit diagnostics loop for .py files.',
123
+ },
124
+ {
125
+ id: 'playwright',
126
+ label: 'Playwright (browser_check tool)',
127
+ npmPackage: 'playwright',
128
+ installScope: 'dev',
129
+ detect: () => detectPlaywright(),
130
+ postInstallHint: 'Then fetch the browser binary: `npx playwright install chromium`',
131
+ featureGate: 'ZELARI_BROWSER',
132
+ description: 'Powers the browser_check tool (URL probing, click/fill/wait, screenshots).',
133
+ },
134
+ {
135
+ id: 'typescript-language-server',
136
+ label: 'typescript-language-server (LSP for TS/JS)',
137
+ npmPackage: 'typescript-language-server',
138
+ installScope: 'global',
139
+ detect: detectGlobalBin(binForLspLanguage('typescript')),
140
+ featureGate: 'ZELARI_LSP',
141
+ description: 'Powers go_to_definition / find_references / hover_type / rename_symbol for TS/JS.',
142
+ },
143
+ {
144
+ id: 'pyright',
145
+ label: 'pyright (LSP for Python)',
146
+ npmPackage: 'pyright',
147
+ installScope: 'global',
148
+ detect: detectGlobalBin(binForLspLanguage('python')),
149
+ featureGate: 'ZELARI_LSP',
150
+ description: 'Powers go_to_definition / find_references / hover_type / rename_symbol for Python.',
151
+ },
152
+ ];
153
+ // ---------------------------------------------------------------------------
154
+ // Small adapters so the catalog above derives binary names from the existing
155
+ // registries rather than hardcoding them (single source of truth).
156
+ // ---------------------------------------------------------------------------
157
+ /** Look up a diagnostic provider's binary name by provider name. */
158
+ function binForProvider(name) {
159
+ const p = DEFAULT_PROVIDERS.find((x) => x.name === name);
160
+ if (!p)
161
+ throw new Error(`plugin registry: unknown diagnostic provider '${name}'`);
162
+ return p.bin;
163
+ }
164
+ /** Look up an LSP server's binary name by language. */
165
+ function binForLspLanguage(language) {
166
+ const s = LSP_SERVERS.find((x) => x.language === language);
167
+ if (!s)
168
+ throw new Error(`plugin registry: unknown LSP language '${language}'`);
169
+ return s.bin;
170
+ }
171
+ // ---------------------------------------------------------------------------
172
+ // Aggregating detector — what the gate / doctor / /plugins call.
173
+ // ---------------------------------------------------------------------------
174
+ /**
175
+ * Detect all plugins that are MISSING, in display order, after applying the
176
+ * two filters that suppress noise:
177
+ * 1. featureGate — if ZELARI_BROWSER=0 etc., the feature is off, so don't
178
+ * prompt to install the tool it needs.
179
+ * 2. dontAskAgain — if the user dismissed this plugin before, respect it.
180
+ * (The `/plugins` command passes `includeMuted: true` to re-surface them.)
181
+ *
182
+ * Never throws. A detect() that rejects is treated as "missing".
183
+ */
184
+ export async function detectMissingPlugins(cwd, opts = {}) {
185
+ const missing = [];
186
+ for (const spec of PLUGINS) {
187
+ // Filter 1: kill-switch. If the feature is disabled, don't offer its tool.
188
+ if (process.env[spec.featureGate] === '0')
189
+ continue;
190
+ // Filter 2: user-muted (unless explicitly re-surfaced via /plugins).
191
+ if (!opts.includeMuted && isMuted(spec.id))
192
+ continue;
193
+ let present = false;
194
+ try {
195
+ present = await spec.detect(cwd);
196
+ }
197
+ catch {
198
+ present = false;
199
+ }
200
+ if (!present)
201
+ missing.push(spec);
202
+ }
203
+ return missing;
204
+ }
205
+ /** Look up a plugin by id (for `/plugins install <id>`). */
206
+ export function findPlugin(id) {
207
+ return PLUGINS.find((p) => p.id === id);
208
+ }
209
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../src/cli/plugins/registry.ts"],"names":[],"mappings":"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"}