codeslick-cli 1.1.3 → 1.1.5
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/README.md +12 -4
- 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/README.md
CHANGED
|
@@ -259,6 +259,7 @@ The `.codeslick.json` file controls how CodeSlick scans your code.
|
|
|
259
259
|
| `autofix` | boolean | `false` | Enable auto-fix (experimental) |
|
|
260
260
|
| `exclude` | string[] | See above | Glob patterns to exclude from scanning |
|
|
261
261
|
| `languages` | string[] | All | Languages to scan: `javascript`, `typescript`, `python`, `java` |
|
|
262
|
+
| `telemetry` | boolean | `true` | Enable anonymous usage analytics |
|
|
262
263
|
|
|
263
264
|
### Severity Thresholds
|
|
264
265
|
|
|
@@ -533,20 +534,27 @@ MIT License - see [LICENSE](../../LICENSE) for details.
|
|
|
533
534
|
- **Issues**: https://github.com/VitorLourenco/codeslick2/issues
|
|
534
535
|
- **Email**: support@codeslick.dev
|
|
535
536
|
|
|
536
|
-
## What's New in v1.
|
|
537
|
+
## What's New in v1.1
|
|
538
|
+
|
|
539
|
+
- **Update Notifications** - CLI notifies you when a new version is available
|
|
540
|
+
- **Anonymous Telemetry** - Usage stats for dashboard analytics (disable with `cs config set telemetry false`)
|
|
541
|
+
- **Improved SSRF Detection** - Internal API routes (`/api/...`) no longer trigger false positives
|
|
542
|
+
- **Fixed Critical Sorting** - CRITICAL issues now correctly appear first in reports
|
|
543
|
+
- **Markdown Reports** - Auto-generates detailed reports for large scans (>20 files or >30 issues)
|
|
544
|
+
|
|
545
|
+
### v1.0 Features
|
|
537
546
|
|
|
538
547
|
- **Staged Files by Default** - Fast pre-commit scans (<1s for most commits)
|
|
539
548
|
- **Quick Mode** - Skip TypeScript type checking with `--quick` for even faster scans
|
|
540
549
|
- **Smart Output** - Only shows CRITICAL and HIGH issues by default (use `--verbose` for all)
|
|
541
|
-
- **Markdown Reports** - Auto-generates detailed reports for large scans (>20 files or >30 issues)
|
|
542
550
|
- **268 Security Checks** - OWASP Top 10:2025 compliant
|
|
543
551
|
|
|
544
552
|
## Roadmap
|
|
545
553
|
|
|
546
|
-
### v1.
|
|
547
|
-
- Auto-fix support (--fix flag)
|
|
554
|
+
### v1.2 (Coming Soon)
|
|
548
555
|
- Custom rule configuration
|
|
549
556
|
- IDE integration (VS Code extension)
|
|
557
|
+
- Enhanced auto-fix support
|
|
550
558
|
|
|
551
559
|
---
|
|
552
560
|
|
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
|
+
}
|