buddy-workbench 0.1.39 → 0.1.40

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "buddy-workbench",
3
- "version": "0.1.39",
3
+ "version": "0.1.40",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,5 +1,5 @@
1
1
  import { execFile } from 'node:child_process';
2
- import { existsSync, readFileSync, writeFileSync } from 'node:fs';
2
+ import { existsSync, readFileSync, readdirSync, writeFileSync } from 'node:fs';
3
3
  import { homedir } from 'node:os';
4
4
  import { basename, join } from 'node:path';
5
5
  import { promisify } from 'node:util';
@@ -8,15 +8,72 @@ const execFileAsync = promisify(execFile);
8
8
  const NPM_KEYS = ['prefix', 'registry', 'strict-ssl', 'cache', 'proxy', 'https-proxy'];
9
9
  const NVM_LOAD = 'if [ -s "$NVM_DIR/nvm.sh" ]; then . "$NVM_DIR/nvm.sh"; elif [ -s "$HOME/.nvm/nvm.sh" ]; then . "$HOME/.nvm/nvm.sh"; fi; ';
10
10
 
11
- async function run(command, args) {
12
- const { stdout } = await execFileAsync(command, args, { timeout: 5000, maxBuffer: 1024 * 1024 });
13
- return stdout.trim();
11
+ function getEnrichedEnv() {
12
+ const home = homedir();
13
+ const extraPaths = [
14
+ join(home, '.nvm', 'current', 'bin'),
15
+ join(home, '.npm-global', 'bin'),
16
+ '/opt/homebrew/bin',
17
+ '/usr/local/bin',
18
+ '/usr/bin',
19
+ '/bin',
20
+ '/usr/sbin',
21
+ '/sbin'
22
+ ];
23
+ const nvmDir = process.env.NVM_DIR || join(home, '.nvm');
24
+ if (existsSync(nvmDir)) {
25
+ try {
26
+ const versionsDir = join(nvmDir, 'versions', 'node');
27
+ if (existsSync(versionsDir)) {
28
+ for (const v of readdirSync(versionsDir)) {
29
+ extraPaths.unshift(join(versionsDir, v, 'bin'));
30
+ }
31
+ }
32
+ } catch {}
33
+ }
34
+ const currentPath = process.env.PATH || '';
35
+ const mergedPath = [...new Set([...extraPaths, ...currentPath.split(':')])].filter(Boolean).join(':');
36
+ return { ...process.env, PATH: mergedPath };
37
+ }
38
+
39
+ function parseJsonOutput(text) {
40
+ const str = String(text || '').trim();
41
+ const objStart = str.indexOf('{');
42
+ const arrStart = str.indexOf('[');
43
+ let start = -1;
44
+ let end = -1;
45
+ if (objStart !== -1 && (arrStart === -1 || objStart < arrStart)) {
46
+ start = objStart;
47
+ end = str.lastIndexOf('}');
48
+ } else if (arrStart !== -1) {
49
+ start = arrStart;
50
+ end = str.lastIndexOf(']');
51
+ }
52
+ if (start !== -1 && end !== -1 && end > start) {
53
+ return JSON.parse(str.slice(start, end + 1));
54
+ }
55
+ return JSON.parse(str);
56
+ }
57
+
58
+ async function run(command, args, timeout = 5000) {
59
+ try {
60
+ const { stdout } = await execFileAsync(command, args, { timeout, maxBuffer: 8 * 1024 * 1024, env: getEnrichedEnv() });
61
+ return stdout.trim();
62
+ } catch (error) {
63
+ if (['node', 'npm'].includes(command)) {
64
+ try {
65
+ const cmdStr = `${command} ${args.map(shellQuote).join(' ')}`;
66
+ return await runNvm(cmdStr, timeout);
67
+ } catch {}
68
+ }
69
+ throw error;
70
+ }
14
71
  }
15
72
 
16
73
  async function runNvm(script, timeout = 5000) {
17
74
  for (const shell of ['zsh', 'bash']) {
18
75
  try {
19
- const { stdout } = await execFileAsync(shell, ['-ilc', `${NVM_LOAD}${script}`], { timeout, maxBuffer: 2 * 1024 * 1024 });
76
+ const { stdout } = await execFileAsync(shell, ['-ilc', `${NVM_LOAD}${script}`], { timeout, maxBuffer: 4 * 1024 * 1024, env: getEnrichedEnv() });
20
77
  return stdout.trim();
21
78
  } catch {}
22
79
  }
@@ -61,14 +118,20 @@ async function readGitConfig(key) {
61
118
 
62
119
  async function readGlobalNpmPackages() {
63
120
  try {
64
- const { stdout } = await execFileAsync('npm', ['ls', '--global', '--depth=0', '--json'], { timeout: 10000, maxBuffer: 4 * 1024 * 1024 });
65
- const packageJson = JSON.parse(stdout);
121
+ const stdout = await run('npm', ['ls', '--global', '--depth=0', '--json'], 10000);
122
+ const packageJson = parseJsonOutput(stdout);
66
123
  return Object.entries(packageJson.dependencies || {}).map(([name, info]) => ({ name, version: info.version || '' }));
67
124
  } catch (error) {
68
125
  try {
69
- const packageJson = JSON.parse(error.stdout || '');
126
+ const packageJson = parseJsonOutput(error.stdout || '');
70
127
  return Object.entries(packageJson.dependencies || {}).map(([name, info]) => ({ name, version: info.version || '' }));
71
- } catch { return []; }
128
+ } catch {
129
+ try {
130
+ const output = await runNvm('npm ls --global --depth=0 --json', 10000);
131
+ const packageJson = parseJsonOutput(output);
132
+ return Object.entries(packageJson.dependencies || {}).map(([name, info]) => ({ name, version: info.version || '' }));
133
+ } catch { return []; }
134
+ }
72
135
  }
73
136
  }
74
137
 
@@ -86,15 +149,15 @@ export async function manageGlobalNpmPackage(action, packageName) {
86
149
  ? ['update', '--global', name]
87
150
  : ['uninstall', '--global', name];
88
151
  if (!['install', 'upgrade', 'uninstall'].includes(action)) throw new Error('Unsupported npm package action.');
89
- await execFileAsync('npm', args, { timeout: 10 * 60 * 1000, maxBuffer: 4 * 1024 * 1024 });
152
+ await run('npm', args, 10 * 60 * 1000);
90
153
  return readGlobalNpmPackages();
91
154
  }
92
155
 
93
156
  export async function searchNpmPackages(query) {
94
157
  const term = String(query || '').trim();
95
158
  if (!term || term.length > 100) throw new Error('Enter a package search term.');
96
- const { stdout } = await execFileAsync('npm', ['search', term, '--json', '--long'], { timeout: 30 * 1000, maxBuffer: 8 * 1024 * 1024 });
97
- const results = JSON.parse(stdout);
159
+ const stdout = await run('npm', ['search', term, '--json', '--long'], 30 * 1000);
160
+ const results = parseJsonOutput(stdout);
98
161
  return (Array.isArray(results) ? results : []).slice(0, 20).map((item) => ({
99
162
  name: item.name,
100
163
  version: item.version || '',
@@ -104,12 +167,12 @@ export async function searchNpmPackages(query) {
104
167
 
105
168
  export async function getNpmPackageVersions(packageName) {
106
169
  const name = validateNpmPackageName(packageName).replace(/@[^@]+$/, '');
107
- const [{ stdout: versionsOutput }, { stdout: timeOutput }] = await Promise.all([
108
- execFileAsync('npm', ['view', name, 'versions', '--json'], { timeout: 30 * 1000, maxBuffer: 4 * 1024 * 1024 }),
109
- execFileAsync('npm', ['view', name, 'time', '--json'], { timeout: 30 * 1000, maxBuffer: 4 * 1024 * 1024 })
170
+ const [versionsOutput, timeOutput] = await Promise.all([
171
+ run('npm', ['view', name, 'versions', '--json'], 30 * 1000),
172
+ run('npm', ['view', name, 'time', '--json'], 30 * 1000)
110
173
  ]);
111
- const versions = JSON.parse(versionsOutput);
112
- const publishTimes = JSON.parse(timeOutput) || {};
174
+ const versions = parseJsonOutput(versionsOutput);
175
+ const publishTimes = parseJsonOutput(timeOutput) || {};
113
176
  return (Array.isArray(versions) ? versions : versions ? [versions] : []).slice(-100).reverse().map((version) => ({ version, publishedAt: publishTimes[version] || '' }));
114
177
  }
115
178
 
@@ -204,3 +267,4 @@ export async function installNvmVersion(version) {
204
267
  await runNvm(`nvm install ${shellQuote(target)}`, 10 * 60 * 1000);
205
268
  return readNvmConfiguration();
206
269
  }
270
+