@lvnt/release-radar-cli 0.2.13 → 0.2.14

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/index.js CHANGED
@@ -1,40 +1,110 @@
1
1
  import chalk from 'chalk';
2
+ import { readFileSync } from 'fs';
3
+ import { fileURLToPath } from 'url';
4
+ import { dirname, join } from 'path';
2
5
  import { ConfigManager } from './config.js';
3
6
  import { DownloadTracker } from './tracker.js';
4
7
  import { loadVersions } from './versions.js';
5
8
  import { checkAndUpdate } from './updater.js';
6
9
  import { downloadFile, updateNpmPackage } from './downloader.js';
7
- import { promptSetup, promptToolSelection } from './ui.js';
10
+ import { promptSetup, promptToolSelection, renderTable } from './ui.js';
8
11
  import { isNpmTool } from './types.js';
12
+ function getVersion() {
13
+ const __dirname = dirname(fileURLToPath(import.meta.url));
14
+ const pkgPath = join(__dirname, '..', 'package.json');
15
+ const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
16
+ return pkg.version;
17
+ }
18
+ function showHelp() {
19
+ const version = getVersion();
20
+ console.log(`
21
+ ${chalk.bold('release-radar-cli')} v${version}
22
+
23
+ ${chalk.bold('USAGE:')}
24
+ release-radar-cli [command] [options]
25
+
26
+ ${chalk.bold('COMMANDS:')}
27
+ ${chalk.cyan('(default)')} Interactive mode - select and download tools
28
+ ${chalk.cyan('status')} Show tool versions and download status
29
+ ${chalk.cyan('config')} Configure or reconfigure settings (Nexus URL, download dir)
30
+ ${chalk.cyan('version')} Show CLI version
31
+ ${chalk.cyan('help')} Show this help message
32
+
33
+ ${chalk.bold('OPTIONS:')}
34
+ ${chalk.cyan('-v, --version')} Show version number
35
+ ${chalk.cyan('-h, --help')} Show help
36
+ ${chalk.cyan('--skip-update')} Skip auto-update check on startup
37
+
38
+ ${chalk.bold('EXAMPLES:')}
39
+ release-radar-cli # Interactive mode
40
+ release-radar-cli status # Show all tool versions
41
+ release-radar-cli config # Reconfigure settings
42
+ release-radar-cli --version # Show version
43
+
44
+ ${chalk.bold('CONFIG LOCATION:')}
45
+ ~/.release-radar-cli/config.json
46
+
47
+ ${chalk.gray('For more info: https://github.com/lvntbkdmr/release-radar')}
48
+ `);
49
+ }
9
50
  async function showStatus() {
10
51
  const tracker = new DownloadTracker();
11
52
  const versions = loadVersions();
12
53
  const downloaded = tracker.getAll();
13
54
  console.log(chalk.bold('\nTool Status:\n'));
14
- console.log(chalk.bold(' Tool Latest Downloaded Status Type'));
15
- console.log(chalk.gray('─'.repeat(70)));
16
- for (const tool of versions.tools) {
55
+ const rows = versions.tools.map(tool => {
17
56
  const record = downloaded[tool.name];
18
- const downloadedVersion = record?.version ?? '-';
19
57
  let status;
20
58
  if (!record) {
21
- status = chalk.blue('NEW');
59
+ status = 'new';
22
60
  }
23
61
  else if (record.version !== tool.version) {
24
- status = chalk.yellow('UPDATE');
62
+ status = 'update';
25
63
  }
26
64
  else {
27
- status = chalk.green('');
65
+ status = 'current';
28
66
  }
29
- const typeStr = isNpmTool(tool) ? chalk.magenta('npm') : chalk.cyan('wget');
30
- console.log(` ${tool.displayName.padEnd(18)} ${tool.version.padEnd(12)} ${downloadedVersion.padEnd(12)} ${status.padEnd(12)} ${typeStr}`);
31
- }
67
+ return {
68
+ displayName: tool.displayName,
69
+ version: tool.version,
70
+ downloadedVersion: record?.version ?? '-',
71
+ status,
72
+ type: isNpmTool(tool) ? 'npm' : 'download',
73
+ };
74
+ });
75
+ renderTable(rows);
32
76
  console.log('');
33
77
  }
34
78
  async function runConfig() {
35
79
  const configManager = new ConfigManager();
36
- const config = await promptSetup();
37
- configManager.save(config);
80
+ // Check if already configured and show current values
81
+ if (configManager.isConfigured()) {
82
+ const current = configManager.load();
83
+ console.log(chalk.bold('\nCurrent configuration:'));
84
+ console.log(` Nexus URL: ${chalk.cyan(current.nexusUrl)}`);
85
+ console.log(` Download dir: ${chalk.cyan(current.downloadDir)}`);
86
+ console.log('');
87
+ const { reconfigure } = await (await import('inquirer')).default.prompt([
88
+ {
89
+ type: 'confirm',
90
+ name: 'reconfigure',
91
+ message: 'Do you want to update these settings?',
92
+ default: false,
93
+ },
94
+ ]);
95
+ if (!reconfigure) {
96
+ console.log(chalk.gray('Configuration unchanged.'));
97
+ return;
98
+ }
99
+ // Prompt with current values as defaults
100
+ const { promptReconfigure } = await import('./ui.js');
101
+ const config = await promptReconfigure(current);
102
+ configManager.save(config);
103
+ }
104
+ else {
105
+ const config = await promptSetup();
106
+ configManager.save(config);
107
+ }
38
108
  console.log(chalk.green('\nConfiguration saved!'));
39
109
  }
40
110
  async function runInteractive() {
@@ -120,9 +190,25 @@ async function runInteractive() {
120
190
  }
121
191
  }
122
192
  async function main() {
123
- const args = process.argv.slice(2).filter(arg => !arg.startsWith('--'));
193
+ const rawArgs = process.argv.slice(2);
194
+ // Handle flags first
195
+ if (rawArgs.includes('-v') || rawArgs.includes('--version')) {
196
+ console.log(getVersion());
197
+ return;
198
+ }
199
+ if (rawArgs.includes('-h') || rawArgs.includes('--help')) {
200
+ showHelp();
201
+ return;
202
+ }
203
+ const args = rawArgs.filter(arg => !arg.startsWith('--') && !arg.startsWith('-'));
124
204
  const command = args[0];
125
205
  switch (command) {
206
+ case 'version':
207
+ console.log(getVersion());
208
+ break;
209
+ case 'help':
210
+ showHelp();
211
+ break;
126
212
  case 'status':
127
213
  await showStatus();
128
214
  break;
package/dist/ui.d.ts CHANGED
@@ -2,6 +2,7 @@ import type { VersionsJsonTool } from './types.js';
2
2
  import type { DownloadedState } from './tracker.js';
3
3
  import type { CliConfig } from './config.js';
4
4
  export declare function promptSetup(): Promise<CliConfig>;
5
+ export declare function promptReconfigure(current: CliConfig): Promise<CliConfig>;
5
6
  interface ToolChoiceBase {
6
7
  name: string;
7
8
  displayName: string;
@@ -19,5 +20,13 @@ interface ToolChoiceNpm extends ToolChoiceBase {
19
20
  package: string;
20
21
  }
21
22
  export type ToolChoice = ToolChoiceDownload | ToolChoiceNpm;
23
+ export interface TableRow {
24
+ displayName: string;
25
+ version: string;
26
+ downloadedVersion: string;
27
+ status: 'new' | 'update' | 'current';
28
+ type: 'npm' | 'download';
29
+ }
30
+ export declare function renderTable(rows: TableRow[]): void;
22
31
  export declare function promptToolSelection(tools: VersionsJsonTool[], downloaded: DownloadedState, generatedAt: string): Promise<ToolChoice[]>;
23
32
  export {};
package/dist/ui.js CHANGED
@@ -30,6 +30,35 @@ export async function promptSetup() {
30
30
  downloadDir: answers.downloadDir.replace('~', process.env.HOME || ''),
31
31
  };
32
32
  }
33
+ export async function promptReconfigure(current) {
34
+ console.log(chalk.bold('\nUpdate your settings:\n'));
35
+ const answers = await inquirer.prompt([
36
+ {
37
+ type: 'input',
38
+ name: 'nexusUrl',
39
+ message: 'Nexus proxy base URL:',
40
+ default: current.nexusUrl,
41
+ validate: (input) => {
42
+ if (!input.trim())
43
+ return 'URL is required';
44
+ if (!input.startsWith('http'))
45
+ return 'URL must start with http:// or https://';
46
+ return true;
47
+ },
48
+ },
49
+ {
50
+ type: 'input',
51
+ name: 'downloadDir',
52
+ message: 'Download directory:',
53
+ default: current.downloadDir,
54
+ validate: (input) => input.trim() ? true : 'Directory is required',
55
+ },
56
+ ]);
57
+ return {
58
+ nexusUrl: answers.nexusUrl.replace(/\/$/, ''),
59
+ downloadDir: answers.downloadDir.replace('~', process.env.HOME || ''),
60
+ };
61
+ }
33
62
  function getStatus(tool, downloaded) {
34
63
  const record = downloaded[tool.name];
35
64
  if (!record) {
@@ -65,17 +94,28 @@ function createToolChoice(tool, downloaded) {
65
94
  };
66
95
  }
67
96
  }
68
- export async function promptToolSelection(tools, downloaded, generatedAt) {
69
- const choices = tools.map((tool) => createToolChoice(tool, downloaded));
70
- console.log(chalk.bold(`\nrelease-radar-cli`));
71
- console.log(chalk.gray(`Last updated: ${new Date(generatedAt).toLocaleString()}\n`));
72
- // Display table
73
- console.log(chalk.bold(' Tool Latest Downloaded Status Type'));
74
- console.log(chalk.gray('─'.repeat(70)));
75
- choices.forEach((choice) => {
76
- const downloadedStr = choice.downloadedVersion ?? '-';
97
+ export function renderTable(rows) {
98
+ // Calculate dynamic column widths
99
+ const colWidths = {
100
+ tool: Math.max(4, ...rows.map(r => r.displayName.length)) + 2,
101
+ latest: Math.max(6, ...rows.map(r => r.version.length)) + 2,
102
+ downloaded: Math.max(10, ...rows.map(r => r.downloadedVersion.length)) + 2,
103
+ status: 8,
104
+ type: 4,
105
+ };
106
+ const totalWidth = colWidths.tool + colWidths.latest + colWidths.downloaded + colWidths.status + colWidths.type + 2;
107
+ // Header
108
+ console.log(chalk.bold(' ' +
109
+ 'Tool'.padEnd(colWidths.tool) +
110
+ 'Latest'.padEnd(colWidths.latest) +
111
+ 'Downloaded'.padEnd(colWidths.downloaded) +
112
+ 'Status'.padEnd(colWidths.status) +
113
+ 'Type'));
114
+ console.log(chalk.gray('─'.repeat(totalWidth)));
115
+ // Rows
116
+ for (const row of rows) {
77
117
  let statusStr;
78
- switch (choice.status) {
118
+ switch (row.status) {
79
119
  case 'new':
80
120
  statusStr = chalk.blue('NEW');
81
121
  break;
@@ -86,9 +126,28 @@ export async function promptToolSelection(tools, downloaded, generatedAt) {
86
126
  statusStr = chalk.green('✓');
87
127
  break;
88
128
  }
89
- const typeStr = choice.type === 'npm' ? chalk.magenta('npm') : chalk.cyan('wget');
90
- console.log(` ${choice.displayName.padEnd(18)} ${choice.version.padEnd(12)} ${downloadedStr.padEnd(12)} ${statusStr.padEnd(12)} ${typeStr}`);
91
- });
129
+ const typeStr = row.type === 'npm' ? chalk.magenta('npm') : chalk.cyan('wget');
130
+ console.log(' ' +
131
+ row.displayName.padEnd(colWidths.tool) +
132
+ row.version.padEnd(colWidths.latest) +
133
+ row.downloadedVersion.padEnd(colWidths.downloaded) +
134
+ statusStr.padEnd(colWidths.status + 5) + // +5 for chalk color codes
135
+ typeStr);
136
+ }
137
+ }
138
+ export async function promptToolSelection(tools, downloaded, generatedAt) {
139
+ const choices = tools.map((tool) => createToolChoice(tool, downloaded));
140
+ console.log(chalk.bold(`\nrelease-radar-cli`));
141
+ console.log(chalk.gray(`Last updated: ${new Date(generatedAt).toLocaleString()}\n`));
142
+ // Convert to table rows and display
143
+ const rows = choices.map(choice => ({
144
+ displayName: choice.displayName,
145
+ version: choice.version,
146
+ downloadedVersion: choice.downloadedVersion ?? '-',
147
+ status: choice.status,
148
+ type: choice.type === 'npm' ? 'npm' : 'download',
149
+ }));
150
+ renderTable(rows);
92
151
  console.log('');
93
152
  const { selected } = await inquirer.prompt([
94
153
  {
package/dist/updater.js CHANGED
@@ -1,4 +1,4 @@
1
- import { execSync, spawn } from 'child_process';
1
+ import { execSync } from 'child_process';
2
2
  import { readFileSync } from 'fs';
3
3
  import { fileURLToPath } from 'url';
4
4
  import { dirname, join } from 'path';
@@ -40,13 +40,7 @@ export async function checkAndUpdate() {
40
40
  });
41
41
  if (result)
42
42
  console.log(result);
43
- console.log('Update complete. Restarting...\n');
44
- // Restart self with a fresh terminal
45
- const child = spawn(process.argv[0], process.argv.slice(1), {
46
- detached: true,
47
- stdio: 'inherit',
48
- });
49
- child.unref();
43
+ console.log('Update complete. Please run the command again.\n');
50
44
  process.exit(0);
51
45
  }
52
46
  catch (error) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lvnt/release-radar-cli",
3
- "version": "0.2.13",
3
+ "version": "0.2.14",
4
4
  "description": "Interactive CLI for downloading tools through Nexus proxy",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -16,7 +16,8 @@
16
16
  "files": [
17
17
  "dist",
18
18
  "bin",
19
- "versions.json"
19
+ "versions.json",
20
+ "README.md"
20
21
  ],
21
22
  "keywords": [
22
23
  "release",
@@ -26,6 +27,12 @@
26
27
  ],
27
28
  "author": "lvnt",
28
29
  "license": "ISC",
30
+ "repository": {
31
+ "type": "git",
32
+ "url": "git+https://github.com/lvntbkdmr/release-radar.git",
33
+ "directory": "cli"
34
+ },
35
+ "homepage": "https://github.com/lvntbkdmr/release-radar#readme",
29
36
  "dependencies": {
30
37
  "chalk": "^5.3.0",
31
38
  "inquirer": "^9.2.12"
package/versions.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
- "generatedAt": "2026-01-25T15:40:53.910Z",
2
+ "generatedAt": "2026-01-25T15:43:54.204Z",
3
3
  "tools": [
4
4
  {
5
5
  "name": "Claude Code CLI",
6
6
  "displayName": "Claude Code CLI",
7
7
  "version": "2.1.19",
8
- "publishedAt": "2026-01-25T15:40:53.910Z",
8
+ "publishedAt": "2026-01-25T15:43:54.204Z",
9
9
  "downloadUrl": "{{NEXUS_URL}}/storage.googleapis.com/claude-code-dist-86c565f3-f756-42ad-8dfa-d59b1c096819/claude-code-releases/2.1.19/win32-x64/claude.exe",
10
10
  "filename": "claude-2.1.19.exe"
11
11
  },
@@ -13,7 +13,7 @@
13
13
  "name": "Ninja",
14
14
  "displayName": "Ninja",
15
15
  "version": "1.13.2",
16
- "publishedAt": "2026-01-25T15:40:53.910Z",
16
+ "publishedAt": "2026-01-25T15:43:54.204Z",
17
17
  "downloadUrl": "{{NEXUS_URL}}/github.com/ninja-build/ninja/releases/download/v1.13.2/ninja-win.zip",
18
18
  "filename": "ninja-1.13.2-win.zip"
19
19
  },
@@ -21,7 +21,7 @@
21
21
  "name": "CMake",
22
22
  "displayName": "CMake",
23
23
  "version": "4.2.2",
24
- "publishedAt": "2026-01-25T15:40:53.910Z",
24
+ "publishedAt": "2026-01-25T15:43:54.204Z",
25
25
  "downloadUrl": "{{NEXUS_URL}}/github.com/Kitware/CMake/releases/download/v4.2.2/cmake-4.2.2-windows-x86_64.zip",
26
26
  "filename": "cmake-4.2.2-windows-x86_64.zip"
27
27
  },
@@ -29,7 +29,7 @@
29
29
  "name": "Git",
30
30
  "displayName": "Git for Windows",
31
31
  "version": "2.52.0.windows.1",
32
- "publishedAt": "2026-01-25T15:40:53.910Z",
32
+ "publishedAt": "2026-01-25T15:43:54.204Z",
33
33
  "downloadUrl": "{{NEXUS_URL}}/github.com/git-for-windows/git/releases/download/v2.52.0.windows.1/Git-2.52.0-64-bit.exe",
34
34
  "filename": "Git-2.52.0-64-bit.exe"
35
35
  },
@@ -37,7 +37,7 @@
37
37
  "name": "Clangd",
38
38
  "displayName": "Clangd",
39
39
  "version": "21.1.8",
40
- "publishedAt": "2026-01-25T15:40:53.910Z",
40
+ "publishedAt": "2026-01-25T15:43:54.204Z",
41
41
  "downloadUrl": "{{NEXUS_URL}}/github.com/clangd/clangd/releases/download/21.1.8/clangd-windows-21.1.8.zip",
42
42
  "filename": "clangd-windows-21.1.8.zip"
43
43
  },
@@ -45,7 +45,7 @@
45
45
  "name": "Wezterm",
46
46
  "displayName": "Wezterm",
47
47
  "version": "20240203-110809-5046fc22",
48
- "publishedAt": "2026-01-25T15:40:53.910Z",
48
+ "publishedAt": "2026-01-25T15:43:54.204Z",
49
49
  "downloadUrl": "{{NEXUS_URL}}/github.com/wezterm/wezterm/releases/download/20240203-110809-5046fc22/WezTerm-20240203-110809-5046fc22-setup.exe",
50
50
  "filename": "WezTerm-20240203-110809-5046fc22-setup.exe"
51
51
  },
@@ -53,7 +53,7 @@
53
53
  "name": "Ralphy",
54
54
  "displayName": "Ralphy CLI",
55
55
  "version": "4.5.3",
56
- "publishedAt": "2026-01-25T15:40:53.910Z",
56
+ "publishedAt": "2026-01-25T15:43:54.204Z",
57
57
  "type": "npm",
58
58
  "package": "ralphy-cli"
59
59
  },
@@ -61,7 +61,7 @@
61
61
  "name": "vscode-cpptools",
62
62
  "displayName": "C/C++ Extension",
63
63
  "version": "1.29.3",
64
- "publishedAt": "2026-01-25T15:40:53.910Z",
64
+ "publishedAt": "2026-01-25T15:43:54.204Z",
65
65
  "downloadUrl": "{{NEXUS_URL}}/github.com/microsoft/vscode-cpptools/releases/download/v1.29.3/cpptools-windows-x64.vsix",
66
66
  "filename": "cpptools-windows-x64-1.29.3.vsix"
67
67
  },
@@ -69,7 +69,7 @@
69
69
  "name": "vscode-clangd",
70
70
  "displayName": "clangd Extension",
71
71
  "version": "0.4.0",
72
- "publishedAt": "2026-01-25T15:40:53.910Z",
72
+ "publishedAt": "2026-01-25T15:43:54.204Z",
73
73
  "downloadUrl": "{{NEXUS_URL}}/github.com/clangd/vscode-clangd/releases/download/0.4.0/vscode-clangd-0.4.0.vsix",
74
74
  "filename": "vscode-clangd-0.4.0.vsix"
75
75
  },
@@ -77,7 +77,7 @@
77
77
  "name": "CMake Tools",
78
78
  "displayName": "CMake Tools Extension",
79
79
  "version": "1.21.36",
80
- "publishedAt": "2026-01-25T15:40:53.910Z",
80
+ "publishedAt": "2026-01-25T15:43:54.204Z",
81
81
  "downloadUrl": "{{NEXUS_URL}}/github.com/microsoft/vscode-cmake-tools/releases/download/v1.21.36/cmake-tools.vsix",
82
82
  "filename": "cmake-tools-1.21.36.vsix"
83
83
  },
@@ -85,7 +85,7 @@
85
85
  "name": "Roo Code",
86
86
  "displayName": "Roo Code Extension",
87
87
  "version": "3.43.0",
88
- "publishedAt": "2026-01-25T15:40:53.910Z",
88
+ "publishedAt": "2026-01-25T15:43:54.204Z",
89
89
  "downloadUrl": "{{NEXUS_URL}}/github.com/RooCodeInc/Roo-Code/releases/download/v3.43.0/roo-cline-3.43.0.vsix",
90
90
  "filename": "roo-cline-3.43.0.vsix"
91
91
  },
@@ -93,7 +93,7 @@
93
93
  "name": "Atlascode",
94
94
  "displayName": "Atlassian Extension",
95
95
  "version": "4.0.17",
96
- "publishedAt": "2026-01-25T15:40:53.910Z",
96
+ "publishedAt": "2026-01-25T15:43:54.204Z",
97
97
  "downloadUrl": "{{NEXUS_URL}}/github.com/atlassian/atlascode/releases/download/v4.0.17/atlascode-4.0.17.vsix",
98
98
  "filename": "atlascode-4.0.17.vsix"
99
99
  },
@@ -101,7 +101,7 @@
101
101
  "name": "Zed",
102
102
  "displayName": "Zed",
103
103
  "version": "0.220.6",
104
- "publishedAt": "2026-01-25T15:40:53.910Z",
104
+ "publishedAt": "2026-01-25T15:43:54.204Z",
105
105
  "downloadUrl": "{{NEXUS_URL}}/github.com/zed-industries/zed/releases/download/v0.220.6/Zed-x86_64.exe",
106
106
  "filename": "Zed-0.220.6-x86_64.exe"
107
107
  }