@kandiforge/spectacle 0.45.8 → 0.45.17

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 (2) hide show
  1. package/package.json +2 -2
  2. package/scripts/install.js +137 -17
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kandiforge/spectacle",
3
- "version": "0.45.8",
3
+ "version": "0.45.17",
4
4
  "description": "Spectacle server and CLI tools for KandiForge ecosystem",
5
5
  "author": "Abstract Class Consulting Inc.",
6
6
  "license": "PROPRIETARY",
@@ -21,7 +21,7 @@
21
21
  "development"
22
22
  ],
23
23
  "dependencies": {
24
- "@kandiforge/kandi-cli": "latest"
24
+ "@kandiforge/kandi-cli": "^0.45.7"
25
25
  },
26
26
  "scripts": {
27
27
  "postinstall": "node scripts/install.js",
@@ -6,13 +6,58 @@ const https = require('https');
6
6
  const { execSync } = require('child_process');
7
7
 
8
8
  // This version MUST match package.json
9
- const RELEASE_VERSION = '0.45.8';
9
+ const RELEASE_VERSION = '0.45.17';
10
10
  const GITHUB_REPO = 'KandiForge/distribution';
11
+ const PACKAGE_NAME = '@kandiforge/spectacle';
12
+
13
+ // ANSI color codes
14
+ const colors = {
15
+ reset: '\x1b[0m',
16
+ bold: '\x1b[1m',
17
+ dim: '\x1b[2m',
18
+ cyan: '\x1b[36m',
19
+ green: '\x1b[32m',
20
+ yellow: '\x1b[33m',
21
+ blue: '\x1b[34m',
22
+ magenta: '\x1b[35m',
23
+ };
24
+
25
+ function log(message) {
26
+ console.log(message);
27
+ }
28
+
29
+ function logStep(step, message) {
30
+ log(`${colors.cyan}[${step}]${colors.reset} ${message}`);
31
+ }
32
+
33
+ function logSuccess(message) {
34
+ log(`${colors.green}OK${colors.reset} ${message}`);
35
+ }
36
+
37
+ function logInfo(message) {
38
+ log(`${colors.dim} ${message}${colors.reset}`);
39
+ }
40
+
41
+ function getPlatformName(platform) {
42
+ const names = {
43
+ darwin: 'macOS',
44
+ linux: 'Linux',
45
+ win32: 'Windows',
46
+ };
47
+ return names[platform] || platform;
48
+ }
49
+
50
+ function getArchName(arch) {
51
+ const names = {
52
+ arm64: 'Apple Silicon',
53
+ x64: 'x64',
54
+ ia32: 'x86',
55
+ };
56
+ return names[arch] || arch;
57
+ }
11
58
 
12
59
  function downloadFile(url, destPath) {
13
60
  return new Promise((resolve, reject) => {
14
- console.log(`Downloading from: ${url}`);
15
-
16
61
  https.get(url, (response) => {
17
62
  if (response.statusCode === 302 || response.statusCode === 301) {
18
63
  // Follow redirect
@@ -57,6 +102,15 @@ function extractZip(zipPath, destDir) {
57
102
  async function install() {
58
103
  try {
59
104
  const platform = process.platform;
105
+ const arch = process.arch;
106
+
107
+ // Print installation header
108
+ log('');
109
+ log(`${colors.bold}${colors.cyan}Spectacle${colors.reset} ${colors.dim}v${RELEASE_VERSION}${colors.reset}`);
110
+ log(`${colors.dim}Server and CLI tools for KandiForge ecosystem${colors.reset}`);
111
+ log('');
112
+
113
+ logStep('1/4', `Detecting platform: ${colors.bold}${getPlatformName(platform)}${colors.reset} (${getArchName(arch)})`);
60
114
 
61
115
  // Determine archive name and binary extension based on platform
62
116
  let fileName, isZip, ext;
@@ -101,7 +155,6 @@ async function install() {
101
155
  }
102
156
 
103
157
  // Clean bin directory - remove any existing binaries to avoid mixing platforms
104
- console.log('Cleaning bin directory...');
105
158
  const existingFiles = fs.readdirSync(binDir);
106
159
  for (const file of existingFiles) {
107
160
  // Skip .gitkeep or other dotfiles
@@ -110,20 +163,19 @@ async function install() {
110
163
  try {
111
164
  fs.unlinkSync(filePath);
112
165
  } catch (e) {
113
- console.warn(`Warning: Could not remove ${file}: ${e.message}`);
166
+ // Ignore cleanup errors
114
167
  }
115
168
  }
116
169
 
117
- // Download the release archive
118
- console.log(`Installing Spectacle v${RELEASE_VERSION} for ${platform}...`);
170
+ logStep('2/4', 'Downloading binaries from GitHub releases...');
171
+ logInfo(downloadUrl);
119
172
  await downloadFile(downloadUrl, tempFile);
120
173
 
121
- // Extract the archive
122
- console.log('Extracting binaries...');
174
+ logStep('3/4', 'Extracting binaries...');
123
175
  if (isZip) {
124
176
  extractZip(tempFile, binDir);
125
177
  } else {
126
- execSync(`tar -xzf "${tempFile}" -C "${binDir}"`, { stdio: 'inherit' });
178
+ execSync(`tar -xzf "${tempFile}" -C "${binDir}"`, { stdio: 'pipe' });
127
179
  }
128
180
 
129
181
  // Clean up archive
@@ -148,8 +200,6 @@ async function install() {
148
200
  }
149
201
 
150
202
  installedBinaries.push({ name: baseName, path: destPath });
151
- } else {
152
- console.warn(`Warning: ${srcName} not found in archive`);
153
203
  }
154
204
  }
155
205
 
@@ -162,15 +212,85 @@ async function install() {
162
212
  throw new Error('No binaries were found in the archive');
163
213
  }
164
214
 
165
- console.log('Spectacle installed successfully!');
166
- console.log(`\nInstalled ${installedBinaries.length} binaries:`);
215
+ logStep('4/4', 'Setting up CLI commands...');
216
+
217
+ // Create symlinks in npm global bin directory
218
+ // npm doesn't create symlinks for binaries that don't exist at install time,
219
+ // so we need to create them manually after downloading
220
+ let symlinkSuccess = false;
221
+ try {
222
+ // Get npm prefix and construct bin path (npm bin -g is deprecated)
223
+ const npmPrefix = execSync('npm config get prefix', { encoding: 'utf8' }).trim();
224
+ const npmGlobalBin = path.join(npmPrefix, 'bin');
225
+
226
+ for (const binary of installedBinaries) {
227
+ const binaryName = `${binary.name}${ext}`;
228
+ const sourcePath = binary.path;
229
+ const linkPath = path.join(npmGlobalBin, binaryName);
230
+
231
+ if (fs.existsSync(sourcePath)) {
232
+ // Remove existing symlink if it exists
233
+ try {
234
+ if (fs.existsSync(linkPath) || fs.lstatSync(linkPath).isSymbolicLink()) {
235
+ fs.unlinkSync(linkPath);
236
+ }
237
+ } catch (e) {
238
+ // Ignore if file doesn't exist
239
+ }
240
+
241
+ // Create symlink
242
+ if (platform === 'win32') {
243
+ // On Windows, copy the file instead of symlinking (requires admin for symlinks)
244
+ fs.copyFileSync(sourcePath, linkPath);
245
+ } else {
246
+ fs.symlinkSync(sourcePath, linkPath);
247
+ }
248
+ }
249
+ }
250
+ symlinkSuccess = true;
251
+ } catch (symlinkError) {
252
+ // Symlink creation failed - will show path instructions below
253
+ }
254
+
255
+ // Print success message
256
+ log('');
257
+ log(`${colors.green}Installation complete!${colors.reset}`);
258
+ log('');
259
+ log(`${colors.bold}Installed ${installedBinaries.length} binaries:${colors.reset}`);
167
260
  for (const binary of installedBinaries) {
168
- console.log(` - ${path.basename(binary.path)}`);
261
+ log(` ${colors.cyan}${binary.name}${colors.reset}`);
169
262
  }
170
263
 
264
+ // Print next steps
265
+ log('');
266
+ log(`${colors.bold}Next steps:${colors.reset}`);
267
+ log(` ${colors.dim}1.${colors.reset} Start the Spectacle server:`);
268
+ log(` ${colors.cyan}kandi-spectacle serve${colors.reset}`);
269
+ log('');
270
+ log(` ${colors.dim}2.${colors.reset} Or use individual CLI tools:`);
271
+ log(` ${colors.cyan}kandi-plan --help${colors.reset} ${colors.dim}# Planning and specs${colors.reset}`);
272
+ log(` ${colors.cyan}kandi-gpt --help${colors.reset} ${colors.dim}# GPT integration${colors.reset}`);
273
+ log(` ${colors.cyan}kandi-deploy --help${colors.reset} ${colors.dim}# Deployment automation${colors.reset}`);
274
+ log('');
275
+
276
+ if (!symlinkSuccess) {
277
+ log(`${colors.yellow}Note:${colors.reset} Commands may not be in your PATH.`);
278
+ log(`Add this to your shell profile:`);
279
+ log(` ${colors.dim}export PATH="${binDir}:$PATH"${colors.reset}`);
280
+ log('');
281
+ }
282
+
283
+ log(`${colors.dim}Documentation: https://docs.kandiforge.com${colors.reset}`);
284
+ log('');
285
+
171
286
  } catch (error) {
172
- console.error('Installation failed:', error.message);
173
- console.error('\nPlease report this issue at: https://github.com/KandiForge/apps/issues');
287
+ log('');
288
+ log(`${colors.bold}Installation failed${colors.reset}`);
289
+ log(`${colors.dim}${error.message}${colors.reset}`);
290
+ log('');
291
+ log(`Please report this issue at:`);
292
+ log(`${colors.cyan}https://github.com/KandiForge/apps/issues${colors.reset}`);
293
+ log('');
174
294
  process.exit(1);
175
295
  }
176
296
  }