@lvnt/release-radar-cli 0.1.1 → 0.2.1
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/downloader.d.ts +2 -0
- package/dist/downloader.js +14 -0
- package/dist/downloader.test.js +7 -1
- package/dist/index.js +38 -12
- package/dist/types.d.ts +13 -1
- package/dist/types.js +7 -1
- package/dist/ui.d.ts +11 -3
- package/dist/ui.js +30 -10
- package/dist/updater.js +8 -3
- package/package.json +1 -1
package/dist/downloader.d.ts
CHANGED
|
@@ -5,3 +5,5 @@ export interface DownloadResult {
|
|
|
5
5
|
error?: string;
|
|
6
6
|
}
|
|
7
7
|
export declare function downloadFile(url: string, downloadDir: string, filename: string, nexusUrl: string): DownloadResult;
|
|
8
|
+
export declare function buildNpmUpdateCommand(packageName: string): string;
|
|
9
|
+
export declare function updateNpmPackage(packageName: string): DownloadResult;
|
package/dist/downloader.js
CHANGED
|
@@ -23,3 +23,17 @@ export function downloadFile(url, downloadDir, filename, nexusUrl) {
|
|
|
23
23
|
return { success: false, error: message };
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
|
+
export function buildNpmUpdateCommand(packageName) {
|
|
27
|
+
return `npm update -g ${packageName}`;
|
|
28
|
+
}
|
|
29
|
+
export function updateNpmPackage(packageName) {
|
|
30
|
+
const command = buildNpmUpdateCommand(packageName);
|
|
31
|
+
try {
|
|
32
|
+
execSync(command, { stdio: 'inherit' });
|
|
33
|
+
return { success: true };
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
37
|
+
return { success: false, error: message };
|
|
38
|
+
}
|
|
39
|
+
}
|
package/dist/downloader.test.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, it, expect } from 'vitest';
|
|
2
|
-
import { buildWgetCommand, replaceNexusUrl } from './downloader.js';
|
|
2
|
+
import { buildWgetCommand, replaceNexusUrl, buildNpmUpdateCommand } from './downloader.js';
|
|
3
3
|
describe('downloader', () => {
|
|
4
4
|
describe('replaceNexusUrl', () => {
|
|
5
5
|
it('replaces {{NEXUS_URL}} placeholder', () => {
|
|
@@ -14,4 +14,10 @@ describe('downloader', () => {
|
|
|
14
14
|
expect(cmd).toBe('wget -O "/downloads/file.zip" "http://nexus.local/file.zip"');
|
|
15
15
|
});
|
|
16
16
|
});
|
|
17
|
+
describe('buildNpmUpdateCommand', () => {
|
|
18
|
+
it('builds correct npm update command', () => {
|
|
19
|
+
const cmd = buildNpmUpdateCommand('ralphy-cli');
|
|
20
|
+
expect(cmd).toBe('npm update -g ralphy-cli');
|
|
21
|
+
});
|
|
22
|
+
});
|
|
17
23
|
});
|
package/dist/index.js
CHANGED
|
@@ -3,13 +3,16 @@ import { ConfigManager } from './config.js';
|
|
|
3
3
|
import { DownloadTracker } from './tracker.js';
|
|
4
4
|
import { loadVersions } from './versions.js';
|
|
5
5
|
import { checkAndUpdate } from './updater.js';
|
|
6
|
-
import { downloadFile } from './downloader.js';
|
|
6
|
+
import { downloadFile, updateNpmPackage } from './downloader.js';
|
|
7
7
|
import { promptSetup, promptToolSelection } from './ui.js';
|
|
8
|
+
import { isNpmTool } from './types.js';
|
|
8
9
|
async function showStatus() {
|
|
9
10
|
const tracker = new DownloadTracker();
|
|
10
11
|
const versions = loadVersions();
|
|
11
12
|
const downloaded = tracker.getAll();
|
|
12
13
|
console.log(chalk.bold('\nTool Status:\n'));
|
|
14
|
+
console.log(chalk.bold(' Tool Latest Downloaded Status Type'));
|
|
15
|
+
console.log(chalk.gray('─'.repeat(70)));
|
|
13
16
|
for (const tool of versions.tools) {
|
|
14
17
|
const record = downloaded[tool.name];
|
|
15
18
|
const downloadedVersion = record?.version ?? '-';
|
|
@@ -23,7 +26,8 @@ async function showStatus() {
|
|
|
23
26
|
else {
|
|
24
27
|
status = chalk.green('✓');
|
|
25
28
|
}
|
|
26
|
-
|
|
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}`);
|
|
27
31
|
}
|
|
28
32
|
console.log('');
|
|
29
33
|
}
|
|
@@ -36,14 +40,17 @@ async function runConfig() {
|
|
|
36
40
|
async function runInteractive() {
|
|
37
41
|
const configManager = new ConfigManager();
|
|
38
42
|
const tracker = new DownloadTracker();
|
|
43
|
+
// Check for updates first (before any prompts) unless --skip-update is passed
|
|
44
|
+
const skipUpdate = process.argv.includes('--skip-update');
|
|
45
|
+
if (!skipUpdate) {
|
|
46
|
+
await checkAndUpdate();
|
|
47
|
+
}
|
|
39
48
|
// First run setup
|
|
40
49
|
if (!configManager.isConfigured()) {
|
|
41
50
|
const config = await promptSetup();
|
|
42
51
|
configManager.save(config);
|
|
43
52
|
console.log(chalk.green('\nConfiguration saved!\n'));
|
|
44
53
|
}
|
|
45
|
-
// Check for updates and restart if needed
|
|
46
|
-
await checkAndUpdate();
|
|
47
54
|
// Load data
|
|
48
55
|
const config = configManager.load();
|
|
49
56
|
const versions = loadVersions();
|
|
@@ -54,23 +61,37 @@ async function runInteractive() {
|
|
|
54
61
|
console.log(chalk.gray('\nNo tools selected. Exiting.'));
|
|
55
62
|
return;
|
|
56
63
|
}
|
|
57
|
-
// Download selected tools
|
|
64
|
+
// Download/update selected tools
|
|
58
65
|
console.log('');
|
|
59
66
|
for (const tool of selected) {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
67
|
+
if (tool.type === 'npm') {
|
|
68
|
+
console.log(chalk.bold(`Updating npm package ${tool.displayName} (${tool.package})...`));
|
|
69
|
+
const result = updateNpmPackage(tool.package);
|
|
70
|
+
if (result.success) {
|
|
71
|
+
tracker.recordDownload(tool.name, tool.version, `npm:${tool.package}`);
|
|
72
|
+
console.log(chalk.green(` Updated ${tool.package} to ${tool.version} ✓\n`));
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
console.log(chalk.red(` Failed: ${result.error}\n`));
|
|
76
|
+
}
|
|
65
77
|
}
|
|
66
78
|
else {
|
|
67
|
-
console.log(chalk.
|
|
79
|
+
console.log(chalk.bold(`Downloading ${tool.displayName} ${tool.version}...`));
|
|
80
|
+
const result = downloadFile(tool.downloadUrl, config.downloadDir, tool.filename, config.nexusUrl);
|
|
81
|
+
if (result.success) {
|
|
82
|
+
tracker.recordDownload(tool.name, tool.version, tool.filename);
|
|
83
|
+
console.log(chalk.green(` Saved to ${config.downloadDir}/${tool.filename} ✓\n`));
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
console.log(chalk.red(` Failed: ${result.error}\n`));
|
|
87
|
+
}
|
|
68
88
|
}
|
|
69
89
|
}
|
|
70
90
|
console.log(chalk.green('Done!'));
|
|
71
91
|
}
|
|
72
92
|
async function main() {
|
|
73
|
-
const
|
|
93
|
+
const args = process.argv.slice(2).filter(arg => !arg.startsWith('--'));
|
|
94
|
+
const command = args[0];
|
|
74
95
|
switch (command) {
|
|
75
96
|
case 'status':
|
|
76
97
|
await showStatus();
|
|
@@ -79,6 +100,11 @@ async function main() {
|
|
|
79
100
|
await runConfig();
|
|
80
101
|
break;
|
|
81
102
|
default:
|
|
103
|
+
// Check if stdin is a TTY for interactive mode
|
|
104
|
+
if (!process.stdin.isTTY) {
|
|
105
|
+
console.error(chalk.red('Error: Interactive mode requires a TTY. Use "status" command for non-interactive use.'));
|
|
106
|
+
process.exit(1);
|
|
107
|
+
}
|
|
82
108
|
await runInteractive();
|
|
83
109
|
break;
|
|
84
110
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,12 +1,24 @@
|
|
|
1
|
-
export interface
|
|
1
|
+
export interface VersionsJsonToolDownload {
|
|
2
2
|
name: string;
|
|
3
3
|
displayName: string;
|
|
4
4
|
version: string;
|
|
5
5
|
publishedAt: string;
|
|
6
|
+
type?: 'download';
|
|
6
7
|
downloadUrl: string;
|
|
7
8
|
filename: string;
|
|
8
9
|
}
|
|
10
|
+
export interface VersionsJsonToolNpm {
|
|
11
|
+
name: string;
|
|
12
|
+
displayName: string;
|
|
13
|
+
version: string;
|
|
14
|
+
publishedAt: string;
|
|
15
|
+
type: 'npm';
|
|
16
|
+
package: string;
|
|
17
|
+
}
|
|
18
|
+
export type VersionsJsonTool = VersionsJsonToolDownload | VersionsJsonToolNpm;
|
|
9
19
|
export interface VersionsJson {
|
|
10
20
|
generatedAt: string;
|
|
11
21
|
tools: VersionsJsonTool[];
|
|
12
22
|
}
|
|
23
|
+
export declare function isNpmTool(tool: VersionsJsonTool): tool is VersionsJsonToolNpm;
|
|
24
|
+
export declare function isDownloadTool(tool: VersionsJsonTool): tool is VersionsJsonToolDownload;
|
package/dist/types.js
CHANGED
package/dist/ui.d.ts
CHANGED
|
@@ -2,14 +2,22 @@ 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
|
-
interface
|
|
5
|
+
interface ToolChoiceBase {
|
|
6
6
|
name: string;
|
|
7
7
|
displayName: string;
|
|
8
8
|
version: string;
|
|
9
|
-
downloadUrl: string;
|
|
10
|
-
filename: string;
|
|
11
9
|
status: 'new' | 'update' | 'current';
|
|
12
10
|
downloadedVersion: string | null;
|
|
13
11
|
}
|
|
12
|
+
interface ToolChoiceDownload extends ToolChoiceBase {
|
|
13
|
+
type: 'download';
|
|
14
|
+
downloadUrl: string;
|
|
15
|
+
filename: string;
|
|
16
|
+
}
|
|
17
|
+
interface ToolChoiceNpm extends ToolChoiceBase {
|
|
18
|
+
type: 'npm';
|
|
19
|
+
package: string;
|
|
20
|
+
}
|
|
21
|
+
export type ToolChoice = ToolChoiceDownload | ToolChoiceNpm;
|
|
14
22
|
export declare function promptToolSelection(tools: VersionsJsonTool[], downloaded: DownloadedState, generatedAt: string): Promise<ToolChoice[]>;
|
|
15
23
|
export {};
|
package/dist/ui.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import inquirer from 'inquirer';
|
|
2
2
|
import chalk from 'chalk';
|
|
3
|
+
import { isNpmTool } from './types.js';
|
|
3
4
|
export async function promptSetup() {
|
|
4
5
|
console.log(chalk.bold('\nWelcome to release-radar-cli!\n'));
|
|
5
6
|
console.log("Let's configure your settings.\n");
|
|
@@ -39,20 +40,38 @@ function getStatus(tool, downloaded) {
|
|
|
39
40
|
}
|
|
40
41
|
return { status: 'current', downloadedVersion: record.version };
|
|
41
42
|
}
|
|
42
|
-
|
|
43
|
-
const
|
|
44
|
-
|
|
43
|
+
function createToolChoice(tool, downloaded) {
|
|
44
|
+
const { status, downloadedVersion } = getStatus(tool, downloaded);
|
|
45
|
+
const base = {
|
|
46
|
+
name: tool.name,
|
|
47
|
+
displayName: tool.displayName,
|
|
48
|
+
version: tool.version,
|
|
49
|
+
status,
|
|
50
|
+
downloadedVersion,
|
|
51
|
+
};
|
|
52
|
+
if (isNpmTool(tool)) {
|
|
45
53
|
return {
|
|
46
|
-
...
|
|
47
|
-
|
|
48
|
-
|
|
54
|
+
...base,
|
|
55
|
+
type: 'npm',
|
|
56
|
+
package: tool.package,
|
|
49
57
|
};
|
|
50
|
-
}
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
return {
|
|
61
|
+
...base,
|
|
62
|
+
type: 'download',
|
|
63
|
+
downloadUrl: tool.downloadUrl,
|
|
64
|
+
filename: tool.filename,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
export async function promptToolSelection(tools, downloaded, generatedAt) {
|
|
69
|
+
const choices = tools.map((tool) => createToolChoice(tool, downloaded));
|
|
51
70
|
console.log(chalk.bold(`\nrelease-radar-cli`));
|
|
52
71
|
console.log(chalk.gray(`Last updated: ${new Date(generatedAt).toLocaleString()}\n`));
|
|
53
72
|
// Display table
|
|
54
|
-
console.log(chalk.bold(' Tool Latest Downloaded Status'));
|
|
55
|
-
console.log(chalk.gray('─'.repeat(
|
|
73
|
+
console.log(chalk.bold(' Tool Latest Downloaded Status Type'));
|
|
74
|
+
console.log(chalk.gray('─'.repeat(70)));
|
|
56
75
|
choices.forEach((choice) => {
|
|
57
76
|
const downloadedStr = choice.downloadedVersion ?? '-';
|
|
58
77
|
let statusStr;
|
|
@@ -67,7 +86,8 @@ export async function promptToolSelection(tools, downloaded, generatedAt) {
|
|
|
67
86
|
statusStr = chalk.green('✓');
|
|
68
87
|
break;
|
|
69
88
|
}
|
|
70
|
-
|
|
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}`);
|
|
71
91
|
});
|
|
72
92
|
console.log('');
|
|
73
93
|
const { selected } = await inquirer.prompt([
|
package/dist/updater.js
CHANGED
|
@@ -13,6 +13,7 @@ function getLatestVersion() {
|
|
|
13
13
|
const result = execSync('npm view @lvnt/release-radar-cli version', {
|
|
14
14
|
encoding: 'utf-8',
|
|
15
15
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
16
|
+
timeout: 10000, // 10 second timeout
|
|
16
17
|
});
|
|
17
18
|
return result.trim();
|
|
18
19
|
}
|
|
@@ -32,11 +33,15 @@ export async function checkAndUpdate() {
|
|
|
32
33
|
}
|
|
33
34
|
console.log(`Updating from ${current} to ${latest}...`);
|
|
34
35
|
try {
|
|
35
|
-
|
|
36
|
-
|
|
36
|
+
// Use pipe instead of inherit to avoid messing with terminal state
|
|
37
|
+
const result = execSync('npm update -g @lvnt/release-radar-cli', {
|
|
38
|
+
encoding: 'utf-8',
|
|
39
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
37
40
|
});
|
|
41
|
+
if (result)
|
|
42
|
+
console.log(result);
|
|
38
43
|
console.log('Update complete. Restarting...\n');
|
|
39
|
-
// Restart self
|
|
44
|
+
// Restart self with a fresh terminal
|
|
40
45
|
const child = spawn(process.argv[0], process.argv.slice(1), {
|
|
41
46
|
detached: true,
|
|
42
47
|
stdio: 'inherit',
|