zelari-code 1.4.1 → 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 (37) hide show
  1. package/dist/cli/components/PluginGate.js +195 -0
  2. package/dist/cli/components/PluginGate.js.map +1 -0
  3. package/dist/cli/diagnostics/engine.js +2 -10
  4. package/dist/cli/diagnostics/engine.js.map +1 -1
  5. package/dist/cli/hooks/useSlashDispatch.js +17 -0
  6. package/dist/cli/hooks/useSlashDispatch.js.map +1 -1
  7. package/dist/cli/lsp/tools.js +3 -12
  8. package/dist/cli/lsp/tools.js.map +1 -1
  9. package/dist/cli/main.bundled.js +1141 -545
  10. package/dist/cli/main.bundled.js.map +4 -4
  11. package/dist/cli/main.js +49 -3
  12. package/dist/cli/main.js.map +1 -1
  13. package/dist/cli/plugins/installer.js +103 -0
  14. package/dist/cli/plugins/installer.js.map +1 -0
  15. package/dist/cli/plugins/prefs.js +96 -0
  16. package/dist/cli/plugins/prefs.js.map +1 -0
  17. package/dist/cli/plugins/registry.js +209 -0
  18. package/dist/cli/plugins/registry.js.map +1 -0
  19. package/dist/cli/slashCommands.js +18 -1
  20. package/dist/cli/slashCommands.js.map +1 -1
  21. package/dist/cli/slashHandlers/plugins.js +75 -0
  22. package/dist/cli/slashHandlers/plugins.js.map +1 -0
  23. package/dist/cli/updater.js +1 -1
  24. package/dist/cli/updater.js.map +1 -1
  25. package/dist/cli/utils/doctor.js +43 -4
  26. package/dist/cli/utils/doctor.js.map +1 -1
  27. package/dist/cli/utils/fixPath.js +119 -0
  28. package/dist/cli/utils/fixPath.js.map +1 -0
  29. package/dist/cli/utils/paths.js +47 -0
  30. package/dist/cli/utils/paths.js.map +1 -1
  31. package/package.json +4 -2
  32. package/scripts/diagnose-path.ps1 +22 -0
  33. package/scripts/dump-path.ps1 +13 -0
  34. package/scripts/fix-path.ps1 +26 -0
  35. package/scripts/path-length.ps1 +15 -0
  36. package/scripts/postinstall.mjs +32 -0
  37. 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";
@@ -164,10 +165,45 @@ function pickRootComponent() {
164
165
  // v1.0.3: install-health diagnostic. Runs BEFORE the bundle is loaded
165
166
  // and before any provider / config work, so it works on a broken
166
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).
167
170
  // eslint-disable-next-line @typescript-eslint/no-require-imports
168
171
  const { runDoctor } = require("./utils/doctor.js");
169
- const healthy = runDoctor();
170
- 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);
171
207
  }
172
208
  if (argv.includes("--help") || argv.includes("-h")) {
173
209
  // eslint-disable-next-line no-console
@@ -180,6 +216,8 @@ function pickRootComponent() {
180
216
  " --help, -h Print this help and exit\n" +
181
217
  " --doctor Diagnose install health (shim, bundle, PATH, deps,\n" +
182
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" +
183
221
  " --skip-checks Skip the boot-time prerequisite check\n" +
184
222
  " (alias for ZELARI_SKIP_PREFLIGHT=1)\n" +
185
223
  " --no-wizard Skip the first-run wizard\n" +
@@ -194,6 +232,7 @@ function pickRootComponent() {
194
232
  "Environment:\n" +
195
233
  " ZELARI_NO_WIZARD=1 Skip the first-run wizard\n" +
196
234
  " ZELARI_SKIP_PREFLIGHT=1 Skip the boot prerequisite check\n" +
235
+ " ZELARI_NO_PLUGIN_PROMPT=1 Skip the boot plugin-install prompt\n" +
197
236
  " ANATHEMA_DEV=1 Disable background update check + preflight\n");
198
237
  process.exit(0);
199
238
  }
@@ -224,9 +263,16 @@ function pickRootComponent() {
224
263
  // v0.7.8: one-shot startup splash (ASCII emblem, ~2s or any-key skip),
225
264
  // then the App mounts. Skipped automatically for non-TTY stdout, small
226
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.
227
270
  return {
228
271
  kind: "app",
229
- 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
+ })),
230
276
  };
231
277
  }
232
278
  /**
@@ -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":"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"}
@@ -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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"}
@@ -73,7 +73,7 @@ export function handleSlashCommand(text, availableSkills) {
73
73
  kind: 'help',
74
74
  message: `Available commands:\n /login <provider> — authenticate with provider (grok, minimax, glm, custom)\n /model — pick the active model from a list (auto-discovers, v0.7.10)\n /model <name> — switch the active model directly\n /model show — print the current model\n /models — list discovered models for the active provider (v3-U)\n /models refresh (or /discover) — re-discover models for the active provider\n /provider — pick the active provider from a list (v0.7.10)\n /provider <name> — switch the active provider directly\n /provider custom <baseUrl> — point the active provider at a self-hosted endpoint (Ollama, LM Studio, vLLM, ...)\n /provider custom clear — clear the custom endpoint override\n /skill <name> [input] — invoke a skill (autocomplete with /skill <TAB>)\n /skill-stats [name] — show invocation stats (success rate, avg duration, total tokens)\n /council <input> — invoke the multi-agent council on input\n /zelari <input> — run an autonomous mission (multi-run council until the MVP slice is complete)\n /council-feedback <memberId> <1-5> [note] — rate a council member for future ranking (Task I.2)
75
75
  /promote-member <memberId> — promote a council member to a standalone skill (v3-K)
76
- /update [--yes|-y] — check for zelari-code updates; --yes performs the update (v3-N)\n /steer <text> — enqueue a follow-up prompt on the active run (Task 18.2)\n /steer --interrupt <text> — cancel current run + enqueue <text> for next dispatch (Task C.3.2)\n /compact — compact the session transcript\n /clear — clear the visible transcript (session is preserved)\n /sessions — list past sessions\n /resume <id> — load a past session\n /branch <name> — snapshot the current session into a new branch\n /branches — list branches\n /checkout <name> — switch the active branch\n /new — start a fresh session\n /diff [--staged] — show uncommitted changes (or staged with --staged)\n /undo [--yes] — revert working-tree changes (destructive! requires --yes)\n /checkpoint [label] — snapshot the working tree as a restore point\n /rollback [id|latest] — restore the working tree to a checkpoint (no arg: list)\n /index [status] — build the semantic code index for semantic_search\n /mode [agent|council|zelari] — switch dispatch mode (same as shift+tab; no arg cycles)\n /help — show this help\n /exit — exit the CLI\n\n${formatSkillList(availableSkills)}`,
76
+ /update [--yes|-y] — check for zelari-code updates; --yes performs the update (v3-N)\n /plugins — list optional tool plugins (Playwright, eslint, ruff, LSP servers)\n /plugins install <id> — install a plugin now (e.g. /plugins install eslint)\n /steer <text> — enqueue a follow-up prompt on the active run (Task 18.2)\n /steer --interrupt <text> — cancel current run + enqueue <text> for next dispatch (Task C.3.2)\n /compact — compact the session transcript\n /clear — clear the visible transcript (session is preserved)\n /sessions — list past sessions\n /resume <id> — load a past session\n /branch <name> — snapshot the current session into a new branch\n /branches — list branches\n /checkout <name> — switch the active branch\n /new — start a fresh session\n /diff [--staged] — show uncommitted changes (or staged with --staged)\n /undo [--yes] — revert working-tree changes (destructive! requires --yes)\n /checkpoint [label] — snapshot the working tree as a restore point\n /rollback [id|latest] — restore the working tree to a checkpoint (no arg: list)\n /index [status] — build the semantic code index for semantic_search\n /mode [agent|council|zelari] — switch dispatch mode (same as shift+tab; no arg cycles)\n /help — show this help\n /exit — exit the CLI\n\n${formatSkillList(availableSkills)}`,
77
77
  };
78
78
  case 'exit':
79
79
  return { handled: true, kind: 'exit', message: 'Goodbye.' };
@@ -432,6 +432,23 @@ export function handleSlashCommand(text, availableSkills) {
432
432
  updateForce: force,
433
433
  };
434
434
  }
435
+ case 'plugins': {
436
+ // Usage:
437
+ // /plugins → list all optional plugins (status + install hints)
438
+ // /plugins install <id> → install a specific plugin now
439
+ if (args.length === 0) {
440
+ return { handled: true, kind: 'plugins_list' };
441
+ }
442
+ if (args[0] === 'install' && args[1]) {
443
+ return { handled: true, kind: 'plugins_install', pluginId: args[1] };
444
+ }
445
+ return {
446
+ handled: true,
447
+ kind: 'plugins_usage',
448
+ message: 'Usage: /plugins — list optional tool plugins (Playwright, eslint, ruff, LSP servers)\n' +
449
+ ' /plugins install <id> — install a plugin now (e.g. /plugins install eslint)',
450
+ };
451
+ }
435
452
  case 'undo': {
436
453
  const confirmed = args.includes('--yes') || args.includes('-y');
437
454
  if (confirmed) {