cskit-cli 1.0.7 → 1.0.9

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": "cskit-cli",
3
- "version": "1.0.7",
3
+ "version": "1.0.9",
4
4
  "description": "Content Suite Kit CLI - Download and manage CSK skills from private repository",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -92,60 +92,69 @@ async function setupPythonEnv(projectDir, spinner) {
92
92
  execSync(`python3 -m venv "${venvPath}"`, { stdio: 'pipe', cwd: libPythonDir });
93
93
  }
94
94
 
95
- // Install requirements with error handling
96
- spinner.text = 'Installing Python packages...';
95
+ // Parse requirements.txt
97
96
  const pipPath = path.join(venvPath, 'bin', 'pip');
97
+ const requirements = fs.readFileSync(requirementsFile, 'utf8')
98
+ .split('\n')
99
+ .map(line => line.trim())
100
+ .filter(line => line && !line.startsWith('#'));
98
101
 
99
- try {
100
- execSync(`"${pipPath}" install -r requirements.txt`, {
101
- stdio: 'pipe',
102
- cwd: libPythonDir
103
- });
104
- spinner.succeed(`Python environment ready (${pythonVersion})`);
102
+ if (requirements.length === 0) {
103
+ spinner.succeed('No packages to install');
105
104
  return { success: true, version: pythonVersion };
106
- } catch (pipError) {
107
- // Extract failed packages from error output
108
- const errorOutput = pipError.stderr ? pipError.stderr.toString() : pipError.message;
109
- const failedPackages = [];
110
-
111
- // Parse error output for specific package failures
112
- const lines = errorOutput.split('\n');
113
- for (const line of lines) {
114
- if (line.includes('No matching distribution') || line.includes('Could not find')) {
115
- const match = line.match(/for\s+(\S+)/);
116
- if (match) failedPackages.push(match[1]);
117
- }
118
- if (line.includes('ERROR:')) {
119
- const pkgMatch = line.match(/ERROR:.*?(\S+>=[\d.]+)/);
120
- if (pkgMatch) failedPackages.push(pkgMatch[1]);
121
- }
122
- }
105
+ }
106
+
107
+ // Upgrade pip first (silent)
108
+ spinner.text = 'Upgrading pip...';
109
+ try {
110
+ execSync(`"${pipPath}" install --upgrade pip -q`, { stdio: 'pipe', cwd: libPythonDir });
111
+ } catch { /* ignore pip upgrade errors */ }
112
+
113
+ // Install packages one by one with progress
114
+ spinner.stop();
115
+ console.log(chalk.dim(`\n Installing ${requirements.length} packages:\n`));
116
+
117
+ const installed = [];
118
+ const failed = [];
119
+
120
+ for (let i = 0; i < requirements.length; i++) {
121
+ const pkg = requirements[i];
122
+ const pkgName = pkg.split(/[>=<\[]/)[0]; // Extract package name
123
+ const progress = `[${i + 1}/${requirements.length}]`;
124
+
125
+ process.stdout.write(` ${chalk.dim(progress)} ${pkgName}... `);
123
126
 
124
- // Try installing without failed packages
125
- spinner.text = 'Retrying with core packages...';
126
127
  try {
127
- execSync(`"${pipPath}" install numpy pandas scipy pydantic rich click -q`, {
128
+ execSync(`"${pipPath}" install "${pkg}" -q`, {
128
129
  stdio: 'pipe',
129
- cwd: libPythonDir
130
+ cwd: libPythonDir,
131
+ timeout: 120000 // 2 min timeout per package
130
132
  });
131
-
132
- // Show specific failures
133
- if (failedPackages.length > 0) {
134
- spinner.warn(`Partial install - failed packages:`);
135
- console.log(chalk.yellow(`\n Failed: ${failedPackages.join(', ')}`));
136
- console.log(chalk.dim(` Run manually: ${pipPath} install <package>\n`));
137
- } else {
138
- spinner.warn('Partial install - some optional packages failed');
139
- console.log(chalk.dim(`\n Error: ${errorOutput.slice(0, 200)}...\n`));
140
- }
141
-
142
- return { success: true, partial: true, version: pythonVersion, failed: failedPackages };
143
- } catch {
144
- spinner.fail('Python setup failed');
145
- console.log(chalk.red(`\n ${errorOutput.slice(0, 500)}\n`));
146
- return { success: false, error: errorOutput.slice(0, 200) };
133
+ console.log(chalk.green('✓'));
134
+ installed.push(pkgName);
135
+ } catch (err) {
136
+ console.log(chalk.red('✗'));
137
+ const errMsg = err.stderr ? err.stderr.toString().split('\n')[0] : err.message;
138
+ console.log(chalk.dim(` ${errMsg.slice(0, 60)}`));
139
+ failed.push(pkgName);
147
140
  }
148
141
  }
142
+
143
+ console.log('');
144
+
145
+ // Summary
146
+ if (failed.length === 0) {
147
+ spinner.succeed(`Python ready: ${installed.length} packages (${pythonVersion})`);
148
+ return { success: true, version: pythonVersion };
149
+ } else if (installed.length > 0) {
150
+ spinner.warn(`Partial: ${installed.length} ok, ${failed.length} failed`);
151
+ console.log(chalk.yellow(` Failed: ${failed.join(', ')}`));
152
+ console.log(chalk.dim(` Run manually: ${pipPath} install <package>\n`));
153
+ return { success: true, partial: true, version: pythonVersion, failed };
154
+ } else {
155
+ spinner.fail('All packages failed');
156
+ return { success: false, error: 'All packages failed to install' };
157
+ }
149
158
  } catch (error) {
150
159
  spinner.warn(`Python setup failed: ${error.message}`);
151
160
  return { success: false, error: error.message };
@@ -241,11 +250,13 @@ async function initCommand(options) {
241
250
  spinner.succeed(`Found ${releases.length} release(s)`);
242
251
  }
243
252
 
244
- // Version selection
253
+ // Version selection (show max 5 recent releases)
245
254
  let selectedVersion = 'main';
255
+ const maxVersions = 5;
246
256
 
247
257
  if (releases.length > 0 && !options.latest) {
248
- const choices = releases.map((r, i) => ({
258
+ const recentReleases = releases.slice(0, maxVersions);
259
+ const choices = recentReleases.map((r, i) => ({
249
260
  name: `${r.tag}${i === 0 ? chalk.green(' (latest)') : ''} - ${formatDate(r.published)}`,
250
261
  value: r.tag
251
262
  }));