antikit 1.2.0 → 1.3.0
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/package.json +1 -1
- package/src/index.js +5 -0
- package/src/utils/updateCheck.js +45 -0
- package/src/utils/updateNotifier.js +113 -0
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -8,10 +8,15 @@ import { listLocalSkills } from './commands/local.js';
|
|
|
8
8
|
import { installSkill } from './commands/install.js';
|
|
9
9
|
import { removeSkill } from './commands/remove.js';
|
|
10
10
|
import { listSources, addNewSource, removeExistingSource, setDefault } from './commands/source.js';
|
|
11
|
+
import { checkForUpdates } from './utils/updateNotifier.js';
|
|
11
12
|
|
|
12
13
|
const require = createRequire(import.meta.url);
|
|
13
14
|
const pkg = require('../package.json');
|
|
14
15
|
|
|
16
|
+
// Check for updates (non-blocking)
|
|
17
|
+
checkForUpdates(pkg.name, pkg.version);
|
|
18
|
+
|
|
19
|
+
|
|
15
20
|
const program = new Command();
|
|
16
21
|
|
|
17
22
|
program
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Background update checker script
|
|
4
|
+
* Spawned by main CLI to fetch version info without blocking
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { existsSync, writeFileSync, mkdirSync } from 'fs';
|
|
8
|
+
import { homedir } from 'os';
|
|
9
|
+
import { join } from 'path';
|
|
10
|
+
|
|
11
|
+
const CONFIG_DIR = join(homedir(), '.antikit');
|
|
12
|
+
const UPDATE_CHECK_FILE = join(CONFIG_DIR, 'update-check.json');
|
|
13
|
+
|
|
14
|
+
const packageName = process.argv[2];
|
|
15
|
+
|
|
16
|
+
if (!packageName) {
|
|
17
|
+
process.exit(1);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
async function fetchAndCache() {
|
|
21
|
+
try {
|
|
22
|
+
const response = await fetch(`https://registry.npmjs.org/${packageName}/latest`, {
|
|
23
|
+
headers: { 'Accept': 'application/json' },
|
|
24
|
+
signal: AbortSignal.timeout(5000)
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
if (!response.ok) process.exit(1);
|
|
28
|
+
|
|
29
|
+
const data = await response.json();
|
|
30
|
+
|
|
31
|
+
if (!existsSync(CONFIG_DIR)) {
|
|
32
|
+
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
writeFileSync(UPDATE_CHECK_FILE, JSON.stringify({
|
|
36
|
+
latestVersion: data.version,
|
|
37
|
+
checkedAt: Date.now()
|
|
38
|
+
}, null, 2));
|
|
39
|
+
|
|
40
|
+
} catch {
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
fetchAndCache();
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from 'fs';
|
|
2
|
+
import { homedir } from 'os';
|
|
3
|
+
import { join, dirname } from 'path';
|
|
4
|
+
import { fileURLToPath } from 'url';
|
|
5
|
+
import { spawn } from 'child_process';
|
|
6
|
+
import chalk from 'chalk';
|
|
7
|
+
|
|
8
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
const CONFIG_DIR = join(homedir(), '.antikit');
|
|
10
|
+
const UPDATE_CHECK_FILE = join(CONFIG_DIR, 'update-check.json');
|
|
11
|
+
|
|
12
|
+
// Check for updates every 6 hours
|
|
13
|
+
const CHECK_INTERVAL = 1000 * 60 * 60 * 6;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Compare semantic versions
|
|
17
|
+
*/
|
|
18
|
+
function compareVersions(v1, v2) {
|
|
19
|
+
const parts1 = v1.split('.').map(Number);
|
|
20
|
+
const parts2 = v2.split('.').map(Number);
|
|
21
|
+
|
|
22
|
+
for (let i = 0; i < 3; i++) {
|
|
23
|
+
if (parts1[i] > parts2[i]) return 1;
|
|
24
|
+
if (parts1[i] < parts2[i]) return -1;
|
|
25
|
+
}
|
|
26
|
+
return 0;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Load cached update check data
|
|
31
|
+
*/
|
|
32
|
+
function loadUpdateCache() {
|
|
33
|
+
try {
|
|
34
|
+
if (!existsSync(UPDATE_CHECK_FILE)) return null;
|
|
35
|
+
return JSON.parse(readFileSync(UPDATE_CHECK_FILE, 'utf-8'));
|
|
36
|
+
} catch {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Display update notification
|
|
43
|
+
*/
|
|
44
|
+
function displayUpdateNotification(packageName, currentVersion, latestVersion) {
|
|
45
|
+
console.error('');
|
|
46
|
+
console.error(chalk.yellow('╭' + '─'.repeat(58) + '╮'));
|
|
47
|
+
console.error(chalk.yellow('│') + ' '.repeat(58) + chalk.yellow('│'));
|
|
48
|
+
console.error(chalk.yellow('│') + ` ${chalk.bold.yellow('Update available!')} ${chalk.dim(currentVersion)} → ${chalk.green.bold(latestVersion)}`.padEnd(76) + chalk.yellow('│'));
|
|
49
|
+
console.error(chalk.yellow('│') + ' '.repeat(58) + chalk.yellow('│'));
|
|
50
|
+
console.error(chalk.yellow('│') + ` Run ${chalk.cyan(`npm i -g ${packageName}`)} to update`.padEnd(65) + chalk.yellow('│'));
|
|
51
|
+
console.error(chalk.yellow('│') + ' '.repeat(58) + chalk.yellow('│'));
|
|
52
|
+
console.error(chalk.yellow('╰' + '─'.repeat(58) + '╯'));
|
|
53
|
+
console.error('');
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Store pending notification
|
|
57
|
+
let pendingNotification = null;
|
|
58
|
+
let listenerRegistered = false;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Check for updates (non-blocking, uses cache)
|
|
62
|
+
*/
|
|
63
|
+
export function checkForUpdates(packageName, currentVersion) {
|
|
64
|
+
const cache = loadUpdateCache();
|
|
65
|
+
const now = Date.now();
|
|
66
|
+
|
|
67
|
+
// Display notification from cache if update available
|
|
68
|
+
if (cache && cache.latestVersion && compareVersions(cache.latestVersion, currentVersion) > 0) {
|
|
69
|
+
pendingNotification = { packageName, currentVersion, latestVersion: cache.latestVersion };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Register to show notification after command completes (only once)
|
|
73
|
+
if (!listenerRegistered) {
|
|
74
|
+
listenerRegistered = true;
|
|
75
|
+
process.on('beforeExit', () => {
|
|
76
|
+
if (pendingNotification) {
|
|
77
|
+
displayUpdateNotification(
|
|
78
|
+
pendingNotification.packageName,
|
|
79
|
+
pendingNotification.currentVersion,
|
|
80
|
+
pendingNotification.latestVersion
|
|
81
|
+
);
|
|
82
|
+
pendingNotification = null;
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Spawn background process to refresh cache if needed
|
|
88
|
+
if (!cache || !cache.checkedAt || (now - cache.checkedAt) >= CHECK_INTERVAL) {
|
|
89
|
+
try {
|
|
90
|
+
const checkScript = join(__dirname, 'updateCheck.js');
|
|
91
|
+
const child = spawn(process.execPath, [checkScript, packageName], {
|
|
92
|
+
detached: true,
|
|
93
|
+
stdio: 'ignore'
|
|
94
|
+
});
|
|
95
|
+
child.unref();
|
|
96
|
+
} catch {
|
|
97
|
+
// Ignore spawn errors
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Initialize update cache (call this once during install or first run)
|
|
104
|
+
*/
|
|
105
|
+
export async function initUpdateCache(packageName) {
|
|
106
|
+
const latestVersion = await fetchLatestVersion(packageName);
|
|
107
|
+
if (latestVersion) {
|
|
108
|
+
saveUpdateCache({ latestVersion, checkedAt: Date.now() });
|
|
109
|
+
}
|
|
110
|
+
return latestVersion;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
|