cli4ai 1.2.1 → 1.2.2
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 +10 -5
- package/dist/commands/browse.js +4 -1
- package/dist/commands/info.js +4 -1
- package/dist/commands/search.js +5 -2
- package/dist/core/config.js +2 -2
- package/package.json +1 -1
package/dist/commands/add.js
CHANGED
|
@@ -4,8 +4,12 @@
|
|
|
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-safe command helpers
|
|
10
|
+
const isWindows = platform() === 'win32';
|
|
11
|
+
const npmCmd = isWindows ? 'npm.cmd' : 'npm';
|
|
12
|
+
const tarCmd = 'tar'; // Windows 10+ has tar built-in
|
|
9
13
|
import { output, outputError, log } from '../lib/cli.js';
|
|
10
14
|
import { loadManifest, tryLoadManifest } from '../core/manifest.js';
|
|
11
15
|
import { ensureCli4aiHome, ensureLocalDir, PACKAGES_DIR, LOCAL_PACKAGES_DIR, loadConfig } from '../core/config.js';
|
|
@@ -98,7 +102,7 @@ async function downloadFromNpm(packageName, targetDir) {
|
|
|
98
102
|
try {
|
|
99
103
|
// Use npm pack to download the tarball - using spawnSync to prevent command injection
|
|
100
104
|
log(`Downloading ${packageName} from npm...`);
|
|
101
|
-
const packResult = spawnSync(
|
|
105
|
+
const packResult = spawnSync(npmCmd, ['pack', packageName, `--pack-destination=${tmpDir}`], {
|
|
102
106
|
stdio: 'pipe',
|
|
103
107
|
cwd: tmpDir,
|
|
104
108
|
encoding: 'utf-8'
|
|
@@ -118,7 +122,7 @@ async function downloadFromNpm(packageName, targetDir) {
|
|
|
118
122
|
// Extract the tarball using spawnSync to prevent command injection
|
|
119
123
|
// Use --strip-components=1 equivalent by extracting to a subdir
|
|
120
124
|
const tarPath = join(tmpDir, tarball);
|
|
121
|
-
const extractResult = spawnSync(
|
|
125
|
+
const extractResult = spawnSync(tarCmd, ['-xzf', tarPath, '-C', tmpDir], {
|
|
122
126
|
stdio: 'pipe',
|
|
123
127
|
encoding: 'utf-8'
|
|
124
128
|
});
|
|
@@ -161,7 +165,8 @@ async function downloadFromNpm(packageName, targetDir) {
|
|
|
161
165
|
*/
|
|
162
166
|
function checkCliTool(name) {
|
|
163
167
|
try {
|
|
164
|
-
const
|
|
168
|
+
const cmd = isWindows ? 'where' : 'which';
|
|
169
|
+
const result = spawnSync(cmd, [name], { stdio: 'pipe' });
|
|
165
170
|
return result.status === 0;
|
|
166
171
|
}
|
|
167
172
|
catch {
|
|
@@ -176,7 +181,7 @@ async function installNpmDependencies(pkgPath, dependencies) {
|
|
|
176
181
|
if (deps.length === 0)
|
|
177
182
|
return;
|
|
178
183
|
log(`Installing npm dependencies: ${deps.join(', ')}`);
|
|
179
|
-
const result = spawnSync(
|
|
184
|
+
const result = spawnSync(npmCmd, ['install', ...deps], {
|
|
180
185
|
cwd: pkgPath,
|
|
181
186
|
stdio: 'inherit'
|
|
182
187
|
});
|
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-safe cli4ai command (npm creates .cmd wrappers on Windows)
|
|
9
|
+
const cli4aiCmd = platform() === 'win32' ? 'cli4ai.cmd' : 'cli4ai';
|
|
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(
|
|
334
|
+
const result = spawnSync(cli4aiCmd, addArgs, { stdio: 'pipe' });
|
|
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-safe npm command
|
|
9
|
+
const npmCmd = platform() === 'win32' ? 'npm.cmd' : 'npm';
|
|
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';
|
|
@@ -62,7 +65,7 @@ export async function infoCommand(packageName, options) {
|
|
|
62
65
|
try {
|
|
63
66
|
log(`Fetching ${scopedName} from npm...`);
|
|
64
67
|
// Use spawnSync with argument array to prevent command injection
|
|
65
|
-
const result = spawnSync(
|
|
68
|
+
const result = spawnSync(npmCmd, ['view', scopedName, '--json'], {
|
|
66
69
|
encoding: 'utf-8',
|
|
67
70
|
timeout: 10000,
|
|
68
71
|
stdio: ['pipe', 'pipe', 'pipe']
|
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-safe npm command
|
|
10
|
+
const npmCmd = platform() === 'win32' ? 'npm.cmd' : 'npm';
|
|
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';
|
|
@@ -94,7 +97,7 @@ export async function searchCommand(query, options) {
|
|
|
94
97
|
try {
|
|
95
98
|
log(`Searching npm for @cli4ai packages...`);
|
|
96
99
|
// Use spawnSync with argument array to prevent command injection
|
|
97
|
-
const searchResult = spawnSync(
|
|
100
|
+
const searchResult = spawnSync(npmCmd, ['search', `@cli4ai/${query}`, '--json'], {
|
|
98
101
|
encoding: 'utf-8',
|
|
99
102
|
timeout: 10000,
|
|
100
103
|
stdio: ['pipe', 'pipe', 'pipe']
|
|
@@ -102,7 +105,7 @@ export async function searchCommand(query, options) {
|
|
|
102
105
|
let npmResults = searchResult.stdout || '';
|
|
103
106
|
// Fallback to searching @cli4ai if specific query fails
|
|
104
107
|
if (!npmResults || npmResults === '[]') {
|
|
105
|
-
const fallbackResult = spawnSync(
|
|
108
|
+
const fallbackResult = spawnSync(npmCmd, ['search', '@cli4ai', '--json'], {
|
|
106
109
|
encoding: 'utf-8',
|
|
107
110
|
timeout: 10000,
|
|
108
111
|
stdio: ['pipe', 'pipe', 'pipe']
|
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) {
|