ai-agent-skills 1.9.0 → 1.9.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/README.md +4 -0
- package/cli.js +332 -7
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -42,6 +42,9 @@ npx ai-agent-skills browse
|
|
|
42
42
|
npx ai-agent-skills install anthropics/skills
|
|
43
43
|
npx ai-agent-skills install anthropics/skills/pdf # specific skill
|
|
44
44
|
|
|
45
|
+
# Install from any git URL (SSH or HTTPS)
|
|
46
|
+
npx ai-agent-skills install git@github.com:anthropics/skills.git
|
|
47
|
+
|
|
45
48
|
# Install from local path
|
|
46
49
|
npx ai-agent-skills install ./my-custom-skill
|
|
47
50
|
```
|
|
@@ -135,6 +138,7 @@ npx ai-agent-skills list --installed --agent cursor
|
|
|
135
138
|
npx ai-agent-skills install <name> # installs to ALL agents
|
|
136
139
|
npx ai-agent-skills install <name> --agent cursor # install to specific agent only
|
|
137
140
|
npx ai-agent-skills install <owner/repo> # from GitHub (all agents)
|
|
141
|
+
npx ai-agent-skills install <git-url> # from any git URL (ssh/https)
|
|
138
142
|
npx ai-agent-skills install ./path # from local path (all agents)
|
|
139
143
|
npx ai-agent-skills install <name> --dry-run # preview only
|
|
140
144
|
|
package/cli.js
CHANGED
|
@@ -620,6 +620,93 @@ function updateFromGitHub(meta, skillName, agent, destPath, dryRun) {
|
|
|
620
620
|
}
|
|
621
621
|
}
|
|
622
622
|
|
|
623
|
+
function updateFromGitUrl(meta, skillName, agent, destPath, dryRun) {
|
|
624
|
+
const { execFileSync } = require('child_process');
|
|
625
|
+
const parsed = parseGitUrl(meta.url);
|
|
626
|
+
const url = parsed.url;
|
|
627
|
+
const ref = meta.ref || parsed.ref;
|
|
628
|
+
|
|
629
|
+
// Validate URL from metadata
|
|
630
|
+
try {
|
|
631
|
+
validateGitUrl(url);
|
|
632
|
+
} catch (e) {
|
|
633
|
+
error(`Invalid git URL in metadata: ${e.message}. Try reinstalling the skill.`);
|
|
634
|
+
return false;
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
if (dryRun) {
|
|
638
|
+
log(`\n${colors.bold}Dry Run${colors.reset} (no changes made)\n`);
|
|
639
|
+
info(`Would update: ${skillName} (from git:${url}${ref ? `#${ref}` : ''})`);
|
|
640
|
+
info(`Agent: ${agent}`);
|
|
641
|
+
info(`Path: ${destPath}`);
|
|
642
|
+
return true;
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
// Use secure temp directory creation
|
|
646
|
+
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'ai-skills-update-'));
|
|
647
|
+
|
|
648
|
+
try {
|
|
649
|
+
info(`Updating ${skillName} from ${url}${ref ? `#${ref}` : ''}...`);
|
|
650
|
+
const cloneArgs = ['clone', '--depth', '1'];
|
|
651
|
+
if (ref) {
|
|
652
|
+
cloneArgs.push('--branch', ref);
|
|
653
|
+
}
|
|
654
|
+
cloneArgs.push(url, tempDir);
|
|
655
|
+
execFileSync('git', cloneArgs, { stdio: 'pipe' });
|
|
656
|
+
|
|
657
|
+
let sourcePath;
|
|
658
|
+
if (meta.isRootSkill) {
|
|
659
|
+
sourcePath = tempDir;
|
|
660
|
+
} else if (meta.skillPath) {
|
|
661
|
+
const skillsSubdir = path.join(tempDir, 'skills', meta.skillPath);
|
|
662
|
+
const directPath = path.join(tempDir, meta.skillPath);
|
|
663
|
+
sourcePath = fs.existsSync(skillsSubdir) ? skillsSubdir : directPath;
|
|
664
|
+
} else {
|
|
665
|
+
sourcePath = tempDir;
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
if (!fs.existsSync(sourcePath) || !fs.existsSync(path.join(sourcePath, 'SKILL.md'))) {
|
|
669
|
+
error(`Skill not found in repository ${url}`);
|
|
670
|
+
fs.rmSync(tempDir, { recursive: true });
|
|
671
|
+
return false;
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
fs.rmSync(destPath, { recursive: true });
|
|
675
|
+
copyDir(sourcePath, destPath);
|
|
676
|
+
|
|
677
|
+
// Sanitize URL before storing
|
|
678
|
+
const sanitizedUrl = sanitizeGitUrl(url);
|
|
679
|
+
|
|
680
|
+
writeSkillMeta(destPath, {
|
|
681
|
+
...meta,
|
|
682
|
+
source: 'git',
|
|
683
|
+
url: sanitizedUrl,
|
|
684
|
+
ref: ref || null
|
|
685
|
+
});
|
|
686
|
+
|
|
687
|
+
fs.rmSync(tempDir, { recursive: true });
|
|
688
|
+
|
|
689
|
+
success(`\nUpdated: ${skillName}`);
|
|
690
|
+
info(`Source: git:${url}${ref ? `#${ref}` : ''}`);
|
|
691
|
+
info(`Agent: ${agent}`);
|
|
692
|
+
info(`Location: ${destPath}`);
|
|
693
|
+
return true;
|
|
694
|
+
} catch (e) {
|
|
695
|
+
// Provide more helpful error messages for common git failures
|
|
696
|
+
let errorMsg = e.message;
|
|
697
|
+
if (e.message.includes('not found') || e.message.includes('Repository not found')) {
|
|
698
|
+
errorMsg = `Repository not found. The URL may have changed or been removed.`;
|
|
699
|
+
} else if (e.message.includes('Authentication failed') || e.message.includes('Permission denied')) {
|
|
700
|
+
errorMsg = `Authentication failed. Check your credentials or SSH key.`;
|
|
701
|
+
} else if (e.message.includes('Could not resolve host')) {
|
|
702
|
+
errorMsg = `Could not resolve host. Check your network connection.`;
|
|
703
|
+
}
|
|
704
|
+
error(`Failed to update from git: ${errorMsg}`);
|
|
705
|
+
try { fs.rmSync(tempDir, { recursive: true }); } catch {}
|
|
706
|
+
return false;
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
|
|
623
710
|
// Update from local path
|
|
624
711
|
function updateFromLocalPath(meta, skillName, agent, destPath, dryRun) {
|
|
625
712
|
const sourcePath = meta.path;
|
|
@@ -696,6 +783,8 @@ function updateSkill(skillName, agent = 'claude', dryRun = false) {
|
|
|
696
783
|
switch (meta.source) {
|
|
697
784
|
case 'github':
|
|
698
785
|
return updateFromGitHub(meta, skillName, agent, destPath, dryRun);
|
|
786
|
+
case 'git':
|
|
787
|
+
return updateFromGitUrl(meta, skillName, agent, destPath, dryRun);
|
|
699
788
|
case 'local':
|
|
700
789
|
return updateFromLocalPath(meta, skillName, agent, destPath, dryRun);
|
|
701
790
|
case 'registry':
|
|
@@ -991,6 +1080,96 @@ function isGitHubUrl(source) {
|
|
|
991
1080
|
!isWindowsPath(source);
|
|
992
1081
|
}
|
|
993
1082
|
|
|
1083
|
+
function isGitUrl(source) {
|
|
1084
|
+
if (!source || typeof source !== 'string') return false;
|
|
1085
|
+
|
|
1086
|
+
// Avoid treating local filesystem paths as git URLs
|
|
1087
|
+
if (isLocalPath(source)) return false;
|
|
1088
|
+
|
|
1089
|
+
// SSH-style: git@host:path (with optional .git suffix and #ref)
|
|
1090
|
+
const sshLike = /^git@[a-zA-Z0-9._-]+:[a-zA-Z0-9._\/-]+(?:\.git)?(?:#[a-zA-Z0-9._\/-]+)?$/;
|
|
1091
|
+
// Protocol URLs: https://, git://, ssh://, file:// (allows @ for user in ssh://git@host)
|
|
1092
|
+
const protocolLike = /^(https?|git|ssh|file):\/\/[a-zA-Z0-9._@:\/-]+(?:#[a-zA-Z0-9._\/-]+)?$/;
|
|
1093
|
+
|
|
1094
|
+
return sshLike.test(source) || protocolLike.test(source);
|
|
1095
|
+
}
|
|
1096
|
+
|
|
1097
|
+
function parseGitUrl(source) {
|
|
1098
|
+
if (!source || typeof source !== 'string') return { url: null, ref: null };
|
|
1099
|
+
// Split on first # only (ref might contain special chars)
|
|
1100
|
+
const hashIndex = source.indexOf('#');
|
|
1101
|
+
if (hashIndex === -1) {
|
|
1102
|
+
return { url: source, ref: null };
|
|
1103
|
+
}
|
|
1104
|
+
return {
|
|
1105
|
+
url: source.slice(0, hashIndex),
|
|
1106
|
+
ref: source.slice(hashIndex + 1) || null
|
|
1107
|
+
};
|
|
1108
|
+
}
|
|
1109
|
+
|
|
1110
|
+
function getRepoNameFromUrl(url) {
|
|
1111
|
+
if (!url || typeof url !== 'string') return null;
|
|
1112
|
+
|
|
1113
|
+
// Remove trailing slashes and .git suffix
|
|
1114
|
+
let cleaned = url.replace(/\/+$/, '').replace(/\.git$/, '');
|
|
1115
|
+
|
|
1116
|
+
// Handle SSH URLs: git@host:org/repo -> extract 'repo'
|
|
1117
|
+
if (cleaned.includes('@') && cleaned.includes(':')) {
|
|
1118
|
+
const colonIndex = cleaned.lastIndexOf(':');
|
|
1119
|
+
const pathPart = cleaned.slice(colonIndex + 1);
|
|
1120
|
+
const segments = pathPart.split('/').filter(Boolean);
|
|
1121
|
+
return segments.length > 0 ? segments[segments.length - 1] : null;
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
// Handle protocol URLs: extract last path segment
|
|
1125
|
+
const segments = cleaned.split('/').filter(Boolean);
|
|
1126
|
+
return segments.length > 0 ? segments[segments.length - 1] : null;
|
|
1127
|
+
}
|
|
1128
|
+
|
|
1129
|
+
// Validate git URL to prevent malformed/malicious input
|
|
1130
|
+
function validateGitUrl(url) {
|
|
1131
|
+
if (!url || typeof url !== 'string') {
|
|
1132
|
+
throw new Error('Invalid git URL: empty or not a string');
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1135
|
+
// Max reasonable URL length
|
|
1136
|
+
if (url.length > 2048) {
|
|
1137
|
+
throw new Error('Git URL too long (max 2048 characters)');
|
|
1138
|
+
}
|
|
1139
|
+
|
|
1140
|
+
// Check for dangerous characters that could cause issues
|
|
1141
|
+
const dangerousChars = /[\x00-\x1f\x7f`$\\]/;
|
|
1142
|
+
if (dangerousChars.test(url)) {
|
|
1143
|
+
throw new Error('Git URL contains invalid characters');
|
|
1144
|
+
}
|
|
1145
|
+
|
|
1146
|
+
// Must match expected patterns
|
|
1147
|
+
if (!isGitUrl(url)) {
|
|
1148
|
+
throw new Error('Invalid git URL format');
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1151
|
+
return true;
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1154
|
+
// Sanitize URL for storage (remove credentials if present)
|
|
1155
|
+
function sanitizeGitUrl(url) {
|
|
1156
|
+
if (!url) return url;
|
|
1157
|
+
try {
|
|
1158
|
+
// Handle protocol URLs
|
|
1159
|
+
if (url.includes('://')) {
|
|
1160
|
+
const parsed = new URL(url);
|
|
1161
|
+
// Remove any embedded credentials
|
|
1162
|
+
parsed.username = '';
|
|
1163
|
+
parsed.password = '';
|
|
1164
|
+
return parsed.toString();
|
|
1165
|
+
}
|
|
1166
|
+
// SSH URLs don't typically have credentials embedded
|
|
1167
|
+
return url;
|
|
1168
|
+
} catch {
|
|
1169
|
+
return url;
|
|
1170
|
+
}
|
|
1171
|
+
}
|
|
1172
|
+
|
|
994
1173
|
function isWindowsPath(source) {
|
|
995
1174
|
// Match Windows absolute paths like C:\, D:\, etc.
|
|
996
1175
|
return /^[a-zA-Z]:[\\\/]/.test(source);
|
|
@@ -1184,6 +1363,148 @@ async function installFromGitHub(source, agent = 'claude', dryRun = false) {
|
|
|
1184
1363
|
}
|
|
1185
1364
|
}
|
|
1186
1365
|
|
|
1366
|
+
async function installFromGitUrl(source, agent = 'claude', dryRun = false) {
|
|
1367
|
+
const { execFileSync } = require('child_process');
|
|
1368
|
+
const { url, ref } = parseGitUrl(source);
|
|
1369
|
+
|
|
1370
|
+
// Validate URL format and safety
|
|
1371
|
+
try {
|
|
1372
|
+
validateGitUrl(url);
|
|
1373
|
+
if (ref && !/^[a-zA-Z0-9._\/-]+$/.test(ref)) {
|
|
1374
|
+
throw new Error('Invalid ref format');
|
|
1375
|
+
}
|
|
1376
|
+
} catch (e) {
|
|
1377
|
+
error(`Invalid git URL: ${e.message}`);
|
|
1378
|
+
return false;
|
|
1379
|
+
}
|
|
1380
|
+
|
|
1381
|
+
const repoName = getRepoNameFromUrl(url);
|
|
1382
|
+
if (!repoName) {
|
|
1383
|
+
error('Could not determine repository name from git URL');
|
|
1384
|
+
return false;
|
|
1385
|
+
}
|
|
1386
|
+
|
|
1387
|
+
// Use secure temp directory creation
|
|
1388
|
+
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'ai-skills-'));
|
|
1389
|
+
|
|
1390
|
+
if (dryRun) {
|
|
1391
|
+
log(`\n${colors.bold}Dry Run${colors.reset} (no changes made)\n`);
|
|
1392
|
+
info(`Would clone: ${url}${ref ? `#${ref}` : ''}`);
|
|
1393
|
+
info('Would install skills discovered in repository');
|
|
1394
|
+
info(`Agent: ${agent}`);
|
|
1395
|
+
return true;
|
|
1396
|
+
}
|
|
1397
|
+
|
|
1398
|
+
try {
|
|
1399
|
+
info(`Cloning ${url}${ref ? `#${ref}` : ''}...`);
|
|
1400
|
+
const cloneArgs = ['clone', '--depth', '1'];
|
|
1401
|
+
if (ref) {
|
|
1402
|
+
cloneArgs.push('--branch', ref);
|
|
1403
|
+
}
|
|
1404
|
+
cloneArgs.push(url, tempDir);
|
|
1405
|
+
execFileSync('git', cloneArgs, { stdio: 'pipe' });
|
|
1406
|
+
|
|
1407
|
+
const skillsDir = fs.existsSync(path.join(tempDir, 'skills'))
|
|
1408
|
+
? path.join(tempDir, 'skills')
|
|
1409
|
+
: tempDir;
|
|
1410
|
+
|
|
1411
|
+
const isRootSkill = fs.existsSync(path.join(tempDir, 'SKILL.md'));
|
|
1412
|
+
|
|
1413
|
+
if (isRootSkill) {
|
|
1414
|
+
const skillName = repoName.toLowerCase()
|
|
1415
|
+
.replace(/[^a-z0-9-]/g, '-')
|
|
1416
|
+
.replace(/-+/g, '-')
|
|
1417
|
+
.replace(/^-|-$/g, '');
|
|
1418
|
+
|
|
1419
|
+
try {
|
|
1420
|
+
validateSkillName(skillName);
|
|
1421
|
+
} catch (e) {
|
|
1422
|
+
error(`Cannot install: repo name "${repoName}" cannot be converted to valid skill name`);
|
|
1423
|
+
fs.rmSync(tempDir, { recursive: true });
|
|
1424
|
+
return false;
|
|
1425
|
+
}
|
|
1426
|
+
|
|
1427
|
+
const destDir = AGENT_PATHS[agent] || AGENT_PATHS.claude;
|
|
1428
|
+
const destPath = path.join(destDir, skillName);
|
|
1429
|
+
|
|
1430
|
+
if (!fs.existsSync(destDir)) {
|
|
1431
|
+
fs.mkdirSync(destDir, { recursive: true });
|
|
1432
|
+
}
|
|
1433
|
+
|
|
1434
|
+
copyDir(tempDir, destPath);
|
|
1435
|
+
|
|
1436
|
+
// Sanitize URL before storing in metadata
|
|
1437
|
+
const sanitizedUrl = sanitizeGitUrl(url);
|
|
1438
|
+
|
|
1439
|
+
writeSkillMeta(destPath, {
|
|
1440
|
+
source: 'git',
|
|
1441
|
+
url: sanitizedUrl,
|
|
1442
|
+
ref: ref || null,
|
|
1443
|
+
isRootSkill: true
|
|
1444
|
+
});
|
|
1445
|
+
|
|
1446
|
+
success(`\nInstalled: ${skillName} from ${url}`);
|
|
1447
|
+
info(`Location: ${destPath}`);
|
|
1448
|
+
} else {
|
|
1449
|
+
const entries = fs.readdirSync(skillsDir, { withFileTypes: true });
|
|
1450
|
+
let installed = 0;
|
|
1451
|
+
|
|
1452
|
+
// Sanitize URL before storing in metadata
|
|
1453
|
+
const sanitizedUrl = sanitizeGitUrl(url);
|
|
1454
|
+
|
|
1455
|
+
for (const entry of entries) {
|
|
1456
|
+
if (entry.isDirectory()) {
|
|
1457
|
+
const skillPath = path.join(skillsDir, entry.name);
|
|
1458
|
+
if (fs.existsSync(path.join(skillPath, 'SKILL.md'))) {
|
|
1459
|
+
const destDir = AGENT_PATHS[agent] || AGENT_PATHS.claude;
|
|
1460
|
+
const destPath = path.join(destDir, entry.name);
|
|
1461
|
+
|
|
1462
|
+
if (!fs.existsSync(destDir)) {
|
|
1463
|
+
fs.mkdirSync(destDir, { recursive: true });
|
|
1464
|
+
}
|
|
1465
|
+
|
|
1466
|
+
copyDir(skillPath, destPath);
|
|
1467
|
+
|
|
1468
|
+
writeSkillMeta(destPath, {
|
|
1469
|
+
source: 'git',
|
|
1470
|
+
url: sanitizedUrl,
|
|
1471
|
+
ref: ref || null,
|
|
1472
|
+
skillPath: entry.name
|
|
1473
|
+
});
|
|
1474
|
+
|
|
1475
|
+
log(` ${colors.green}✓${colors.reset} ${entry.name}`);
|
|
1476
|
+
installed++;
|
|
1477
|
+
}
|
|
1478
|
+
}
|
|
1479
|
+
}
|
|
1480
|
+
|
|
1481
|
+
if (installed > 0) {
|
|
1482
|
+
success(`\nInstalled ${installed} skill(s) from ${url}`);
|
|
1483
|
+
} else {
|
|
1484
|
+
warn('No skills found in repository');
|
|
1485
|
+
}
|
|
1486
|
+
}
|
|
1487
|
+
|
|
1488
|
+
fs.rmSync(tempDir, { recursive: true });
|
|
1489
|
+
return true;
|
|
1490
|
+
} catch (e) {
|
|
1491
|
+
// Provide more helpful error messages for common git failures
|
|
1492
|
+
let errorMsg = e.message;
|
|
1493
|
+
if (e.message.includes('not found') || e.message.includes('Repository not found')) {
|
|
1494
|
+
errorMsg = `Repository not found. Check the URL is correct and you have access.`;
|
|
1495
|
+
} else if (e.message.includes('Authentication failed') || e.message.includes('Permission denied')) {
|
|
1496
|
+
errorMsg = `Authentication failed. For SSH URLs, ensure your SSH key is configured. For HTTPS, check credentials.`;
|
|
1497
|
+
} else if (e.message.includes('Could not resolve host')) {
|
|
1498
|
+
errorMsg = `Could not resolve host. Check your network connection and the URL.`;
|
|
1499
|
+
} else if (e.message.includes('Connection refused') || e.message.includes('Connection timed out')) {
|
|
1500
|
+
errorMsg = `Connection failed. Check your network connection.`;
|
|
1501
|
+
}
|
|
1502
|
+
error(`Failed to install from git: ${errorMsg}`);
|
|
1503
|
+
try { fs.rmSync(tempDir, { recursive: true }); } catch {}
|
|
1504
|
+
return false;
|
|
1505
|
+
}
|
|
1506
|
+
}
|
|
1507
|
+
|
|
1187
1508
|
function installFromLocalPath(source, agent = 'claude', dryRun = false) {
|
|
1188
1509
|
const sourcePath = expandPath(source);
|
|
1189
1510
|
|
|
@@ -1286,6 +1607,7 @@ ${colors.bold}Commands:${colors.reset}
|
|
|
1286
1607
|
${colors.green}install <name>${colors.reset} Install to ALL agents (default)
|
|
1287
1608
|
${colors.green}install <name> --agent cursor${colors.reset} Install to specific agent only
|
|
1288
1609
|
${colors.green}install <owner/repo>${colors.reset} Install from GitHub repository
|
|
1610
|
+
${colors.green}install <git-url>${colors.reset} Install from any git URL (ssh/https)
|
|
1289
1611
|
${colors.green}install ./path${colors.reset} Install from local path
|
|
1290
1612
|
${colors.green}install <name> --dry-run${colors.reset} Preview installation without changes
|
|
1291
1613
|
${colors.green}uninstall <name>${colors.reset} Remove an installed skill
|
|
@@ -1323,13 +1645,14 @@ ${colors.bold}Categories:${colors.reset}
|
|
|
1323
1645
|
development, document, creative, business, productivity
|
|
1324
1646
|
|
|
1325
1647
|
${colors.bold}Examples:${colors.reset}
|
|
1326
|
-
npx ai-agent-skills browse
|
|
1327
|
-
npx ai-agent-skills install frontend-design
|
|
1328
|
-
npx ai-agent-skills install pdf --agent cursor
|
|
1329
|
-
npx ai-agent-skills install pdf --agents claude,cursor
|
|
1330
|
-
npx ai-agent-skills install anthropics/skills
|
|
1331
|
-
npx ai-agent-skills install
|
|
1332
|
-
npx ai-agent-skills install
|
|
1648
|
+
npx ai-agent-skills browse # Interactive browser
|
|
1649
|
+
npx ai-agent-skills install frontend-design # Install to ALL agents
|
|
1650
|
+
npx ai-agent-skills install pdf --agent cursor # Install to Cursor only
|
|
1651
|
+
npx ai-agent-skills install pdf --agents claude,cursor # Install to specific agents
|
|
1652
|
+
npx ai-agent-skills install anthropics/skills # Install from GitHub
|
|
1653
|
+
npx ai-agent-skills install git@example.com:user/repo.git # Install from any git URL (ssh/https)
|
|
1654
|
+
npx ai-agent-skills install ./my-skill # Install from local path
|
|
1655
|
+
npx ai-agent-skills install pdf --dry-run # Preview install
|
|
1333
1656
|
npx ai-agent-skills list --category development
|
|
1334
1657
|
npx ai-agent-skills search testing
|
|
1335
1658
|
npx ai-agent-skills update --all
|
|
@@ -1488,6 +1811,8 @@ switch (command || 'help') {
|
|
|
1488
1811
|
for (const agent of installTargets) {
|
|
1489
1812
|
if (isLocalPath(param)) {
|
|
1490
1813
|
installFromLocalPath(param, agent, dryRun);
|
|
1814
|
+
} else if (isGitUrl(param)) {
|
|
1815
|
+
installFromGitUrl(param, agent, dryRun);
|
|
1491
1816
|
} else if (isGitHubUrl(param)) {
|
|
1492
1817
|
installFromGitHub(param, agent, dryRun);
|
|
1493
1818
|
} else {
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ai-agent-skills",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.1",
|
|
4
4
|
"description": "Install curated AI agent skills with one command. Works with Claude Code, Cursor, Codex, Gemini CLI, VS Code, Copilot, and 11+ agents.",
|
|
5
5
|
"main": "cli.js",
|
|
6
6
|
"bin": {
|
|
7
|
-
"ai-agent-skills": "
|
|
8
|
-
"skills": "
|
|
7
|
+
"ai-agent-skills": "cli.js",
|
|
8
|
+
"skills": "cli.js"
|
|
9
9
|
},
|
|
10
10
|
"engines": {
|
|
11
11
|
"node": ">=14.14.0"
|