antikit 1.3.1 → 1.5.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/commands/install.js +73 -2
- package/src/commands/update.js +76 -0
- package/src/commands/upgrade.js +90 -0
- package/src/index.js +16 -0
package/package.json
CHANGED
package/src/commands/install.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import ora from 'ora';
|
|
3
3
|
import { execSync } from 'child_process';
|
|
4
|
-
import { existsSync, mkdirSync, cpSync, rmSync } from 'fs';
|
|
4
|
+
import { existsSync, mkdirSync, cpSync, rmSync, writeFileSync } from 'fs';
|
|
5
5
|
import { join } from 'path';
|
|
6
6
|
import { homedir } from 'os';
|
|
7
7
|
import { getOrCreateSkillsDir, skillExists } from '../utils/local.js';
|
|
@@ -69,15 +69,84 @@ export async function installSkill(skillName, options = {}) {
|
|
|
69
69
|
if (!existsSync(sourcePath)) {
|
|
70
70
|
rmSync(tempDir, { recursive: true, force: true });
|
|
71
71
|
spinner.fail(`Skill "${skillName}" not found in ${owner}/${repo}`);
|
|
72
|
+
if (options.noExit) throw new Error('Skill not found');
|
|
72
73
|
process.exit(1);
|
|
73
74
|
}
|
|
74
75
|
|
|
76
|
+
// --- Check dependencies ---
|
|
77
|
+
try {
|
|
78
|
+
const mdPath = join(sourcePath, 'SKILL.md');
|
|
79
|
+
if (existsSync(mdPath)) {
|
|
80
|
+
// Import locally to avoid cluttering top imports if possible, or just use fs
|
|
81
|
+
const { readFileSync } = await import('fs');
|
|
82
|
+
const content = readFileSync(mdPath, 'utf-8');
|
|
83
|
+
|
|
84
|
+
// Parse frontmatter dependencies
|
|
85
|
+
// Supports inline: dependencies: [a, b]
|
|
86
|
+
// Supports list:
|
|
87
|
+
// dependencies:
|
|
88
|
+
// - a
|
|
89
|
+
// - b
|
|
90
|
+
let deps = [];
|
|
91
|
+
|
|
92
|
+
// Try inline
|
|
93
|
+
const inlineMatch = content.match(/^dependencies:\s*\[(.*?)\]/m);
|
|
94
|
+
if (inlineMatch) {
|
|
95
|
+
deps = inlineMatch[1].split(',').map(s => s.trim().replace(/['"]/g, '')).filter(Boolean);
|
|
96
|
+
} else {
|
|
97
|
+
// Try list
|
|
98
|
+
const listMatch = content.match(/^dependencies:\s*\n((?:\s*-\s*.+\n?)+)/m);
|
|
99
|
+
if (listMatch) {
|
|
100
|
+
deps = listMatch[1].split('\n')
|
|
101
|
+
.map(l => l.replace(/^\s*-\s*/, '').trim())
|
|
102
|
+
.filter(Boolean);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (deps.length > 0) {
|
|
107
|
+
spinner.stop();
|
|
108
|
+
console.log(chalk.blue(`\nSkill "${skillName}" requires: ${deps.join(', ')}`));
|
|
109
|
+
|
|
110
|
+
for (const dep of deps) {
|
|
111
|
+
// Prevent infinite recursion if self-referencing
|
|
112
|
+
if (dep === skillName) continue;
|
|
113
|
+
|
|
114
|
+
if (!skillExists(dep)) {
|
|
115
|
+
console.log(chalk.dim(`Installing dependency: ${dep}...`));
|
|
116
|
+
// Recursive install
|
|
117
|
+
await installSkill(dep, {
|
|
118
|
+
...options,
|
|
119
|
+
force: false,
|
|
120
|
+
noExit: true // Don't exit on dependency failure, just log
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
spinner.start(`Resuming installation of "${skillName}"...`);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
} catch (e) {
|
|
128
|
+
// Dep check failed, but continue installing main skill
|
|
129
|
+
// console.error(e);
|
|
130
|
+
}
|
|
131
|
+
|
|
75
132
|
if (options.force && existsSync(destPath)) {
|
|
76
133
|
rmSync(destPath, { recursive: true, force: true });
|
|
77
134
|
}
|
|
78
135
|
|
|
79
136
|
cpSync(sourcePath, destPath, { recursive: true });
|
|
80
137
|
|
|
138
|
+
// Save skill metadata for future upgrades
|
|
139
|
+
try {
|
|
140
|
+
const metadata = {
|
|
141
|
+
name: skillName,
|
|
142
|
+
source: { owner, repo },
|
|
143
|
+
installedAt: Date.now()
|
|
144
|
+
};
|
|
145
|
+
writeFileSync(join(destPath, '.antikit-skill.json'), JSON.stringify(metadata, null, 2));
|
|
146
|
+
} catch (e) {
|
|
147
|
+
// Ignore metadata write error, not critical
|
|
148
|
+
}
|
|
149
|
+
|
|
81
150
|
// Cleanup temp
|
|
82
151
|
rmSync(tempDir, { recursive: true, force: true });
|
|
83
152
|
|
|
@@ -87,7 +156,9 @@ export async function installSkill(skillName, options = {}) {
|
|
|
87
156
|
} catch (error) {
|
|
88
157
|
spinner.fail(`Failed to install "${skillName}"`);
|
|
89
158
|
console.error(chalk.red(error.message));
|
|
159
|
+
if (options.noExit) {
|
|
160
|
+
throw error;
|
|
161
|
+
}
|
|
90
162
|
process.exit(1);
|
|
91
163
|
}
|
|
92
164
|
}
|
|
93
|
-
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import ora from 'ora';
|
|
3
|
+
import { execSync } from 'child_process';
|
|
4
|
+
import { confirm } from '@inquirer/prompts';
|
|
5
|
+
|
|
6
|
+
// Since fetchLatestVersion was internal in updateNotifier.js, let's create a helper
|
|
7
|
+
// or I can duplicate the fetch logic here for simplicity, or refactor updateNotifier.js.
|
|
8
|
+
// Refactoring is better practice.
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Update the CLI tool to the latest version
|
|
12
|
+
*/
|
|
13
|
+
export async function updateCli() {
|
|
14
|
+
const spinner = ora('Checking for updates...').start();
|
|
15
|
+
|
|
16
|
+
try {
|
|
17
|
+
// Fetch latest version from npm
|
|
18
|
+
const response = await fetch(`https://registry.npmjs.org/antikit/latest`, {
|
|
19
|
+
headers: { 'Accept': 'application/json' },
|
|
20
|
+
signal: AbortSignal.timeout(5000)
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
if (!response.ok) {
|
|
24
|
+
throw new Error('Failed to fetch version info from npm registry');
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const data = await response.json();
|
|
28
|
+
const latestVersion = data.version;
|
|
29
|
+
|
|
30
|
+
// Import package.json to get current version
|
|
31
|
+
// Using dynamic import to avoid requiring createRequire in this module if possible,
|
|
32
|
+
// but for consistency with index.js style
|
|
33
|
+
const { createRequire } = await import('module');
|
|
34
|
+
const require = createRequire(import.meta.url);
|
|
35
|
+
const pkg = require('../../package.json');
|
|
36
|
+
const currentVersion = pkg.version;
|
|
37
|
+
|
|
38
|
+
spinner.stop();
|
|
39
|
+
|
|
40
|
+
if (latestVersion === currentVersion) {
|
|
41
|
+
console.log(chalk.green(`\n✓ You are already on the latest version (${currentVersion})`));
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
console.log(chalk.bold(`\nUpdate available: ${chalk.dim(currentVersion)} → ${chalk.green(latestVersion)}`));
|
|
46
|
+
|
|
47
|
+
const shouldUpdate = await confirm({
|
|
48
|
+
message: 'Do you want to update now?',
|
|
49
|
+
default: true
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
if (!shouldUpdate) {
|
|
53
|
+
console.log(chalk.yellow('Update cancelled.'));
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const updateSpinner = ora('Updating antikit...').start();
|
|
58
|
+
|
|
59
|
+
try {
|
|
60
|
+
execSync('npm install -g antikit@latest', { stdio: 'pipe' });
|
|
61
|
+
updateSpinner.succeed(chalk.green(`Updated to version ${latestVersion}`));
|
|
62
|
+
console.log(chalk.dim('\nYou may need to restart your terminal for changes to take effect.'));
|
|
63
|
+
} catch (err) {
|
|
64
|
+
updateSpinner.fail('Update failed');
|
|
65
|
+
console.log(chalk.red('Please try running: npm install -g antikit@latest'));
|
|
66
|
+
// Check for permission error
|
|
67
|
+
if (err.message.includes('EACCES')) {
|
|
68
|
+
console.log(chalk.yellow('Note: You might need to run with sudo'));
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
} catch (error) {
|
|
73
|
+
spinner.fail('Failed to check for updates');
|
|
74
|
+
console.error(chalk.red(error.message));
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { readdirSync, existsSync, readFileSync } from 'fs';
|
|
3
|
+
import { join } from 'path';
|
|
4
|
+
import { getOrCreateSkillsDir } from '../utils/local.js';
|
|
5
|
+
import { installSkill } from './install.js';
|
|
6
|
+
import { confirm } from '@inquirer/prompts';
|
|
7
|
+
|
|
8
|
+
export async function upgradeSkills(skillName, options = {}) {
|
|
9
|
+
const skillsDir = getOrCreateSkillsDir();
|
|
10
|
+
|
|
11
|
+
// 1. Upgrade specific skill
|
|
12
|
+
if (skillName) {
|
|
13
|
+
try {
|
|
14
|
+
await upgradeSingleSkill(skillsDir, skillName);
|
|
15
|
+
} catch {
|
|
16
|
+
process.exit(1);
|
|
17
|
+
}
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// 2. Upgrade all skills
|
|
22
|
+
const skills = readdirSync(skillsDir).filter(f =>
|
|
23
|
+
existsSync(join(skillsDir, f)) &&
|
|
24
|
+
!f.startsWith('.')
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
if (skills.length === 0) {
|
|
28
|
+
console.log(chalk.yellow('No skills installed.'));
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
console.log(chalk.blue(`Found ${skills.length} installed skills.`));
|
|
33
|
+
|
|
34
|
+
let shouldProceed = options.yes;
|
|
35
|
+
if (!shouldProceed) {
|
|
36
|
+
shouldProceed = await confirm({ message: 'Upgrade all skills?', default: true });
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (!shouldProceed) return;
|
|
40
|
+
|
|
41
|
+
let successCount = 0;
|
|
42
|
+
let failCount = 0;
|
|
43
|
+
|
|
44
|
+
for (const skill of skills) {
|
|
45
|
+
try {
|
|
46
|
+
await upgradeSingleSkill(skillsDir, skill);
|
|
47
|
+
successCount++;
|
|
48
|
+
} catch {
|
|
49
|
+
failCount++;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
console.log('\n────────────────────────────────────────');
|
|
54
|
+
if (failCount === 0) {
|
|
55
|
+
console.log(chalk.green(`✓ All ${successCount} skills upgraded successfully`));
|
|
56
|
+
} else {
|
|
57
|
+
console.log(chalk.yellow(`⚠ Upgraded ${successCount} skills, ${failCount} failed`));
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
async function upgradeSingleSkill(skillsDir, skillName) {
|
|
62
|
+
const skillPath = join(skillsDir, skillName);
|
|
63
|
+
const metaPath = join(skillPath, '.antikit-skill.json');
|
|
64
|
+
|
|
65
|
+
if (!existsSync(metaPath)) {
|
|
66
|
+
console.log(chalk.yellow(`⚠ Skipping "${skillName}": Missing metadata (install again to fix)`));
|
|
67
|
+
throw new Error('Missing metadata');
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
try {
|
|
71
|
+
const meta = JSON.parse(readFileSync(metaPath, 'utf-8'));
|
|
72
|
+
if (!meta.source || !meta.source.owner || !meta.source.repo) {
|
|
73
|
+
console.log(chalk.yellow(`⚠ Skipping "${skillName}": Invalid metadata`));
|
|
74
|
+
throw new Error('Invalid metadata');
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
console.log(chalk.bold.cyan(`\nUpgrading ${skillName}...`));
|
|
78
|
+
|
|
79
|
+
await installSkill(skillName, {
|
|
80
|
+
force: true,
|
|
81
|
+
owner: meta.source.owner,
|
|
82
|
+
repo: meta.source.repo,
|
|
83
|
+
noExit: true // Don't kill process on error
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
} catch (error) {
|
|
87
|
+
// Error already logged by installSkill or above
|
|
88
|
+
throw error;
|
|
89
|
+
}
|
|
90
|
+
}
|
package/src/index.js
CHANGED
|
@@ -7,9 +7,12 @@ import { listRemoteSkills } from './commands/list.js';
|
|
|
7
7
|
import { listLocalSkills } from './commands/local.js';
|
|
8
8
|
import { installSkill } from './commands/install.js';
|
|
9
9
|
import { removeSkill } from './commands/remove.js';
|
|
10
|
+
import { updateCli } from './commands/update.js';
|
|
11
|
+
import { upgradeSkills } from './commands/upgrade.js';
|
|
10
12
|
import { listSources, addNewSource, removeExistingSource, setDefault } from './commands/source.js';
|
|
11
13
|
import { checkForUpdates } from './utils/updateNotifier.js';
|
|
12
14
|
|
|
15
|
+
|
|
13
16
|
const require = createRequire(import.meta.url);
|
|
14
17
|
const pkg = require('../package.json');
|
|
15
18
|
|
|
@@ -52,6 +55,19 @@ program
|
|
|
52
55
|
.description('Remove an installed skill')
|
|
53
56
|
.action(removeSkill);
|
|
54
57
|
|
|
58
|
+
program
|
|
59
|
+
.command('update')
|
|
60
|
+
.alias('up')
|
|
61
|
+
.description('Update antikit to the latest version')
|
|
62
|
+
.action(updateCli);
|
|
63
|
+
|
|
64
|
+
program
|
|
65
|
+
.command('upgrade [skill]')
|
|
66
|
+
.alias('ug')
|
|
67
|
+
.description('Upgrade installed skills')
|
|
68
|
+
.option('-y, --yes', 'Skip confirmation')
|
|
69
|
+
.action(upgradeSkills);
|
|
70
|
+
|
|
55
71
|
// Source management commands
|
|
56
72
|
const sourceCmd = program
|
|
57
73
|
.command('source')
|