@agi-cli/install 0.1.33 → 0.1.35

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 +1 -1
  2. package/start.js +182 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agi-cli/install",
3
- "version": "0.1.33",
3
+ "version": "0.1.35",
4
4
  "description": "AI-powered development assistant CLI - npm installer",
5
5
  "author": "ntishxyz",
6
6
  "license": "MIT",
package/start.js CHANGED
@@ -6,6 +6,8 @@ import {
6
6
  chmodSync,
7
7
  mkdirSync,
8
8
  statSync,
9
+ readFileSync,
10
+ appendFileSync,
9
11
  } from 'fs';
10
12
  import { resolve, dirname } from 'path';
11
13
  import { fileURLToPath } from 'url';
@@ -47,6 +49,91 @@ function findBinaryInPath() {
47
49
  return null;
48
50
  }
49
51
 
52
+ function getVersion(binaryPath) {
53
+ try {
54
+ const result = spawnSync(binaryPath, ['--version'], { encoding: 'utf8' });
55
+ if (result.status === 0 && result.stdout) {
56
+ // Extract version number from output (e.g., "agi 1.2.3" -> "1.2.3")
57
+ const match = result.stdout.trim().match(/[\d.]+/);
58
+ return match ? match[0] : null;
59
+ }
60
+ } catch (err) {
61
+ // If we can't get version, return null
62
+ }
63
+ return null;
64
+ }
65
+
66
+ function getLatestVersion() {
67
+ return new Promise((resolve, reject) => {
68
+ const url = `https://api.github.com/repos/${REPO}/releases/latest`;
69
+
70
+ get(
71
+ url,
72
+ {
73
+ headers: {
74
+ 'User-Agent': 'agi-installer',
75
+ },
76
+ },
77
+ (response) => {
78
+ if (response.statusCode === 302 || response.statusCode === 301) {
79
+ // Follow redirect
80
+ get(
81
+ response.headers.location,
82
+ {
83
+ headers: {
84
+ 'User-Agent': 'agi-installer',
85
+ },
86
+ },
87
+ handleResponse,
88
+ );
89
+ } else {
90
+ handleResponse(response);
91
+ }
92
+
93
+ function handleResponse(res) {
94
+ let data = '';
95
+
96
+ res.on('data', (chunk) => {
97
+ data += chunk;
98
+ });
99
+
100
+ res.on('end', () => {
101
+ try {
102
+ const json = JSON.parse(data);
103
+ if (json.tag_name) {
104
+ // Remove 'v' prefix if present (e.g., "v1.2.3" -> "1.2.3")
105
+ const version = json.tag_name.replace(/^v/, '');
106
+ resolve(version);
107
+ } else {
108
+ reject(new Error('No tag_name in response'));
109
+ }
110
+ } catch (err) {
111
+ reject(err);
112
+ }
113
+ });
114
+ }
115
+ },
116
+ ).on('error', reject);
117
+ });
118
+ }
119
+
120
+ function compareVersions(v1, v2) {
121
+ if (!v1 || !v2) return null;
122
+
123
+ const parts1 = v1.split('.').map(Number);
124
+ const parts2 = v2.split('.').map(Number);
125
+
126
+ for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) {
127
+ const part1 = parts1[i] || 0;
128
+ const part2 = parts2[i] || 0;
129
+
130
+ if (part1 > part2) return 1;
131
+ if (part1 < part2) return -1;
132
+ }
133
+
134
+ return 0; // Equal
135
+ }
136
+
50
137
  function getPlatformInfo() {
51
138
  const platformMap = {
52
139
  darwin: 'darwin',
@@ -119,6 +206,49 @@ function downloadWithProgress(url, dest) {
119
206
  });
120
207
  }
121
208
 
209
+ function updateShellProfile(userBin) {
210
+ // Skip on Windows
211
+ if (platform() === 'win32') return;
212
+
213
+ const shell = process.env.SHELL || '';
214
+ let configFile;
215
+ let shellType;
216
+
217
+ if (shell.includes('zsh')) {
218
+ configFile = resolve(homedir(), '.zshrc');
219
+ shellType = 'zsh';
220
+ } else if (shell.includes('bash')) {
221
+ configFile = resolve(homedir(), '.bashrc');
222
+ shellType = 'bash';
223
+ } else {
224
+ configFile = resolve(homedir(), '.profile');
225
+ shellType = 'shell';
226
+ }
227
+
228
+ const pathExport = 'export PATH="$HOME/.local/bin:$PATH"';
229
+
230
+ try {
231
+ let fileContent = '';
232
+ if (existsSync(configFile)) {
233
+ fileContent = readFileSync(configFile, 'utf8');
234
+ }
235
+
236
+ // Check if .local/bin is already in the config file
237
+ if (fileContent.includes('.local/bin')) {
238
+ console.log(`✓ PATH already configured in ${configFile}`);
239
+ return;
240
+ }
241
+
242
+ // Add the PATH export
243
+ appendFileSync(configFile, `\n${pathExport}\n`);
244
+ console.log(`✓ Added ${userBin} to PATH in ${configFile}`);
245
+ console.log(`✓ Restart your ${shellType} or run: source ${configFile}`);
246
+ } catch (error) {
247
+ // Silently fail if we can't update the profile
248
+ console.log(`⚠️ Could not automatically update ${configFile}`);
249
+ }
250
+ }
251
+
122
252
  async function install() {
123
253
  try {
124
254
  const { os, arch: architecture, ext } = getPlatformInfo();
@@ -143,6 +273,7 @@ async function install() {
143
273
 
144
274
  const pathDirs = (process.env.PATH || '').split(':');
145
275
  if (!pathDirs.includes(userBin)) {
276
+ updateShellProfile(userBin);
146
277
  console.log(`\n⚠️ Add ${userBin} to your PATH:`);
147
278
  console.log(
148
279
  ` echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc`,
@@ -150,6 +281,8 @@ async function install() {
150
281
  console.log(
151
282
  ` Or for zsh: echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.zshrc`,
152
283
  );
284
+ } else {
285
+ console.log(`✓ ${userBin} already in PATH`);
153
286
  }
154
287
  } else {
155
288
  console.log(`\n✓ Installed to ${binPath}`);
@@ -165,15 +298,62 @@ async function install() {
165
298
  }
166
299
  }
167
300
 
301
+ async function checkAndUpdateVersion(binaryPath) {
302
+ try {
303
+ const currentVersion = getVersion(binaryPath);
304
+
305
+ if (!currentVersion) {
306
+ console.log('⚠️ Could not determine current version');
307
+ return { needsUpdate: false, binaryPath };
308
+ }
309
+
310
+ console.log(`Current version: ${currentVersion}`);
311
+ console.log('Checking for updates...');
312
+
313
+ const latestVersion = await getLatestVersion();
314
+ console.log(`Latest version: ${latestVersion}`);
315
+
316
+ const comparison = compareVersions(currentVersion, latestVersion);
317
+
318
+ if (comparison < 0) {
319
+ // Current version is older
320
+ console.log(
321
+ `\n🔄 New version available: ${currentVersion} → ${latestVersion}`,
322
+ );
323
+ console.log('Updating...\n');
324
+ const newBinaryPath = await install();
325
+ return { needsUpdate: true, binaryPath: newBinaryPath };
326
+ } else if (comparison > 0) {
327
+ // Current version is newer (dev version?)
328
+ console.log(
329
+ `✓ You have a newer version (${currentVersion}) than the latest release`,
330
+ );
331
+ return { needsUpdate: false, binaryPath };
332
+ } else {
333
+ // Versions match
334
+ console.log('✓ You have the latest version');
335
+ return { needsUpdate: false, binaryPath };
336
+ }
337
+ } catch (error) {
338
+ console.log(`⚠️ Could not check for updates: ${error.message}`);
339
+ return { needsUpdate: false, binaryPath };
340
+ }
341
+ }
342
+
168
343
  async function main() {
169
344
  if (isInWorkspace()) {
170
345
  console.log('Detected workspace environment, skipping install script.');
171
346
  return;
172
347
  }
173
348
 
174
- const binaryPath = findBinaryInPath();
349
+ let binaryPath = findBinaryInPath();
175
350
 
176
351
  if (binaryPath) {
352
+ // Binary exists, check version
353
+ const { needsUpdate, binaryPath: updatedPath } =
354
+ await checkAndUpdateVersion(binaryPath);
355
+ binaryPath = updatedPath;
356
+
177
357
  const child = spawn(binaryPath, process.argv.slice(2), {
178
358
  stdio: 'inherit',
179
359
  });
@@ -182,6 +362,7 @@ async function main() {
182
362
  process.exit(code || 0);
183
363
  });
184
364
  } else {
365
+ // No binary found, install fresh
185
366
  const installedPath = await install();
186
367
 
187
368
  if (process.argv.length > 2) {