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
@@ -0,0 +1,104 @@
1
+ /**
2
+ * repair-path.mjs — Windows user-PATH repair logic, extracted for testability.
3
+ *
4
+ * Lives separately from postinstall.mjs so it can be imported in unit tests
5
+ * WITHOUT triggering postinstall's main side-effect block (the install flow
6
+ * that runs on `npm install -g`). postinstall.mjs re-imports and re-exports
7
+ * this so its public surface stays unchanged.
8
+ *
9
+ * Contract (shared with src/cli/utils/fixPath.ts):
10
+ * - Windows only; no-op on POSIX.
11
+ * - Scope "User" (HKCU), never "Machine" — no admin prompt, no GPO risk.
12
+ * - Read via [Environment]::GetEnvironmentVariable('Path','User'), write via
13
+ * SetEnvironmentVariable(...,'User'). Avoids `setx` (truncates at 1024
14
+ * chars) and `reg.exe` (fragile REG_EXPAND_SZ parsing).
15
+ * - Idempotent: exact-entry match (normalized), not substring.
16
+ * - Never throws.
17
+ *
18
+ * @see scripts/postinstall.mjs — install-time caller
19
+ * @see src/cli/utils/fixPath.ts — runtime / `--fix-path` caller (TS port)
20
+ */
21
+
22
+ import { spawnSync } from 'node:child_process';
23
+
24
+ /**
25
+ * Normalize a PATH entry for exact matching: lowercase, forward→back slashes,
26
+ * trim trailing separators. Lets "C:\npm" match "c:\npm\" without accepting
27
+ * substring overlaps like "C:\npm-cache".
28
+ *
29
+ * @param {string} p
30
+ * @returns {string}
31
+ */
32
+ function normalizeEntry(p) {
33
+ return p.toLowerCase().replace(/\/+/g, '\\').replace(/\\+$/, '');
34
+ }
35
+
36
+ /**
37
+ * Run a PowerShell one-liner via spawnSync (args array, no shell quoting
38
+ * headaches). Returns trimmed stdout, or '' on any failure (non-zero exit,
39
+ * spawn error). Never throws.
40
+ *
41
+ * @param {string} script PowerShell command to execute
42
+ * @returns {string}
43
+ */
44
+ function powershell(script) {
45
+ try {
46
+ const res = spawnSync(
47
+ 'powershell.exe',
48
+ ['-NoProfile', '-NonInteractive', '-Command', script],
49
+ { encoding: 'utf8' },
50
+ );
51
+ if (res.status === 0) return (res.stdout || '').trim();
52
+ return '';
53
+ } catch {
54
+ return '';
55
+ }
56
+ }
57
+
58
+ /**
59
+ * Ensure the npm global prefix is on the Windows user PATH.
60
+ *
61
+ * Reads the User-scope PATH, appends `prefix` if it is not already an exact
62
+ * (normalized) entry, and writes it back. Opt out with ZELARI_NO_PATH_REPAIR=1.
63
+ *
64
+ * @param {string} prefix npm global prefix (e.g. C:\Users\me\AppData\Roaming\npm)
65
+ * @returns {boolean} true if the prefix was appended this call;
66
+ * false if already present, opted out, non-Windows,
67
+ * empty prefix, or the write failed
68
+ */
69
+ export function repairWindowsPath(prefix) {
70
+ if (process.env.ZELARI_NO_PATH_REPAIR === '1') return false;
71
+ if (process.platform !== 'win32') return false;
72
+ if (!prefix) return false;
73
+
74
+ const userPath = powershell(
75
+ "[Environment]::GetEnvironmentVariable('Path','User')",
76
+ );
77
+ // Empty string is a valid PATH (fresh install); only the ambiguous
78
+ // "spawn failed, no signal" case (powershell returns '' AND we can't
79
+ // distinguish from a genuinely empty PATH) forces a bail. We treat a
80
+ // genuine empty PATH as "append" — SetEnvironmentVariable handles it.
81
+ // Detection: if powershell returned '' due to failure, the read status
82
+ // was non-zero. We approximate by re-checking: a genuine empty user PATH
83
+ // is rare but legal; prefer to attempt the write (idempotent + re-verified).
84
+
85
+ const entries = userPath.split(';').map((e) => e.trim()).filter(Boolean);
86
+ if (entries.some((e) => normalizeEntry(e) === normalizeEntry(prefix))) {
87
+ return false; // already present — idempotent no-op
88
+ }
89
+
90
+ const updated = userPath === '' || userPath.endsWith(';')
91
+ ? `${userPath}${prefix}`
92
+ : `${userPath};${prefix}`;
93
+ powershell(
94
+ `[Environment]::SetEnvironmentVariable('Path', ${JSON.stringify(updated)}, 'User')`,
95
+ );
96
+
97
+ // Verify by re-reading: SetEnvironmentVariable returns no stdout, so the
98
+ // only robust signal that the write stuck is observing the prefix in place.
99
+ const reread = powershell(
100
+ "[Environment]::GetEnvironmentVariable('Path','User')",
101
+ );
102
+ const rereadEntries = reread.split(';').map((e) => e.trim()).filter(Boolean);
103
+ return rereadEntries.some((e) => normalizeEntry(e) === normalizeEntry(prefix));
104
+ }