codeslick-cli 1.1.3 → 1.1.4
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/bin/codeslick.cjs +5 -0
- package/dist/packages/cli/src/utils/version-check.d.ts +30 -0
- package/dist/packages/cli/src/utils/version-check.d.ts.map +1 -0
- package/dist/packages/cli/src/utils/version-check.js +176 -0
- package/dist/packages/cli/src/utils/version-check.js.map +1 -0
- package/package.json +1 -1
- package/src/utils/version-check.ts +185 -0
package/bin/codeslick.cjs
CHANGED
|
@@ -25,8 +25,13 @@ const { scanCommand } = require('../dist/packages/cli/src/commands/scan');
|
|
|
25
25
|
const { initCommand } = require('../dist/packages/cli/src/commands/init');
|
|
26
26
|
const { configCommand } = require('../dist/packages/cli/src/commands/config');
|
|
27
27
|
const { loginCommand, logoutCommand, whoamiCommand } = require('../dist/packages/cli/src/commands/auth');
|
|
28
|
+
const { startBackgroundUpdateCheck } = require('../dist/packages/cli/src/utils/version-check');
|
|
28
29
|
const { version } = require('../package.json');
|
|
29
30
|
|
|
31
|
+
// Start version check in background (non-blocking)
|
|
32
|
+
// Will print notification at the end if update is available
|
|
33
|
+
void startBackgroundUpdateCheck();
|
|
34
|
+
|
|
30
35
|
// Detect if running as 'cs' or 'codeslick'
|
|
31
36
|
const scriptName = process.argv[1].includes('/cs') ? 'cs' : 'codeslick';
|
|
32
37
|
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Version Check Utility
|
|
3
|
+
*
|
|
4
|
+
* Checks npm registry for newer versions and notifies users.
|
|
5
|
+
* Uses a 24-hour cache to avoid slowing down every command.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Get the currently installed version
|
|
9
|
+
*/
|
|
10
|
+
export declare function getInstalledVersion(): string;
|
|
11
|
+
/**
|
|
12
|
+
* Check for updates and return info if available
|
|
13
|
+
* Uses cache to avoid checking on every command
|
|
14
|
+
*/
|
|
15
|
+
export declare function checkForUpdates(): Promise<{
|
|
16
|
+
hasUpdate: boolean;
|
|
17
|
+
currentVersion: string;
|
|
18
|
+
latestVersion: string;
|
|
19
|
+
} | null>;
|
|
20
|
+
/**
|
|
21
|
+
* Print update notification if a new version is available
|
|
22
|
+
* Non-blocking - runs in background
|
|
23
|
+
*/
|
|
24
|
+
export declare function printUpdateNotification(): Promise<void>;
|
|
25
|
+
/**
|
|
26
|
+
* Start update check in background (non-blocking)
|
|
27
|
+
* Returns a promise that resolves when check is complete
|
|
28
|
+
*/
|
|
29
|
+
export declare function startBackgroundUpdateCheck(): Promise<void>;
|
|
30
|
+
//# sourceMappingURL=version-check.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version-check.d.ts","sourceRoot":"","sources":["../../../../../src/utils/version-check.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAkBH;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,CAO5C;AA6ED;;;GAGG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC;IAC/C,SAAS,EAAE,OAAO,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;CACvB,GAAG,IAAI,CAAC,CAqCR;AAED;;;GAGG;AACH,wBAAsB,uBAAuB,IAAI,OAAO,CAAC,IAAI,CAAC,CAe7D;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,IAAI,OAAO,CAAC,IAAI,CAAC,CAE1D"}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Version Check Utility
|
|
4
|
+
*
|
|
5
|
+
* Checks npm registry for newer versions and notifies users.
|
|
6
|
+
* Uses a 24-hour cache to avoid slowing down every command.
|
|
7
|
+
*/
|
|
8
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
9
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.getInstalledVersion = getInstalledVersion;
|
|
13
|
+
exports.checkForUpdates = checkForUpdates;
|
|
14
|
+
exports.printUpdateNotification = printUpdateNotification;
|
|
15
|
+
exports.startBackgroundUpdateCheck = startBackgroundUpdateCheck;
|
|
16
|
+
const os_1 = require("os");
|
|
17
|
+
const path_1 = require("path");
|
|
18
|
+
const fs_1 = require("fs");
|
|
19
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
20
|
+
const PACKAGE_NAME = 'codeslick-cli';
|
|
21
|
+
const CACHE_FILE = (0, path_1.join)((0, os_1.homedir)(), '.codeslick', 'version-cache.json');
|
|
22
|
+
const CACHE_DURATION_MS = 24 * 60 * 60 * 1000; // 24 hours
|
|
23
|
+
const NPM_REGISTRY_URL = `https://registry.npmjs.org/${PACKAGE_NAME}/latest`;
|
|
24
|
+
const CHECK_TIMEOUT_MS = 3000; // 3 seconds - don't slow down the CLI
|
|
25
|
+
/**
|
|
26
|
+
* Get the currently installed version
|
|
27
|
+
*/
|
|
28
|
+
function getInstalledVersion() {
|
|
29
|
+
try {
|
|
30
|
+
const pkg = require('../../package.json');
|
|
31
|
+
return pkg.version;
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return '0.0.0';
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Compare two semver versions
|
|
39
|
+
* Returns: 1 if a > b, -1 if a < b, 0 if equal
|
|
40
|
+
*/
|
|
41
|
+
function compareVersions(a, b) {
|
|
42
|
+
const partsA = a.split('.').map(Number);
|
|
43
|
+
const partsB = b.split('.').map(Number);
|
|
44
|
+
for (let i = 0; i < 3; i++) {
|
|
45
|
+
const numA = partsA[i] || 0;
|
|
46
|
+
const numB = partsB[i] || 0;
|
|
47
|
+
if (numA > numB)
|
|
48
|
+
return 1;
|
|
49
|
+
if (numA < numB)
|
|
50
|
+
return -1;
|
|
51
|
+
}
|
|
52
|
+
return 0;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Read cached version info
|
|
56
|
+
*/
|
|
57
|
+
function readCache() {
|
|
58
|
+
try {
|
|
59
|
+
if (!(0, fs_1.existsSync)(CACHE_FILE))
|
|
60
|
+
return null;
|
|
61
|
+
const data = JSON.parse((0, fs_1.readFileSync)(CACHE_FILE, 'utf-8'));
|
|
62
|
+
return data;
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Write version info to cache
|
|
70
|
+
*/
|
|
71
|
+
function writeCache(latestVersion) {
|
|
72
|
+
try {
|
|
73
|
+
const cacheDir = (0, path_1.join)((0, os_1.homedir)(), '.codeslick');
|
|
74
|
+
if (!(0, fs_1.existsSync)(cacheDir)) {
|
|
75
|
+
(0, fs_1.mkdirSync)(cacheDir, { recursive: true });
|
|
76
|
+
}
|
|
77
|
+
const cache = {
|
|
78
|
+
latestVersion,
|
|
79
|
+
checkedAt: Date.now(),
|
|
80
|
+
};
|
|
81
|
+
(0, fs_1.writeFileSync)(CACHE_FILE, JSON.stringify(cache, null, 2));
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
// Silently ignore cache write errors
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Fetch latest version from npm registry
|
|
89
|
+
*/
|
|
90
|
+
async function fetchLatestVersion() {
|
|
91
|
+
try {
|
|
92
|
+
const controller = new AbortController();
|
|
93
|
+
const timeoutId = setTimeout(() => controller.abort(), CHECK_TIMEOUT_MS);
|
|
94
|
+
const response = await fetch(NPM_REGISTRY_URL, {
|
|
95
|
+
signal: controller.signal,
|
|
96
|
+
headers: {
|
|
97
|
+
'Accept': 'application/json',
|
|
98
|
+
},
|
|
99
|
+
});
|
|
100
|
+
clearTimeout(timeoutId);
|
|
101
|
+
if (!response.ok)
|
|
102
|
+
return null;
|
|
103
|
+
const data = await response.json();
|
|
104
|
+
return data.version || null;
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Check for updates and return info if available
|
|
112
|
+
* Uses cache to avoid checking on every command
|
|
113
|
+
*/
|
|
114
|
+
async function checkForUpdates() {
|
|
115
|
+
try {
|
|
116
|
+
const currentVersion = getInstalledVersion();
|
|
117
|
+
// Check cache first
|
|
118
|
+
const cache = readCache();
|
|
119
|
+
const now = Date.now();
|
|
120
|
+
let latestVersion = null;
|
|
121
|
+
if (cache && (now - cache.checkedAt) < CACHE_DURATION_MS) {
|
|
122
|
+
// Use cached version
|
|
123
|
+
latestVersion = cache.latestVersion;
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
// Fetch from npm (fire and forget - don't block)
|
|
127
|
+
latestVersion = await fetchLatestVersion();
|
|
128
|
+
if (latestVersion) {
|
|
129
|
+
writeCache(latestVersion);
|
|
130
|
+
}
|
|
131
|
+
else if (cache) {
|
|
132
|
+
// Use stale cache if fetch failed
|
|
133
|
+
latestVersion = cache.latestVersion;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if (!latestVersion)
|
|
137
|
+
return null;
|
|
138
|
+
const hasUpdate = compareVersions(latestVersion, currentVersion) > 0;
|
|
139
|
+
return {
|
|
140
|
+
hasUpdate,
|
|
141
|
+
currentVersion,
|
|
142
|
+
latestVersion,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
catch {
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Print update notification if a new version is available
|
|
151
|
+
* Non-blocking - runs in background
|
|
152
|
+
*/
|
|
153
|
+
async function printUpdateNotification() {
|
|
154
|
+
try {
|
|
155
|
+
const result = await checkForUpdates();
|
|
156
|
+
if (result?.hasUpdate) {
|
|
157
|
+
console.log('');
|
|
158
|
+
console.log(chalk_1.default.cyan('┌─────────────────────────────────────────────────┐'));
|
|
159
|
+
console.log(chalk_1.default.cyan('│') + chalk_1.default.yellow(` Update available: ${result.currentVersion} → ${result.latestVersion}`.padEnd(47)) + chalk_1.default.cyan('│'));
|
|
160
|
+
console.log(chalk_1.default.cyan('│') + chalk_1.default.gray(' Run: ') + chalk_1.default.green('npm install -g codeslick-cli'.padEnd(39)) + chalk_1.default.cyan('│'));
|
|
161
|
+
console.log(chalk_1.default.cyan('└─────────────────────────────────────────────────┘'));
|
|
162
|
+
console.log('');
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
catch {
|
|
166
|
+
// Silently ignore errors - don't disrupt user workflow
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Start update check in background (non-blocking)
|
|
171
|
+
* Returns a promise that resolves when check is complete
|
|
172
|
+
*/
|
|
173
|
+
function startBackgroundUpdateCheck() {
|
|
174
|
+
return printUpdateNotification().catch(() => { });
|
|
175
|
+
}
|
|
176
|
+
//# sourceMappingURL=version-check.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version-check.js","sourceRoot":"","sources":["../../../../../src/utils/version-check.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Version Check Utility
|
|
3
|
+
*
|
|
4
|
+
* Checks npm registry for newer versions and notifies users.
|
|
5
|
+
* Uses a 24-hour cache to avoid slowing down every command.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { homedir } from 'os';
|
|
9
|
+
import { join } from 'path';
|
|
10
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
|
|
11
|
+
import chalk from 'chalk';
|
|
12
|
+
|
|
13
|
+
const PACKAGE_NAME = 'codeslick-cli';
|
|
14
|
+
const CACHE_FILE = join(homedir(), '.codeslick', 'version-cache.json');
|
|
15
|
+
const CACHE_DURATION_MS = 24 * 60 * 60 * 1000; // 24 hours
|
|
16
|
+
const NPM_REGISTRY_URL = `https://registry.npmjs.org/${PACKAGE_NAME}/latest`;
|
|
17
|
+
const CHECK_TIMEOUT_MS = 3000; // 3 seconds - don't slow down the CLI
|
|
18
|
+
|
|
19
|
+
interface VersionCache {
|
|
20
|
+
latestVersion: string;
|
|
21
|
+
checkedAt: number;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Get the currently installed version
|
|
26
|
+
*/
|
|
27
|
+
export function getInstalledVersion(): string {
|
|
28
|
+
try {
|
|
29
|
+
const pkg = require('../../package.json');
|
|
30
|
+
return pkg.version;
|
|
31
|
+
} catch {
|
|
32
|
+
return '0.0.0';
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Compare two semver versions
|
|
38
|
+
* Returns: 1 if a > b, -1 if a < b, 0 if equal
|
|
39
|
+
*/
|
|
40
|
+
function compareVersions(a: string, b: string): number {
|
|
41
|
+
const partsA = a.split('.').map(Number);
|
|
42
|
+
const partsB = b.split('.').map(Number);
|
|
43
|
+
|
|
44
|
+
for (let i = 0; i < 3; i++) {
|
|
45
|
+
const numA = partsA[i] || 0;
|
|
46
|
+
const numB = partsB[i] || 0;
|
|
47
|
+
if (numA > numB) return 1;
|
|
48
|
+
if (numA < numB) return -1;
|
|
49
|
+
}
|
|
50
|
+
return 0;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Read cached version info
|
|
55
|
+
*/
|
|
56
|
+
function readCache(): VersionCache | null {
|
|
57
|
+
try {
|
|
58
|
+
if (!existsSync(CACHE_FILE)) return null;
|
|
59
|
+
const data = JSON.parse(readFileSync(CACHE_FILE, 'utf-8'));
|
|
60
|
+
return data as VersionCache;
|
|
61
|
+
} catch {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Write version info to cache
|
|
68
|
+
*/
|
|
69
|
+
function writeCache(latestVersion: string): void {
|
|
70
|
+
try {
|
|
71
|
+
const cacheDir = join(homedir(), '.codeslick');
|
|
72
|
+
if (!existsSync(cacheDir)) {
|
|
73
|
+
mkdirSync(cacheDir, { recursive: true });
|
|
74
|
+
}
|
|
75
|
+
const cache: VersionCache = {
|
|
76
|
+
latestVersion,
|
|
77
|
+
checkedAt: Date.now(),
|
|
78
|
+
};
|
|
79
|
+
writeFileSync(CACHE_FILE, JSON.stringify(cache, null, 2));
|
|
80
|
+
} catch {
|
|
81
|
+
// Silently ignore cache write errors
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Fetch latest version from npm registry
|
|
87
|
+
*/
|
|
88
|
+
async function fetchLatestVersion(): Promise<string | null> {
|
|
89
|
+
try {
|
|
90
|
+
const controller = new AbortController();
|
|
91
|
+
const timeoutId = setTimeout(() => controller.abort(), CHECK_TIMEOUT_MS);
|
|
92
|
+
|
|
93
|
+
const response = await fetch(NPM_REGISTRY_URL, {
|
|
94
|
+
signal: controller.signal,
|
|
95
|
+
headers: {
|
|
96
|
+
'Accept': 'application/json',
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
clearTimeout(timeoutId);
|
|
101
|
+
|
|
102
|
+
if (!response.ok) return null;
|
|
103
|
+
|
|
104
|
+
const data = await response.json() as { version?: string };
|
|
105
|
+
return data.version || null;
|
|
106
|
+
} catch {
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Check for updates and return info if available
|
|
113
|
+
* Uses cache to avoid checking on every command
|
|
114
|
+
*/
|
|
115
|
+
export async function checkForUpdates(): Promise<{
|
|
116
|
+
hasUpdate: boolean;
|
|
117
|
+
currentVersion: string;
|
|
118
|
+
latestVersion: string;
|
|
119
|
+
} | null> {
|
|
120
|
+
try {
|
|
121
|
+
const currentVersion = getInstalledVersion();
|
|
122
|
+
|
|
123
|
+
// Check cache first
|
|
124
|
+
const cache = readCache();
|
|
125
|
+
const now = Date.now();
|
|
126
|
+
|
|
127
|
+
let latestVersion: string | null = null;
|
|
128
|
+
|
|
129
|
+
if (cache && (now - cache.checkedAt) < CACHE_DURATION_MS) {
|
|
130
|
+
// Use cached version
|
|
131
|
+
latestVersion = cache.latestVersion;
|
|
132
|
+
} else {
|
|
133
|
+
// Fetch from npm (fire and forget - don't block)
|
|
134
|
+
latestVersion = await fetchLatestVersion();
|
|
135
|
+
|
|
136
|
+
if (latestVersion) {
|
|
137
|
+
writeCache(latestVersion);
|
|
138
|
+
} else if (cache) {
|
|
139
|
+
// Use stale cache if fetch failed
|
|
140
|
+
latestVersion = cache.latestVersion;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (!latestVersion) return null;
|
|
145
|
+
|
|
146
|
+
const hasUpdate = compareVersions(latestVersion, currentVersion) > 0;
|
|
147
|
+
|
|
148
|
+
return {
|
|
149
|
+
hasUpdate,
|
|
150
|
+
currentVersion,
|
|
151
|
+
latestVersion,
|
|
152
|
+
};
|
|
153
|
+
} catch {
|
|
154
|
+
return null;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Print update notification if a new version is available
|
|
160
|
+
* Non-blocking - runs in background
|
|
161
|
+
*/
|
|
162
|
+
export async function printUpdateNotification(): Promise<void> {
|
|
163
|
+
try {
|
|
164
|
+
const result = await checkForUpdates();
|
|
165
|
+
|
|
166
|
+
if (result?.hasUpdate) {
|
|
167
|
+
console.log('');
|
|
168
|
+
console.log(chalk.cyan('┌─────────────────────────────────────────────────┐'));
|
|
169
|
+
console.log(chalk.cyan('│') + chalk.yellow(` Update available: ${result.currentVersion} → ${result.latestVersion}`.padEnd(47)) + chalk.cyan('│'));
|
|
170
|
+
console.log(chalk.cyan('│') + chalk.gray(' Run: ') + chalk.green('npm install -g codeslick-cli'.padEnd(39)) + chalk.cyan('│'));
|
|
171
|
+
console.log(chalk.cyan('└─────────────────────────────────────────────────┘'));
|
|
172
|
+
console.log('');
|
|
173
|
+
}
|
|
174
|
+
} catch {
|
|
175
|
+
// Silently ignore errors - don't disrupt user workflow
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Start update check in background (non-blocking)
|
|
181
|
+
* Returns a promise that resolves when check is complete
|
|
182
|
+
*/
|
|
183
|
+
export function startBackgroundUpdateCheck(): Promise<void> {
|
|
184
|
+
return printUpdateNotification().catch(() => {});
|
|
185
|
+
}
|