cli4ai 1.2.1 → 1.2.3
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/commands/add.js +12 -5
- package/dist/commands/browse.js +4 -1
- package/dist/commands/info.js +5 -1
- package/dist/commands/search.js +7 -2
- package/dist/core/config.js +2 -2
- package/package.json +1 -1
package/dist/commands/add.js
CHANGED
|
@@ -4,8 +4,11 @@
|
|
|
4
4
|
import { existsSync, symlinkSync, mkdirSync, cpSync, rmSync, readdirSync, unlinkSync, lstatSync } from 'fs';
|
|
5
5
|
import { resolve, dirname, join, normalize } from 'path';
|
|
6
6
|
import { createInterface } from 'readline';
|
|
7
|
-
import { tmpdir } from 'os';
|
|
7
|
+
import { tmpdir, platform } from 'os';
|
|
8
8
|
import { spawnSync } from 'child_process';
|
|
9
|
+
// Windows compatibility: use shell: true on Windows to handle .cmd wrappers
|
|
10
|
+
// This is safe because package names are validated with strict regex patterns
|
|
11
|
+
const isWindows = platform() === 'win32';
|
|
9
12
|
import { output, outputError, log } from '../lib/cli.js';
|
|
10
13
|
import { loadManifest, tryLoadManifest } from '../core/manifest.js';
|
|
11
14
|
import { ensureCli4aiHome, ensureLocalDir, PACKAGES_DIR, LOCAL_PACKAGES_DIR, loadConfig } from '../core/config.js';
|
|
@@ -101,7 +104,8 @@ async function downloadFromNpm(packageName, targetDir) {
|
|
|
101
104
|
const packResult = spawnSync('npm', ['pack', packageName, `--pack-destination=${tmpDir}`], {
|
|
102
105
|
stdio: 'pipe',
|
|
103
106
|
cwd: tmpDir,
|
|
104
|
-
encoding: 'utf-8'
|
|
107
|
+
encoding: 'utf-8',
|
|
108
|
+
shell: isWindows // Required on Windows to find npm.cmd
|
|
105
109
|
});
|
|
106
110
|
if (packResult.error) {
|
|
107
111
|
throw new Error(`npm not found or failed to execute: ${packResult.error.message}`);
|
|
@@ -120,7 +124,8 @@ async function downloadFromNpm(packageName, targetDir) {
|
|
|
120
124
|
const tarPath = join(tmpDir, tarball);
|
|
121
125
|
const extractResult = spawnSync('tar', ['-xzf', tarPath, '-C', tmpDir], {
|
|
122
126
|
stdio: 'pipe',
|
|
123
|
-
encoding: 'utf-8'
|
|
127
|
+
encoding: 'utf-8',
|
|
128
|
+
shell: isWindows // Required on Windows
|
|
124
129
|
});
|
|
125
130
|
if (extractResult.status !== 0) {
|
|
126
131
|
throw new Error(`Failed to extract package: ${extractResult.stderr || 'tar extraction failed'}`);
|
|
@@ -161,7 +166,8 @@ async function downloadFromNpm(packageName, targetDir) {
|
|
|
161
166
|
*/
|
|
162
167
|
function checkCliTool(name) {
|
|
163
168
|
try {
|
|
164
|
-
const
|
|
169
|
+
const cmd = isWindows ? 'where' : 'which';
|
|
170
|
+
const result = spawnSync(cmd, [name], { stdio: 'pipe' });
|
|
165
171
|
return result.status === 0;
|
|
166
172
|
}
|
|
167
173
|
catch {
|
|
@@ -178,7 +184,8 @@ async function installNpmDependencies(pkgPath, dependencies) {
|
|
|
178
184
|
log(`Installing npm dependencies: ${deps.join(', ')}`);
|
|
179
185
|
const result = spawnSync('npm', ['install', ...deps], {
|
|
180
186
|
cwd: pkgPath,
|
|
181
|
-
stdio: 'inherit'
|
|
187
|
+
stdio: 'inherit',
|
|
188
|
+
shell: isWindows // Required on Windows to find npm.cmd
|
|
182
189
|
});
|
|
183
190
|
if (result.status !== 0) {
|
|
184
191
|
throw new Error(`Failed to install dependencies (exit code: ${result.status})`);
|
package/dist/commands/browse.js
CHANGED
|
@@ -2,8 +2,11 @@
|
|
|
2
2
|
* cli4ai browse - Interactive package browser
|
|
3
3
|
*/
|
|
4
4
|
import { spawnSync } from 'child_process';
|
|
5
|
+
import { platform } from 'os';
|
|
5
6
|
import { log, outputError } from '../lib/cli.js';
|
|
6
7
|
import { getNpmGlobalPackages, getGlobalPackages, getLocalPackages } from '../core/config.js';
|
|
8
|
+
// Windows compatibility
|
|
9
|
+
const isWindows = platform() === 'win32';
|
|
7
10
|
// ANSI codes
|
|
8
11
|
const RESET = '\x1B[0m';
|
|
9
12
|
const BOLD = '\x1B[1m';
|
|
@@ -328,7 +331,7 @@ async function installPackages(packages, scope) {
|
|
|
328
331
|
if (scopeFlag)
|
|
329
332
|
addArgs.push(scopeFlag);
|
|
330
333
|
addArgs.push('-y');
|
|
331
|
-
const result = spawnSync('cli4ai', addArgs, { stdio: 'pipe' });
|
|
334
|
+
const result = spawnSync('cli4ai', addArgs, { stdio: 'pipe', shell: isWindows });
|
|
332
335
|
clearInterval(spinner);
|
|
333
336
|
if (result.status === 0) {
|
|
334
337
|
process.stderr.write(`\r ${GREEN}✓${RESET} ${BOLD}${shortName}${RESET} installed \n`);
|
package/dist/commands/info.js
CHANGED
|
@@ -3,7 +3,10 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { resolve } from 'path';
|
|
5
5
|
import { spawnSync } from 'child_process';
|
|
6
|
+
import { platform } from 'os';
|
|
6
7
|
import { output, outputError, log } from '../lib/cli.js';
|
|
8
|
+
// Windows compatibility
|
|
9
|
+
const isWindows = platform() === 'win32';
|
|
7
10
|
import { findPackage, loadConfig } from '../core/config.js';
|
|
8
11
|
import { loadManifest, tryLoadManifest } from '../core/manifest.js';
|
|
9
12
|
import { remotePackageInfo, RemoteConnectionError, RemoteApiError } from '../core/remote-client.js';
|
|
@@ -65,7 +68,8 @@ export async function infoCommand(packageName, options) {
|
|
|
65
68
|
const result = spawnSync('npm', ['view', scopedName, '--json'], {
|
|
66
69
|
encoding: 'utf-8',
|
|
67
70
|
timeout: 10000,
|
|
68
|
-
stdio: ['pipe', 'pipe', 'pipe']
|
|
71
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
72
|
+
shell: isWindows // Required on Windows to find npm.cmd
|
|
69
73
|
});
|
|
70
74
|
if (result.status === 0 && result.stdout) {
|
|
71
75
|
const pkg = JSON.parse(result.stdout);
|
package/dist/commands/search.js
CHANGED
|
@@ -4,7 +4,10 @@
|
|
|
4
4
|
import { readdirSync, existsSync } from 'fs';
|
|
5
5
|
import { resolve } from 'path';
|
|
6
6
|
import { spawnSync } from 'child_process';
|
|
7
|
+
import { platform } from 'os';
|
|
7
8
|
import { output, outputError, log } from '../lib/cli.js';
|
|
9
|
+
// Windows compatibility
|
|
10
|
+
const isWindows = platform() === 'win32';
|
|
8
11
|
import { loadConfig, getGlobalPackages, getLocalPackages } from '../core/config.js';
|
|
9
12
|
import { tryLoadManifest } from '../core/manifest.js';
|
|
10
13
|
import { remoteListPackages, RemoteConnectionError, RemoteApiError } from '../core/remote-client.js';
|
|
@@ -97,7 +100,8 @@ export async function searchCommand(query, options) {
|
|
|
97
100
|
const searchResult = spawnSync('npm', ['search', `@cli4ai/${query}`, '--json'], {
|
|
98
101
|
encoding: 'utf-8',
|
|
99
102
|
timeout: 10000,
|
|
100
|
-
stdio: ['pipe', 'pipe', 'pipe']
|
|
103
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
104
|
+
shell: isWindows // Required on Windows to find npm.cmd
|
|
101
105
|
});
|
|
102
106
|
let npmResults = searchResult.stdout || '';
|
|
103
107
|
// Fallback to searching @cli4ai if specific query fails
|
|
@@ -105,7 +109,8 @@ export async function searchCommand(query, options) {
|
|
|
105
109
|
const fallbackResult = spawnSync('npm', ['search', '@cli4ai', '--json'], {
|
|
106
110
|
encoding: 'utf-8',
|
|
107
111
|
timeout: 10000,
|
|
108
|
-
stdio: ['pipe', 'pipe', 'pipe']
|
|
112
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
113
|
+
shell: isWindows // Required on Windows to find npm.cmd
|
|
109
114
|
});
|
|
110
115
|
npmResults = fallbackResult.stdout || '[]';
|
|
111
116
|
}
|
package/dist/core/config.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Global cli4ai configuration (~/.cli4ai/)
|
|
3
3
|
*/
|
|
4
4
|
import { readFileSync, writeFileSync, mkdirSync, existsSync, readdirSync, lstatSync, realpathSync, openSync, closeSync, unlinkSync, renameSync } from 'fs';
|
|
5
|
-
import { resolve, join, normalize } from 'path';
|
|
5
|
+
import { resolve, join, normalize, sep } from 'path';
|
|
6
6
|
import { homedir } from 'os';
|
|
7
7
|
import { outputError, log } from '../lib/cli.js';
|
|
8
8
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
@@ -36,7 +36,7 @@ function validateSymlinkTarget(symlinkPath) {
|
|
|
36
36
|
// Check if the real path is within a safe prefix
|
|
37
37
|
const isSafe = SAFE_SYMLINK_PREFIXES.some(prefix => {
|
|
38
38
|
const normalizedPrefix = normalize(prefix);
|
|
39
|
-
return normalizedRealPath.startsWith(normalizedPrefix +
|
|
39
|
+
return normalizedRealPath.startsWith(normalizedPrefix + sep) ||
|
|
40
40
|
normalizedRealPath === normalizedPrefix;
|
|
41
41
|
});
|
|
42
42
|
if (!isSafe) {
|