skillscat 0.1.2 → 0.1.3
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/dist/commands/add.d.ts +1 -0
- package/dist/commands/add.d.ts.map +1 -1
- package/dist/commands/convert.d.ts +8 -0
- package/dist/commands/convert.d.ts.map +1 -0
- package/dist/commands/info.d.ts.map +1 -1
- package/dist/commands/remove.d.ts.map +1 -1
- package/dist/commands/report.d.ts +7 -0
- package/dist/commands/report.d.ts.map +1 -0
- package/dist/commands/submit.d.ts.map +1 -1
- package/dist/commands/view.d.ts +6 -0
- package/dist/commands/view.d.ts.map +1 -0
- package/dist/index.js +621 -94
- package/dist/utils/agents/agents.d.ts +7 -1
- package/dist/utils/agents/agents.d.ts.map +1 -1
- package/dist/utils/core/browser.d.ts +3 -0
- package/dist/utils/core/browser.d.ts.map +1 -0
- package/dist/utils/core/slug.d.ts +12 -0
- package/dist/utils/core/slug.d.ts.map +1 -1
- package/dist/utils/source/git.d.ts.map +1 -1
- package/dist/utils/source/source.d.ts.map +1 -1
- package/dist/utils/storage/db.d.ts +7 -0
- package/dist/utils/storage/db.d.ts.map +1 -1
- package/package.json +5 -2
package/dist/commands/add.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"add.d.ts","sourceRoot":"","sources":["../../src/commands/add.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"add.d.ts","sourceRoot":"","sources":["../../src/commands/add.ts"],"names":[],"mappings":"AA8BA,UAAU,UAAU;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAwBD,wBAAsB,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CA4S5E"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"convert.d.ts","sourceRoot":"","sources":["../../src/commands/convert.ts"],"names":[],"mappings":"AAOA,UAAU,cAAc;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAaD,wBAAsB,OAAO,CAAC,aAAa,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CA2E3F"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"info.d.ts","sourceRoot":"","sources":["../../src/commands/info.ts"],"names":[],"mappings":"AAMA,wBAAsB,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"info.d.ts","sourceRoot":"","sources":["../../src/commands/info.ts"],"names":[],"mappings":"AAMA,wBAAsB,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA+ExD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"remove.d.ts","sourceRoot":"","sources":["../../src/commands/remove.ts"],"names":[],"mappings":"AAMA,UAAU,aAAa;IACrB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,wBAAsB,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"remove.d.ts","sourceRoot":"","sources":["../../src/commands/remove.ts"],"names":[],"mappings":"AAMA,UAAU,aAAa;IACrB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,wBAAsB,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAiErF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../../src/commands/report.ts"],"names":[],"mappings":"AAKA,UAAU,aAAa;IACrB,MAAM,CAAC,EAAE,UAAU,GAAG,WAAW,CAAC;IAClC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAsBD,wBAAsB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAiDrF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"submit.d.ts","sourceRoot":"","sources":["../../src/commands/submit.ts"],"names":[],"mappings":"AAKA,UAAU,aAAa;CAEtB;
|
|
1
|
+
{"version":3,"file":"submit.d.ts","sourceRoot":"","sources":["../../src/commands/submit.ts"],"names":[],"mappings":"AAKA,UAAU,aAAa;CAEtB;AAyLD,wBAAsB,MAAM,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAqMrF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"view.d.ts","sourceRoot":"","sources":["../../src/commands/view.ts"],"names":[],"mappings":"AAQA,UAAU,WAAW;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AA0FD,wBAAsB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CA8CjF"}
|
package/dist/index.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Command } from 'commander';
|
|
3
3
|
import pc from 'picocolors';
|
|
4
|
-
import { existsSync, readFileSync, writeFileSync, mkdirSync, chmodSync, unlinkSync, readdirSync, rmSync, realpathSync, statSync } from 'node:fs';
|
|
5
|
-
import { join, dirname, posix, resolve, relative, isAbsolute } from 'node:path';
|
|
4
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync, chmodSync, unlinkSync, readdirSync, rmSync, cpSync, realpathSync, statSync } from 'node:fs';
|
|
5
|
+
import { join, dirname, posix, basename, resolve, relative, isAbsolute } from 'node:path';
|
|
6
6
|
import { createHash, randomBytes } from 'node:crypto';
|
|
7
7
|
import os, { platform, homedir, hostname, release } from 'node:os';
|
|
8
8
|
import * as readline from 'node:readline';
|
|
9
|
-
import { spawnSync, execFileSync } from 'node:child_process';
|
|
9
|
+
import { spawnSync, execFileSync, execFile } from 'node:child_process';
|
|
10
10
|
import { fileURLToPath } from 'node:url';
|
|
11
11
|
import { createServer } from 'node:http';
|
|
12
12
|
|
|
@@ -98,6 +98,7 @@ const SKILL_DISCOVERY_PATHS = [
|
|
|
98
98
|
'skills/.experimental',
|
|
99
99
|
'skills/.system',
|
|
100
100
|
'.opencode/skill',
|
|
101
|
+
'.agents',
|
|
101
102
|
'.claude/skills',
|
|
102
103
|
'.codex/skills',
|
|
103
104
|
'.cursor/skills',
|
|
@@ -1103,7 +1104,6 @@ async function fetchGitHubSkillCompanionFiles(source, skillFilePath, snapshot) {
|
|
|
1103
1104
|
const tree = await snapshot.getTree();
|
|
1104
1105
|
const normalizedSkillFilePath = normalizeRepoPath(skillFilePath);
|
|
1105
1106
|
const skillDir = getRepoDirPath(normalizedSkillFilePath);
|
|
1106
|
-
const nestedSkillDirs = getNestedSkillDirectories(tree, normalizedSkillFilePath);
|
|
1107
1107
|
const pathMap = await snapshot.getPathMap();
|
|
1108
1108
|
const files = [];
|
|
1109
1109
|
for (const item of tree) {
|
|
@@ -1114,8 +1114,6 @@ async function fetchGitHubSkillCompanionFiles(source, skillFilePath, snapshot) {
|
|
|
1114
1114
|
continue;
|
|
1115
1115
|
if (!isPathWithinDirectory(repoPath, skillDir))
|
|
1116
1116
|
continue;
|
|
1117
|
-
if (isPathInNestedSkillDirectory(repoPath, nestedSkillDirs))
|
|
1118
|
-
continue;
|
|
1119
1117
|
const relativePath = toRelativeSkillPath(repoPath, skillDir);
|
|
1120
1118
|
if (!relativePath)
|
|
1121
1119
|
continue;
|
|
@@ -1168,32 +1166,6 @@ async function resolveGitHubBlobOrSymlinkContent({ snapshot, item, currentPath,
|
|
|
1168
1166
|
visited: nextVisited,
|
|
1169
1167
|
});
|
|
1170
1168
|
}
|
|
1171
|
-
function getNestedSkillDirectories(tree, currentSkillFilePath) {
|
|
1172
|
-
const currentSkillDir = getRepoDirPath(currentSkillFilePath);
|
|
1173
|
-
const nested = new Set();
|
|
1174
|
-
for (const item of tree) {
|
|
1175
|
-
const itemPath = normalizeRepoPath(item.path);
|
|
1176
|
-
if (item.type !== 'blob' || !itemPath.endsWith('/SKILL.md'))
|
|
1177
|
-
continue;
|
|
1178
|
-
if (itemPath === currentSkillFilePath)
|
|
1179
|
-
continue;
|
|
1180
|
-
const dir = getRepoDirPath(itemPath);
|
|
1181
|
-
if (dir === currentSkillDir)
|
|
1182
|
-
continue;
|
|
1183
|
-
if (!isPathWithinDirectory(dir, currentSkillDir))
|
|
1184
|
-
continue;
|
|
1185
|
-
nested.add(dir);
|
|
1186
|
-
}
|
|
1187
|
-
return Array.from(nested);
|
|
1188
|
-
}
|
|
1189
|
-
function isPathInNestedSkillDirectory(path, nestedSkillDirs) {
|
|
1190
|
-
for (const nestedDir of nestedSkillDirs) {
|
|
1191
|
-
if (isPathWithinDirectory(path, nestedDir)) {
|
|
1192
|
-
return true;
|
|
1193
|
-
}
|
|
1194
|
-
}
|
|
1195
|
-
return false;
|
|
1196
|
-
}
|
|
1197
1169
|
function normalizeRepoPath(path) {
|
|
1198
1170
|
const normalized = path.replace(/^\/+|\/+$/g, '');
|
|
1199
1171
|
if (!normalized)
|
|
@@ -1658,6 +1630,27 @@ function parseSlug(slug) {
|
|
|
1658
1630
|
}
|
|
1659
1631
|
return { owner: match[1], name: match[2] };
|
|
1660
1632
|
}
|
|
1633
|
+
/**
|
|
1634
|
+
* Encode a slug for use in /skills/[owner]/[...name] paths
|
|
1635
|
+
* @param slug - Skill slug in format "owner/name[/nested]"
|
|
1636
|
+
* @returns Encoded path segment like "owner/name" (without leading slash)
|
|
1637
|
+
*/
|
|
1638
|
+
function encodeSlugForSkillPath(slug) {
|
|
1639
|
+
const { owner, name } = parseSlug(slug);
|
|
1640
|
+
const encodedName = name
|
|
1641
|
+
.split('/')
|
|
1642
|
+
.map((segment) => encodeURIComponent(segment))
|
|
1643
|
+
.join('/');
|
|
1644
|
+
return `${encodeURIComponent(owner)}/${encodedName}`;
|
|
1645
|
+
}
|
|
1646
|
+
/**
|
|
1647
|
+
* Build the canonical web skill path from a slug
|
|
1648
|
+
* @param slug - Skill slug in format "owner/name[/nested]"
|
|
1649
|
+
* @returns Path like "/skills/owner/name"
|
|
1650
|
+
*/
|
|
1651
|
+
function buildSkillPath(slug) {
|
|
1652
|
+
return `/skills/${encodeSlugForSkillPath(slug)}`;
|
|
1653
|
+
}
|
|
1661
1654
|
|
|
1662
1655
|
const GITHUB_API = 'https://api.github.com';
|
|
1663
1656
|
async function getAuthHeaders() {
|
|
@@ -1887,6 +1880,7 @@ function submitRepoForIndexingInBackground(source) {
|
|
|
1887
1880
|
}
|
|
1888
1881
|
}
|
|
1889
1882
|
|
|
1883
|
+
const FALLBACK_AGENT_ID = 'agents';
|
|
1890
1884
|
function sanitizeSkillDirName(skillName) {
|
|
1891
1885
|
const sanitized = skillName
|
|
1892
1886
|
.replace(/[\\/]/g, '-')
|
|
@@ -1902,6 +1896,13 @@ function sanitizeSkillDirName(skillName) {
|
|
|
1902
1896
|
return sanitized;
|
|
1903
1897
|
}
|
|
1904
1898
|
const AGENTS = [
|
|
1899
|
+
{
|
|
1900
|
+
id: FALLBACK_AGENT_ID,
|
|
1901
|
+
name: '.agents',
|
|
1902
|
+
projectPath: '.agents/',
|
|
1903
|
+
globalPath: join(homedir(), '.agents'),
|
|
1904
|
+
aliases: ['.agents', 'generic']
|
|
1905
|
+
},
|
|
1905
1906
|
{
|
|
1906
1907
|
id: 'amp',
|
|
1907
1908
|
name: 'Amp',
|
|
@@ -2023,21 +2024,51 @@ const AGENTS = [
|
|
|
2023
2024
|
globalPath: join(homedir(), '.codeium', 'windsurf', 'skills')
|
|
2024
2025
|
}
|
|
2025
2026
|
];
|
|
2027
|
+
function normalizeAgentId(id) {
|
|
2028
|
+
return id.trim().toLowerCase().replace(/\s+/g, '-');
|
|
2029
|
+
}
|
|
2030
|
+
function getGlobalDetectionPath(agent) {
|
|
2031
|
+
const normalized = agent.globalPath.replace(/[\\/]+$/, '');
|
|
2032
|
+
const container = normalized.replace(/[\\/](?:skill|skills)$/i, '');
|
|
2033
|
+
return container || normalized;
|
|
2034
|
+
}
|
|
2035
|
+
function getAgentBasePath(agent, global, cwd = process.cwd()) {
|
|
2036
|
+
return global ? agent.globalPath : join(cwd, agent.projectPath);
|
|
2037
|
+
}
|
|
2026
2038
|
/**
|
|
2027
2039
|
* Detect which agents are installed by checking for their config directories
|
|
2028
2040
|
*/
|
|
2029
2041
|
function detectInstalledAgents() {
|
|
2030
2042
|
return AGENTS.filter(agent => {
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
return existsSync(globalDir);
|
|
2043
|
+
const globalDir = getGlobalDetectionPath(agent);
|
|
2044
|
+
return existsSync(agent.globalPath) || existsSync(globalDir);
|
|
2034
2045
|
});
|
|
2035
2046
|
}
|
|
2047
|
+
function detectProjectAgents(cwd = process.cwd()) {
|
|
2048
|
+
return AGENTS.filter((agent) => existsSync(getAgentBasePath(agent, false, cwd)));
|
|
2049
|
+
}
|
|
2050
|
+
function preferSpecificAgents(agents) {
|
|
2051
|
+
const specificAgents = agents.filter((agent) => agent.id !== FALLBACK_AGENT_ID);
|
|
2052
|
+
return specificAgents.length > 0 ? specificAgents : agents;
|
|
2053
|
+
}
|
|
2054
|
+
function detectPreferredAgents(global, cwd = process.cwd()) {
|
|
2055
|
+
if (global) {
|
|
2056
|
+
const installedAgents = preferSpecificAgents(detectInstalledAgents());
|
|
2057
|
+
return installedAgents.length > 0 ? installedAgents : [getFallbackAgent()];
|
|
2058
|
+
}
|
|
2059
|
+
const projectAgents = preferSpecificAgents(detectProjectAgents(cwd));
|
|
2060
|
+
if (projectAgents.length > 0) {
|
|
2061
|
+
return projectAgents;
|
|
2062
|
+
}
|
|
2063
|
+
const installedAgents = preferSpecificAgents(detectInstalledAgents());
|
|
2064
|
+
return installedAgents.length > 0 ? installedAgents : [getFallbackAgent()];
|
|
2065
|
+
}
|
|
2036
2066
|
/**
|
|
2037
2067
|
* Get agent by ID
|
|
2038
2068
|
*/
|
|
2039
2069
|
function getAgentById(id) {
|
|
2040
|
-
|
|
2070
|
+
const normalized = normalizeAgentId(id);
|
|
2071
|
+
return AGENTS.find((agent) => agent.id === normalized || agent.aliases?.some((alias) => normalizeAgentId(alias) === normalized));
|
|
2041
2072
|
}
|
|
2042
2073
|
/**
|
|
2043
2074
|
* Get agents by IDs
|
|
@@ -2045,11 +2076,18 @@ function getAgentById(id) {
|
|
|
2045
2076
|
function getAgentsByIds(ids) {
|
|
2046
2077
|
return ids.map(id => getAgentById(id)).filter((a) => a !== undefined);
|
|
2047
2078
|
}
|
|
2079
|
+
function getFallbackAgent() {
|
|
2080
|
+
const fallbackAgent = getAgentById(FALLBACK_AGENT_ID);
|
|
2081
|
+
if (!fallbackAgent) {
|
|
2082
|
+
throw new Error('Fallback .agents target is not configured');
|
|
2083
|
+
}
|
|
2084
|
+
return fallbackAgent;
|
|
2085
|
+
}
|
|
2048
2086
|
/**
|
|
2049
2087
|
* Get skill installation path for an agent
|
|
2050
2088
|
*/
|
|
2051
|
-
function getSkillPath(agent, skillName, global) {
|
|
2052
|
-
const basePath =
|
|
2089
|
+
function getSkillPath(agent, skillName, global, cwd = process.cwd()) {
|
|
2090
|
+
const basePath = getAgentBasePath(agent, global, cwd);
|
|
2053
2091
|
return join(basePath, sanitizeSkillDirName(skillName));
|
|
2054
2092
|
}
|
|
2055
2093
|
|
|
@@ -2111,6 +2149,7 @@ function normalizeSkill(raw) {
|
|
|
2111
2149
|
sha: typeof candidate.sha === 'string' ? candidate.sha : undefined,
|
|
2112
2150
|
path,
|
|
2113
2151
|
contentHash: typeof candidate.contentHash === 'string' ? candidate.contentHash : undefined,
|
|
2152
|
+
installRoot: typeof candidate.installRoot === 'string' && candidate.installRoot ? candidate.installRoot : undefined,
|
|
2114
2153
|
};
|
|
2115
2154
|
}
|
|
2116
2155
|
function loadDb() {
|
|
@@ -2155,11 +2194,75 @@ function sameSource(a, b) {
|
|
|
2155
2194
|
function sameInstallationIdentity(a, b) {
|
|
2156
2195
|
return (a.name === b.name &&
|
|
2157
2196
|
a.global === b.global &&
|
|
2197
|
+
(a.installRoot ?? '') === (b.installRoot ?? '') &&
|
|
2158
2198
|
a.path === b.path &&
|
|
2159
2199
|
(a.registrySlug ?? '') === (b.registrySlug ?? '') &&
|
|
2160
2200
|
getUpdateStrategy$1(a) === getUpdateStrategy$1(b) &&
|
|
2161
2201
|
sameSource(a.source, b.source));
|
|
2162
2202
|
}
|
|
2203
|
+
function sameLegacyProjectIdentity(existing, next) {
|
|
2204
|
+
return (!existing.global &&
|
|
2205
|
+
!next.global &&
|
|
2206
|
+
!existing.installRoot &&
|
|
2207
|
+
Boolean(next.installRoot) &&
|
|
2208
|
+
existing.name === next.name &&
|
|
2209
|
+
existing.path === next.path &&
|
|
2210
|
+
(existing.registrySlug ?? '') === (next.registrySlug ?? '') &&
|
|
2211
|
+
getUpdateStrategy$1(existing) === getUpdateStrategy$1(next) &&
|
|
2212
|
+
sameSource(existing.source, next.source));
|
|
2213
|
+
}
|
|
2214
|
+
function saveDbIfChanged(db, changed) {
|
|
2215
|
+
if (changed) {
|
|
2216
|
+
saveDb(db);
|
|
2217
|
+
}
|
|
2218
|
+
return db;
|
|
2219
|
+
}
|
|
2220
|
+
function reconcileInstallations(db) {
|
|
2221
|
+
let changed = false;
|
|
2222
|
+
const cwd = process.cwd();
|
|
2223
|
+
db.skills = db.skills.flatMap((skill) => {
|
|
2224
|
+
let reconciledSkill = skill;
|
|
2225
|
+
if (!reconciledSkill.global && !reconciledSkill.installRoot) {
|
|
2226
|
+
const hasCurrentWorkspaceMatch = reconciledSkill.agents.some((agentId) => {
|
|
2227
|
+
const agent = getAgentById(agentId);
|
|
2228
|
+
if (!agent) {
|
|
2229
|
+
return false;
|
|
2230
|
+
}
|
|
2231
|
+
const skillDir = getSkillPath(agent, reconciledSkill.name, false, cwd);
|
|
2232
|
+
return existsSync(join(skillDir, 'SKILL.md'));
|
|
2233
|
+
});
|
|
2234
|
+
if (!hasCurrentWorkspaceMatch) {
|
|
2235
|
+
return [reconciledSkill];
|
|
2236
|
+
}
|
|
2237
|
+
reconciledSkill = {
|
|
2238
|
+
...reconciledSkill,
|
|
2239
|
+
installRoot: cwd,
|
|
2240
|
+
};
|
|
2241
|
+
changed = true;
|
|
2242
|
+
}
|
|
2243
|
+
const remainingAgents = reconciledSkill.agents.filter((agentId) => {
|
|
2244
|
+
const agent = getAgentById(agentId);
|
|
2245
|
+
if (!agent) {
|
|
2246
|
+
changed = true;
|
|
2247
|
+
return false;
|
|
2248
|
+
}
|
|
2249
|
+
const skillDir = getSkillPath(agent, reconciledSkill.name, reconciledSkill.global, reconciledSkill.installRoot);
|
|
2250
|
+
return existsSync(join(skillDir, 'SKILL.md'));
|
|
2251
|
+
});
|
|
2252
|
+
if (remainingAgents.length === reconciledSkill.agents.length) {
|
|
2253
|
+
return [reconciledSkill];
|
|
2254
|
+
}
|
|
2255
|
+
changed = true;
|
|
2256
|
+
if (remainingAgents.length === 0) {
|
|
2257
|
+
return [];
|
|
2258
|
+
}
|
|
2259
|
+
return [{
|
|
2260
|
+
...reconciledSkill,
|
|
2261
|
+
agents: remainingAgents,
|
|
2262
|
+
}];
|
|
2263
|
+
});
|
|
2264
|
+
return saveDbIfChanged(db, changed);
|
|
2265
|
+
}
|
|
2163
2266
|
/**
|
|
2164
2267
|
* Record a skill installation
|
|
2165
2268
|
*/
|
|
@@ -2170,7 +2273,8 @@ function recordInstallation(skill) {
|
|
|
2170
2273
|
return;
|
|
2171
2274
|
}
|
|
2172
2275
|
// Replace only exact same installation identity.
|
|
2173
|
-
db.skills = db.skills.filter((existing) => !sameInstallationIdentity(existing, normalized)
|
|
2276
|
+
db.skills = db.skills.filter((existing) => !sameInstallationIdentity(existing, normalized) &&
|
|
2277
|
+
!sameLegacyProjectIdentity(existing, normalized));
|
|
2174
2278
|
db.skills.push(normalized);
|
|
2175
2279
|
saveDb(db);
|
|
2176
2280
|
}
|
|
@@ -2192,6 +2296,9 @@ function removeInstallation(skillName, options) {
|
|
|
2192
2296
|
if (options?.global !== undefined && skill.global !== options.global) {
|
|
2193
2297
|
return [skill];
|
|
2194
2298
|
}
|
|
2299
|
+
if (options?.installRoot !== undefined && (skill.installRoot ?? '') !== options.installRoot) {
|
|
2300
|
+
return [skill];
|
|
2301
|
+
}
|
|
2195
2302
|
if (targetAgents && targetAgents.length > 0) {
|
|
2196
2303
|
const remainingAgents = skill.agents.filter((agentId) => !targetAgents.includes(agentId));
|
|
2197
2304
|
if (remainingAgents.length === 0) {
|
|
@@ -2203,11 +2310,60 @@ function removeInstallation(skillName, options) {
|
|
|
2203
2310
|
});
|
|
2204
2311
|
saveDb(db);
|
|
2205
2312
|
}
|
|
2313
|
+
function copyInstallationAgent(sourceAgentId, targetAgentId, options) {
|
|
2314
|
+
if (sourceAgentId === targetAgentId) {
|
|
2315
|
+
return 0;
|
|
2316
|
+
}
|
|
2317
|
+
const db = loadDb();
|
|
2318
|
+
let updated = 0;
|
|
2319
|
+
const sourceSkillDirs = options?.sourceSkillDirs ? new Set(options.sourceSkillDirs) : null;
|
|
2320
|
+
const sourceAgent = getAgentById(sourceAgentId);
|
|
2321
|
+
db.skills = db.skills.map((skill) => {
|
|
2322
|
+
if (options?.global !== undefined && skill.global !== options.global) {
|
|
2323
|
+
return skill;
|
|
2324
|
+
}
|
|
2325
|
+
if (!skill.agents.includes(sourceAgentId) || skill.agents.includes(targetAgentId)) {
|
|
2326
|
+
return skill;
|
|
2327
|
+
}
|
|
2328
|
+
let installRoot = skill.installRoot;
|
|
2329
|
+
if (options?.installRoot !== undefined) {
|
|
2330
|
+
if (installRoot) {
|
|
2331
|
+
if (installRoot !== options.installRoot) {
|
|
2332
|
+
return skill;
|
|
2333
|
+
}
|
|
2334
|
+
}
|
|
2335
|
+
else if (!skill.global &&
|
|
2336
|
+
sourceAgent &&
|
|
2337
|
+
existsSync(join(getSkillPath(sourceAgent, skill.name, false, options.installRoot), 'SKILL.md'))) {
|
|
2338
|
+
installRoot = options.installRoot;
|
|
2339
|
+
}
|
|
2340
|
+
else {
|
|
2341
|
+
return skill;
|
|
2342
|
+
}
|
|
2343
|
+
}
|
|
2344
|
+
if (sourceSkillDirs && sourceAgent) {
|
|
2345
|
+
const sourceSkillDir = getSkillPath(sourceAgent, skill.name, skill.global, installRoot);
|
|
2346
|
+
if (!sourceSkillDirs.has(sourceSkillDir)) {
|
|
2347
|
+
return skill;
|
|
2348
|
+
}
|
|
2349
|
+
}
|
|
2350
|
+
updated += 1;
|
|
2351
|
+
return {
|
|
2352
|
+
...skill,
|
|
2353
|
+
installRoot,
|
|
2354
|
+
agents: [...skill.agents, targetAgentId],
|
|
2355
|
+
};
|
|
2356
|
+
});
|
|
2357
|
+
if (updated > 0) {
|
|
2358
|
+
saveDb(db);
|
|
2359
|
+
}
|
|
2360
|
+
return updated;
|
|
2361
|
+
}
|
|
2206
2362
|
/**
|
|
2207
2363
|
* Get all installed skills
|
|
2208
2364
|
*/
|
|
2209
2365
|
function getInstalledSkills() {
|
|
2210
|
-
const db = loadDb();
|
|
2366
|
+
const db = reconcileInstallations(loadDb());
|
|
2211
2367
|
return db.skills;
|
|
2212
2368
|
}
|
|
2213
2369
|
|
|
@@ -2301,6 +2457,7 @@ function box(content, title) {
|
|
|
2301
2457
|
const COMPANION_MANIFEST_FILE = '.skillscat-companion-files.json';
|
|
2302
2458
|
const COMPANION_MANIFEST_VERSION = 1;
|
|
2303
2459
|
async function add(source, options) {
|
|
2460
|
+
const explicitRepoInstall = options.repo === true;
|
|
2304
2461
|
const repoSource = parseSource(source);
|
|
2305
2462
|
if (!repoSource) {
|
|
2306
2463
|
error('Invalid source. Supported formats:');
|
|
@@ -2328,6 +2485,7 @@ async function add(source, options) {
|
|
|
2328
2485
|
sourceInput: source,
|
|
2329
2486
|
repoSource,
|
|
2330
2487
|
requestedSkillNames: options.skill ?? [],
|
|
2488
|
+
explicitRepoInstall,
|
|
2331
2489
|
explicitRefBypassRegistry: isExplicitGitHubRefSource,
|
|
2332
2490
|
githubSnapshot,
|
|
2333
2491
|
});
|
|
@@ -2369,12 +2527,17 @@ async function add(source, options) {
|
|
|
2369
2527
|
}
|
|
2370
2528
|
console.log(pc.dim('─'.repeat(50)));
|
|
2371
2529
|
console.log(pc.dim('Install with:'));
|
|
2372
|
-
console.log(` ${pc.cyan(
|
|
2530
|
+
console.log(` ${pc.cyan(formatAddCommand(source, options))}`);
|
|
2373
2531
|
return;
|
|
2374
2532
|
}
|
|
2375
2533
|
if (selectionMode === 'install-all' && !options.yes && (!options.skill || options.skill.length === 0)) {
|
|
2376
2534
|
console.log();
|
|
2377
|
-
|
|
2535
|
+
if (explicitRepoInstall) {
|
|
2536
|
+
info$1(`Treating ${pc.cyan(sourceLabel)} as a repository install.`);
|
|
2537
|
+
}
|
|
2538
|
+
else {
|
|
2539
|
+
info$1(`No published skill slug matched ${pc.cyan(sourceLabel)}.`);
|
|
2540
|
+
}
|
|
2378
2541
|
console.log(pc.dim(`Found ${resolvedSkills.length} published skill(s) in repository ${sourceLabel}:`));
|
|
2379
2542
|
for (const entry of resolvedSkills) {
|
|
2380
2543
|
console.log(pc.dim(` - ${entry.skill.name}${formatSkillPathHint(entry.skill.path)}`));
|
|
@@ -2404,6 +2567,8 @@ async function add(source, options) {
|
|
|
2404
2567
|
}
|
|
2405
2568
|
// Detect or select agents
|
|
2406
2569
|
let targetAgents;
|
|
2570
|
+
const isGlobal = options.global ?? false;
|
|
2571
|
+
let usedFallbackAgent = false;
|
|
2407
2572
|
if (options.agent && options.agent.length > 0) {
|
|
2408
2573
|
targetAgents = getAgentsByIds(options.agent);
|
|
2409
2574
|
if (targetAgents.length === 0) {
|
|
@@ -2416,38 +2581,12 @@ async function add(source, options) {
|
|
|
2416
2581
|
}
|
|
2417
2582
|
}
|
|
2418
2583
|
else {
|
|
2419
|
-
targetAgents =
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
warn('No coding agents detected.');
|
|
2424
|
-
console.log(pc.dim('Select agents to install skills for:'));
|
|
2425
|
-
console.log();
|
|
2426
|
-
for (let i = 0; i < AGENTS.length; i++) {
|
|
2427
|
-
console.log(` ${pc.dim(`${i + 1}.`)} ${AGENTS[i].name} (${AGENTS[i].id})`);
|
|
2428
|
-
}
|
|
2429
|
-
console.log();
|
|
2430
|
-
const response = await prompt('Enter agent numbers (comma-separated) or "all": ');
|
|
2431
|
-
if (response.toLowerCase() === 'all') {
|
|
2432
|
-
targetAgents = AGENTS;
|
|
2433
|
-
}
|
|
2434
|
-
else {
|
|
2435
|
-
const indices = response.split(',').map((s) => parseInt(s.trim()) - 1);
|
|
2436
|
-
targetAgents = indices
|
|
2437
|
-
.filter((i) => i >= 0 && i < AGENTS.length)
|
|
2438
|
-
.map((i) => AGENTS[i]);
|
|
2439
|
-
}
|
|
2440
|
-
if (targetAgents.length === 0) {
|
|
2441
|
-
error('No agents selected.');
|
|
2442
|
-
process.exit(1);
|
|
2443
|
-
}
|
|
2444
|
-
}
|
|
2445
|
-
else {
|
|
2446
|
-
targetAgents = AGENTS.filter((a) => a.id === 'claude-code');
|
|
2447
|
-
}
|
|
2584
|
+
targetAgents = detectPreferredAgents(isGlobal);
|
|
2585
|
+
usedFallbackAgent = targetAgents.length === 1 && targetAgents[0]?.id === FALLBACK_AGENT_ID;
|
|
2586
|
+
if (usedFallbackAgent) {
|
|
2587
|
+
warn('No agent-specific directory detected. Installing to .agents.');
|
|
2448
2588
|
}
|
|
2449
2589
|
}
|
|
2450
|
-
const isGlobal = options.global ?? false;
|
|
2451
2590
|
const locationLabel = isGlobal ? 'global' : 'project';
|
|
2452
2591
|
console.log();
|
|
2453
2592
|
console.log(pc.bold(`Installing ${selectedEntries.length} skill(s) to ${targetAgents.length} agent(s):`));
|
|
@@ -2460,7 +2599,7 @@ async function add(source, options) {
|
|
|
2460
2599
|
console.log();
|
|
2461
2600
|
console.log(pc.dim('Target agents:'));
|
|
2462
2601
|
for (const agent of targetAgents) {
|
|
2463
|
-
const path =
|
|
2602
|
+
const path = getAgentBasePath(agent, isGlobal);
|
|
2464
2603
|
console.log(` ${pc.cyan('•')} ${agent.name} → ${pc.dim(path)}`);
|
|
2465
2604
|
}
|
|
2466
2605
|
console.log();
|
|
@@ -2546,6 +2685,7 @@ async function add(source, options) {
|
|
|
2546
2685
|
sha: skill.sha,
|
|
2547
2686
|
path: skill.path,
|
|
2548
2687
|
contentHash: skill.contentHash,
|
|
2688
|
+
installRoot: isGlobal ? undefined : process.cwd(),
|
|
2549
2689
|
});
|
|
2550
2690
|
trackInstallation(entry.trackingSlug).catch(() => { });
|
|
2551
2691
|
}
|
|
@@ -2567,12 +2707,16 @@ async function add(source, options) {
|
|
|
2567
2707
|
console.log();
|
|
2568
2708
|
console.log(pc.dim('Skills are now available in your coding agents.'));
|
|
2569
2709
|
console.log(pc.dim('Restart your agent or start a new session to use them.'));
|
|
2710
|
+
if (usedFallbackAgent) {
|
|
2711
|
+
console.log(pc.dim('Need a tool-specific copy later? Run `npx skillscat convert <agent>` to copy from .agents.'));
|
|
2712
|
+
}
|
|
2570
2713
|
}
|
|
2571
|
-
async function resolveInstallSkills({ sourceInput, repoSource, requestedSkillNames, explicitRefBypassRegistry, githubSnapshot, }) {
|
|
2714
|
+
async function resolveInstallSkills({ sourceInput, repoSource, requestedSkillNames, explicitRepoInstall, explicitRefBypassRegistry, githubSnapshot, }) {
|
|
2572
2715
|
const requestedNamesLower = new Set(requestedSkillNames.map((name) => name.toLowerCase()));
|
|
2573
2716
|
const needsRegistryFirst = repoSource.platform === 'github' && !explicitRefBypassRegistry;
|
|
2574
|
-
const
|
|
2575
|
-
const
|
|
2717
|
+
const ambiguousSlugOrRepoInput = isAmbiguousSlugOrRepoInput(sourceInput, repoSource);
|
|
2718
|
+
const preferRepoSelection = explicitRepoInstall || ambiguousSlugOrRepoInput;
|
|
2719
|
+
const canShortCircuitExactSlug = ambiguousSlugOrRepoInput && !explicitRepoInstall && requestedNamesLower.size === 0;
|
|
2576
2720
|
let resolved = [];
|
|
2577
2721
|
let selectionMode = 'default';
|
|
2578
2722
|
let registryRepoMatchesFound = false;
|
|
@@ -2605,7 +2749,7 @@ async function resolveInstallSkills({ sourceInput, repoSource, requestedSkillNam
|
|
|
2605
2749
|
if (requestedNamesLower.size > 0) {
|
|
2606
2750
|
selectedSummaries = summaries.filter((item) => requestedNamesLower.has(item.name.toLowerCase()));
|
|
2607
2751
|
}
|
|
2608
|
-
else if (
|
|
2752
|
+
else if (preferRepoSelection) {
|
|
2609
2753
|
selectionMode = 'install-all';
|
|
2610
2754
|
}
|
|
2611
2755
|
if (selectedSummaries.length > 0) {
|
|
@@ -2649,7 +2793,7 @@ async function resolveInstallSkills({ sourceInput, repoSource, requestedSkillNam
|
|
|
2649
2793
|
throw err;
|
|
2650
2794
|
}
|
|
2651
2795
|
// Fallback: preserve existing behavior for registry slugs or private skills.
|
|
2652
|
-
if (resolved.length === 0 && true) {
|
|
2796
|
+
if (!explicitRepoInstall && resolved.length === 0 && true) {
|
|
2653
2797
|
const registrySkill = await fetchSkill(sourceInput).catch(() => null);
|
|
2654
2798
|
if (registrySkill?.content) {
|
|
2655
2799
|
resolved.push(toRegistryResolvedSkill(registrySkill, sourceInput, repoSource));
|
|
@@ -2971,6 +3115,9 @@ function formatSkillPathHint(path) {
|
|
|
2971
3115
|
const normalized = normalizeSkillPath(path);
|
|
2972
3116
|
return normalized ? ` (${normalized})` : '';
|
|
2973
3117
|
}
|
|
3118
|
+
function formatAddCommand(source, options) {
|
|
3119
|
+
return options.repo ? `npx skillscat add ${source} --repo` : `npx skillscat add ${source}`;
|
|
3120
|
+
}
|
|
2974
3121
|
function toSkillFilePath(path) {
|
|
2975
3122
|
const normalized = normalizeSkillPath(path);
|
|
2976
3123
|
return normalized ? `${normalized}/SKILL.md` : 'SKILL.md';
|
|
@@ -3095,7 +3242,7 @@ async function list(options) {
|
|
|
3095
3242
|
warn('No skills installed.');
|
|
3096
3243
|
console.log();
|
|
3097
3244
|
console.log(pc.dim('Install skills with:'));
|
|
3098
|
-
console.log(` ${pc.cyan('npx skillscat add <
|
|
3245
|
+
console.log(` ${pc.cyan('npx skillscat add <slug>')}`);
|
|
3099
3246
|
console.log();
|
|
3100
3247
|
console.log(pc.dim('Or search for skills:'));
|
|
3101
3248
|
console.log(` ${pc.cyan('npx skillscat search <query>')}`);
|
|
@@ -3229,13 +3376,15 @@ async function search(query, options = {}) {
|
|
|
3229
3376
|
console.log(pc.dim('─'.repeat(50)));
|
|
3230
3377
|
console.log();
|
|
3231
3378
|
console.log(pc.dim('Install a skill:'));
|
|
3232
|
-
console.log(` ${pc.cyan('npx skillscat add <
|
|
3379
|
+
console.log(` ${pc.cyan('npx skillscat add <slug>')}`);
|
|
3233
3380
|
console.log();
|
|
3234
|
-
console.log(pc.dim('
|
|
3381
|
+
console.log(pc.dim('Inspect a repository first:'));
|
|
3235
3382
|
console.log(` ${pc.cyan('npx skillscat info <owner>/<repo>')}`);
|
|
3236
3383
|
}
|
|
3237
3384
|
|
|
3238
3385
|
async function remove(skillName, options) {
|
|
3386
|
+
// Reconcile tracked installs so manual deletions do not leave stale records behind.
|
|
3387
|
+
getInstalledSkills();
|
|
3239
3388
|
// Determine which agents to check
|
|
3240
3389
|
let agents;
|
|
3241
3390
|
if (options.agent && options.agent.length > 0) {
|
|
@@ -3270,6 +3419,7 @@ async function remove(skillName, options) {
|
|
|
3270
3419
|
removeInstallation(skillName, {
|
|
3271
3420
|
agents: agents.map((agent) => agent.id),
|
|
3272
3421
|
global: isGlobal,
|
|
3422
|
+
installRoot: isGlobal ? undefined : process.cwd(),
|
|
3273
3423
|
});
|
|
3274
3424
|
}
|
|
3275
3425
|
if (removed === 0) {
|
|
@@ -3443,7 +3593,7 @@ async function update(skillName, options) {
|
|
|
3443
3593
|
skillAgents.push(...agents.filter(a => skill.agents.includes(a.id)));
|
|
3444
3594
|
}
|
|
3445
3595
|
for (const agent of skillAgents) {
|
|
3446
|
-
const skillDir = getSkillPath(agent, skill.name, skill.global);
|
|
3596
|
+
const skillDir = getSkillPath(agent, skill.name, skill.global, skill.installRoot);
|
|
3447
3597
|
const skillFile = join(skillDir, 'SKILL.md');
|
|
3448
3598
|
try {
|
|
3449
3599
|
mkdirSync(dirname(skillFile), { recursive: true });
|
|
@@ -3471,6 +3621,78 @@ async function update(skillName, options) {
|
|
|
3471
3621
|
success(`Updated ${updated} skill(s) successfully!`);
|
|
3472
3622
|
}
|
|
3473
3623
|
|
|
3624
|
+
function getSkillDirectories(basePath) {
|
|
3625
|
+
if (!existsSync(basePath)) {
|
|
3626
|
+
return [];
|
|
3627
|
+
}
|
|
3628
|
+
return readdirSync(basePath, { withFileTypes: true })
|
|
3629
|
+
.filter((entry) => entry.isDirectory())
|
|
3630
|
+
.map((entry) => join(basePath, entry.name))
|
|
3631
|
+
.filter((skillDir) => existsSync(join(skillDir, 'SKILL.md')));
|
|
3632
|
+
}
|
|
3633
|
+
async function convert(targetAgentId, options) {
|
|
3634
|
+
const isGlobal = options.global ?? false;
|
|
3635
|
+
const sourceAgent = getAgentById(options.from ?? FALLBACK_AGENT_ID);
|
|
3636
|
+
const targetAgent = getAgentById(targetAgentId);
|
|
3637
|
+
if (!sourceAgent) {
|
|
3638
|
+
error(`Invalid source agent: ${options.from ?? FALLBACK_AGENT_ID}`);
|
|
3639
|
+
process.exit(1);
|
|
3640
|
+
}
|
|
3641
|
+
if (!targetAgent) {
|
|
3642
|
+
error(`Invalid target agent: ${targetAgentId}`);
|
|
3643
|
+
process.exit(1);
|
|
3644
|
+
}
|
|
3645
|
+
const sourceBase = getAgentBasePath(sourceAgent, isGlobal);
|
|
3646
|
+
const targetBase = getAgentBasePath(targetAgent, isGlobal);
|
|
3647
|
+
if (sourceBase === targetBase) {
|
|
3648
|
+
error('Source and target directories are the same.');
|
|
3649
|
+
process.exit(1);
|
|
3650
|
+
}
|
|
3651
|
+
const sourceSkills = getSkillDirectories(sourceBase);
|
|
3652
|
+
if (sourceSkills.length === 0) {
|
|
3653
|
+
warn(`No skills found in ${sourceAgent.name}.`);
|
|
3654
|
+
console.log(pc.dim(`Checked: ${sourceBase}`));
|
|
3655
|
+
return;
|
|
3656
|
+
}
|
|
3657
|
+
let copied = 0;
|
|
3658
|
+
let skipped = 0;
|
|
3659
|
+
const copiedSkillDirs = [];
|
|
3660
|
+
for (const sourceSkillDir of sourceSkills) {
|
|
3661
|
+
const skillName = basename(sourceSkillDir);
|
|
3662
|
+
const targetSkillDir = join(targetBase, skillName);
|
|
3663
|
+
if (existsSync(targetSkillDir)) {
|
|
3664
|
+
if (!options.force) {
|
|
3665
|
+
skipped += 1;
|
|
3666
|
+
continue;
|
|
3667
|
+
}
|
|
3668
|
+
rmSync(targetSkillDir, { recursive: true, force: true });
|
|
3669
|
+
}
|
|
3670
|
+
mkdirSync(dirname(targetSkillDir), { recursive: true });
|
|
3671
|
+
cpSync(sourceSkillDir, targetSkillDir, { recursive: true });
|
|
3672
|
+
copied += 1;
|
|
3673
|
+
copiedSkillDirs.push(sourceSkillDir);
|
|
3674
|
+
}
|
|
3675
|
+
if (copied === 0) {
|
|
3676
|
+
warn(`All ${sourceSkills.length} skill(s) already exist in ${targetAgent.name}.`);
|
|
3677
|
+
console.log(pc.dim('Use `--force` to overwrite the target copy.'));
|
|
3678
|
+
return;
|
|
3679
|
+
}
|
|
3680
|
+
const trackedUpdates = copyInstallationAgent(sourceAgent.id, targetAgent.id, {
|
|
3681
|
+
global: isGlobal,
|
|
3682
|
+
installRoot: isGlobal ? undefined : process.cwd(),
|
|
3683
|
+
sourceSkillDirs: copiedSkillDirs,
|
|
3684
|
+
});
|
|
3685
|
+
console.log();
|
|
3686
|
+
success(`Copied ${copied} skill(s) from ${sourceAgent.name} to ${targetAgent.name}.`);
|
|
3687
|
+
console.log(pc.dim(`${sourceBase} → ${targetBase}`));
|
|
3688
|
+
if (skipped > 0) {
|
|
3689
|
+
info$1(`Skipped ${skipped} existing skill(s). Use --force to overwrite them.`);
|
|
3690
|
+
}
|
|
3691
|
+
if (trackedUpdates > 0) {
|
|
3692
|
+
console.log(pc.dim(`Updated ${trackedUpdates} tracked installation(s) so future updates also target ${targetAgent.name}.`));
|
|
3693
|
+
}
|
|
3694
|
+
}
|
|
3695
|
+
|
|
3474
3696
|
const PACKAGE_NAME = 'skillscat';
|
|
3475
3697
|
function safeExec(command, args) {
|
|
3476
3698
|
try {
|
|
@@ -3701,8 +3923,9 @@ async function info(source) {
|
|
|
3701
3923
|
}
|
|
3702
3924
|
console.log(pc.dim('─'.repeat(50)));
|
|
3703
3925
|
console.log();
|
|
3704
|
-
console.log(pc.bold('Install:'));
|
|
3705
|
-
console.log(` ${pc.cyan(
|
|
3926
|
+
console.log(pc.bold('Install published skills by slug:'));
|
|
3927
|
+
console.log(` ${pc.cyan('npx skillscat add <slug>')}`);
|
|
3928
|
+
console.log(` ${pc.dim('Use search or the web detail page to discover the exact published slug for this repository.')}`);
|
|
3706
3929
|
console.log();
|
|
3707
3930
|
// Show compatible agents
|
|
3708
3931
|
console.log(pc.bold('Compatible agents:'));
|
|
@@ -4153,6 +4376,14 @@ async function publish(skillPath, options) {
|
|
|
4153
4376
|
}
|
|
4154
4377
|
}
|
|
4155
4378
|
|
|
4379
|
+
function printSubmitMessage(message) {
|
|
4380
|
+
for (const line of message.split('\n')) {
|
|
4381
|
+
console.log(pc.dim(line));
|
|
4382
|
+
}
|
|
4383
|
+
}
|
|
4384
|
+
const IGNORED_DISCOVERY_DIRS = new Set([
|
|
4385
|
+
'.git',
|
|
4386
|
+
]);
|
|
4156
4387
|
/**
|
|
4157
4388
|
* Check if a URL is a valid GitHub URL
|
|
4158
4389
|
*/
|
|
@@ -4243,8 +4474,7 @@ function findSkillMd(cwd, maxDepth = 3) {
|
|
|
4243
4474
|
try {
|
|
4244
4475
|
const entries = readdirSync(dir);
|
|
4245
4476
|
for (const entry of entries) {
|
|
4246
|
-
|
|
4247
|
-
if (entry.startsWith('.'))
|
|
4477
|
+
if (IGNORED_DISCOVERY_DIRS.has(entry))
|
|
4248
4478
|
continue;
|
|
4249
4479
|
const fullPath = join(dir, entry);
|
|
4250
4480
|
try {
|
|
@@ -4425,26 +4655,46 @@ async function submit(urlArg, _options) {
|
|
|
4425
4655
|
process.exit(1);
|
|
4426
4656
|
}
|
|
4427
4657
|
if (response.status === 400) {
|
|
4428
|
-
|
|
4429
|
-
|
|
4658
|
+
const submitError = result.error || result.message || 'Invalid request';
|
|
4659
|
+
console.error(pc.red(`Submission failed: ${submitError}`));
|
|
4660
|
+
if (result.code === 'no_skill_md_found') {
|
|
4430
4661
|
console.log();
|
|
4431
|
-
console.log(pc.dim('Make sure your repository has a SKILL.md file in the root
|
|
4662
|
+
console.log(pc.dim('Make sure your repository has a SKILL.md file in the repository root or a supported subdirectory, including dot folders.'));
|
|
4432
4663
|
console.log(pc.dim('Learn more: https://skillscat.com/docs/skill-format'));
|
|
4433
4664
|
}
|
|
4434
|
-
if (result.
|
|
4665
|
+
if (result.code === 'fork_no_unique_commits') {
|
|
4666
|
+
console.log();
|
|
4667
|
+
console.log(pc.dim('Please submit the original repository, or add your own commits to the fork first.'));
|
|
4668
|
+
}
|
|
4669
|
+
if (result.code === 'fork_behind_upstream') {
|
|
4435
4670
|
console.log();
|
|
4436
|
-
console.log(pc.dim('Please
|
|
4671
|
+
console.log(pc.dim('Please sync your fork with upstream before submitting it.'));
|
|
4437
4672
|
}
|
|
4438
4673
|
process.exit(1);
|
|
4439
4674
|
}
|
|
4440
4675
|
if (!response.ok || !result.success) {
|
|
4441
4676
|
console.error(pc.red(`Submission failed: ${result.error || result.message || 'Unknown error'}`));
|
|
4677
|
+
if (result.code === 'github_rate_limited' && result.retryAfterSeconds) {
|
|
4678
|
+
console.log(pc.dim(`Try again in about ${result.retryAfterSeconds} seconds.`));
|
|
4679
|
+
}
|
|
4442
4680
|
process.exit(1);
|
|
4443
4681
|
}
|
|
4444
4682
|
// Success!
|
|
4683
|
+
const submittedCount = result.submitted ?? 0;
|
|
4684
|
+
const existingCount = result.existing ?? 0;
|
|
4445
4685
|
console.log();
|
|
4446
|
-
|
|
4447
|
-
|
|
4686
|
+
if (existingCount > 0 && submittedCount === 0) {
|
|
4687
|
+
console.log(pc.green('No new submission needed.'));
|
|
4688
|
+
}
|
|
4689
|
+
else {
|
|
4690
|
+
console.log(pc.green('Skill submitted successfully!'));
|
|
4691
|
+
}
|
|
4692
|
+
printSubmitMessage(result.message || 'It will appear in the catalog once processed.');
|
|
4693
|
+
if (result.existingSlug) {
|
|
4694
|
+
console.log();
|
|
4695
|
+
console.log(`View it at: ${pc.cyan(`${baseUrl}/skills/${result.existingSlug}`)}`);
|
|
4696
|
+
console.log(`Install with: ${pc.cyan(`skillscat add ${result.existingSlug}`)}`);
|
|
4697
|
+
}
|
|
4448
4698
|
}
|
|
4449
4699
|
catch (error) {
|
|
4450
4700
|
console.error(pc.red('Failed to connect to SkillsCat.'));
|
|
@@ -4455,6 +4705,60 @@ async function submit(urlArg, _options) {
|
|
|
4455
4705
|
}
|
|
4456
4706
|
}
|
|
4457
4707
|
|
|
4708
|
+
function normalizeReason(value) {
|
|
4709
|
+
if (!value)
|
|
4710
|
+
return null;
|
|
4711
|
+
const normalized = value.trim().toLowerCase();
|
|
4712
|
+
if (normalized === 'security' || normalized === 'copyright') {
|
|
4713
|
+
return normalized;
|
|
4714
|
+
}
|
|
4715
|
+
return null;
|
|
4716
|
+
}
|
|
4717
|
+
async function report(slug, options = {}) {
|
|
4718
|
+
const token = await getValidToken();
|
|
4719
|
+
if (!token) {
|
|
4720
|
+
error('Authentication required.');
|
|
4721
|
+
console.log(pc.dim('Run `skillscat login` first.'));
|
|
4722
|
+
process.exit(1);
|
|
4723
|
+
}
|
|
4724
|
+
let reason = normalizeReason(options.reason);
|
|
4725
|
+
if (!reason) {
|
|
4726
|
+
const answer = await prompt('Report reason [security/copyright]: ');
|
|
4727
|
+
reason = normalizeReason(answer);
|
|
4728
|
+
}
|
|
4729
|
+
if (!reason) {
|
|
4730
|
+
error('Invalid report reason. Use `security` or `copyright`.');
|
|
4731
|
+
process.exit(1);
|
|
4732
|
+
}
|
|
4733
|
+
const baseUrl = getBaseUrl();
|
|
4734
|
+
const response = await fetch(`${baseUrl}/api/skills/${encodeURIComponent(slug)}/report`, {
|
|
4735
|
+
method: 'POST',
|
|
4736
|
+
headers: {
|
|
4737
|
+
Authorization: `Bearer ${token}`,
|
|
4738
|
+
'Content-Type': 'application/json',
|
|
4739
|
+
Origin: baseUrl,
|
|
4740
|
+
'User-Agent': 'skillscat-cli/0.1.0',
|
|
4741
|
+
},
|
|
4742
|
+
body: JSON.stringify({
|
|
4743
|
+
reason,
|
|
4744
|
+
details: options.details || undefined,
|
|
4745
|
+
}),
|
|
4746
|
+
});
|
|
4747
|
+
const payload = await response.json();
|
|
4748
|
+
if (!response.ok || !payload.success) {
|
|
4749
|
+
error(payload.error || payload.message || 'Failed to submit report');
|
|
4750
|
+
process.exit(1);
|
|
4751
|
+
}
|
|
4752
|
+
success(payload.message || 'Report submitted');
|
|
4753
|
+
if (reason === 'security' && payload.report) {
|
|
4754
|
+
console.log(` Open security reports: ${pc.cyan(String(payload.report.openSecurityReportCount))}`);
|
|
4755
|
+
console.log(` Risk level: ${pc.cyan(payload.report.riskLevel)}`);
|
|
4756
|
+
if (payload.report.premiumEscalated) {
|
|
4757
|
+
console.log(` ${pc.yellow('Premium review queued')}`);
|
|
4758
|
+
}
|
|
4759
|
+
}
|
|
4760
|
+
}
|
|
4761
|
+
|
|
4458
4762
|
/**
|
|
4459
4763
|
* Find skill by slug using two-segment path
|
|
4460
4764
|
*/
|
|
@@ -4548,6 +4852,208 @@ async function unpublishSkill(slug, options) {
|
|
|
4548
4852
|
}
|
|
4549
4853
|
}
|
|
4550
4854
|
|
|
4855
|
+
function hasCommand(command) {
|
|
4856
|
+
const trimmed = command.trim();
|
|
4857
|
+
if (!trimmed) {
|
|
4858
|
+
return false;
|
|
4859
|
+
}
|
|
4860
|
+
const lookupCommand = process.platform === 'win32' ? 'where' : 'which';
|
|
4861
|
+
const result = spawnSync(lookupCommand, [trimmed], {
|
|
4862
|
+
stdio: 'ignore',
|
|
4863
|
+
});
|
|
4864
|
+
return result.status === 0;
|
|
4865
|
+
}
|
|
4866
|
+
function getEnvBrowserCommand(url) {
|
|
4867
|
+
const rawBrowser = process.env.BROWSER?.trim();
|
|
4868
|
+
if (!rawBrowser || rawBrowser.toLowerCase() === 'none') {
|
|
4869
|
+
return null;
|
|
4870
|
+
}
|
|
4871
|
+
const [command, ...rawArgs] = rawBrowser.split(/\s+/);
|
|
4872
|
+
if (!command) {
|
|
4873
|
+
return null;
|
|
4874
|
+
}
|
|
4875
|
+
let replacedUrl = false;
|
|
4876
|
+
const args = rawArgs.map((arg) => {
|
|
4877
|
+
if (!arg.includes('%s')) {
|
|
4878
|
+
return arg;
|
|
4879
|
+
}
|
|
4880
|
+
replacedUrl = true;
|
|
4881
|
+
return arg.replace(/%s/g, url);
|
|
4882
|
+
});
|
|
4883
|
+
if (!replacedUrl) {
|
|
4884
|
+
args.push(url);
|
|
4885
|
+
}
|
|
4886
|
+
return { command, args };
|
|
4887
|
+
}
|
|
4888
|
+
function getDefaultBrowserCommand(url) {
|
|
4889
|
+
if (process.platform === 'darwin') {
|
|
4890
|
+
return { command: 'open', args: [url] };
|
|
4891
|
+
}
|
|
4892
|
+
if (process.platform === 'win32') {
|
|
4893
|
+
return { command: 'rundll32', args: ['url.dll,FileProtocolHandler', url] };
|
|
4894
|
+
}
|
|
4895
|
+
if ((process.env.WSL_DISTRO_NAME || process.env.WSL_INTEROP) && hasCommand('wslview')) {
|
|
4896
|
+
return { command: 'wslview', args: [url] };
|
|
4897
|
+
}
|
|
4898
|
+
return { command: 'xdg-open', args: [url] };
|
|
4899
|
+
}
|
|
4900
|
+
function getBrowserCommand(url) {
|
|
4901
|
+
return getEnvBrowserCommand(url) || getDefaultBrowserCommand(url);
|
|
4902
|
+
}
|
|
4903
|
+
function hasBrowserEnvironment() {
|
|
4904
|
+
const rawBrowser = process.env.BROWSER?.trim();
|
|
4905
|
+
if (rawBrowser?.toLowerCase() === 'none') {
|
|
4906
|
+
return false;
|
|
4907
|
+
}
|
|
4908
|
+
if (rawBrowser) {
|
|
4909
|
+
return true;
|
|
4910
|
+
}
|
|
4911
|
+
if (process.env.CI) {
|
|
4912
|
+
return false;
|
|
4913
|
+
}
|
|
4914
|
+
if (process.platform === 'linux') {
|
|
4915
|
+
if (process.env.WSL_DISTRO_NAME || process.env.WSL_INTEROP) {
|
|
4916
|
+
return true;
|
|
4917
|
+
}
|
|
4918
|
+
return Boolean(process.env.DISPLAY || process.env.WAYLAND_DISPLAY);
|
|
4919
|
+
}
|
|
4920
|
+
return true;
|
|
4921
|
+
}
|
|
4922
|
+
function canOpenUrlInBrowser() {
|
|
4923
|
+
if (!hasBrowserEnvironment()) {
|
|
4924
|
+
return false;
|
|
4925
|
+
}
|
|
4926
|
+
return hasCommand(getBrowserCommand('https://skills.cat').command);
|
|
4927
|
+
}
|
|
4928
|
+
async function openUrlInBrowser(url) {
|
|
4929
|
+
if (!canOpenUrlInBrowser()) {
|
|
4930
|
+
return false;
|
|
4931
|
+
}
|
|
4932
|
+
const browserCommand = getBrowserCommand(url);
|
|
4933
|
+
return new Promise((resolve) => {
|
|
4934
|
+
execFile(browserCommand.command, browserCommand.args, (err) => {
|
|
4935
|
+
resolve(!err);
|
|
4936
|
+
});
|
|
4937
|
+
});
|
|
4938
|
+
}
|
|
4939
|
+
|
|
4940
|
+
class ViewHttpError extends Error {
|
|
4941
|
+
}
|
|
4942
|
+
function normalizeOutputFormat(output) {
|
|
4943
|
+
if (!output) {
|
|
4944
|
+
return null;
|
|
4945
|
+
}
|
|
4946
|
+
const normalized = output.trim().toLowerCase();
|
|
4947
|
+
if (normalized === 'html' || normalized === 'markdown') {
|
|
4948
|
+
return normalized;
|
|
4949
|
+
}
|
|
4950
|
+
return null;
|
|
4951
|
+
}
|
|
4952
|
+
function getSiteBaseUrl() {
|
|
4953
|
+
const registryUrl = getRegistryUrl();
|
|
4954
|
+
try {
|
|
4955
|
+
const parsed = new URL(registryUrl);
|
|
4956
|
+
const pathname = parsed.pathname.replace(/\/+$/, '');
|
|
4957
|
+
const strippedPathname = pathname.endsWith('/registry')
|
|
4958
|
+
? pathname.slice(0, -'/registry'.length)
|
|
4959
|
+
: pathname.endsWith('/openclaw')
|
|
4960
|
+
? pathname.slice(0, -'/openclaw'.length)
|
|
4961
|
+
: pathname;
|
|
4962
|
+
return `${parsed.protocol}//${parsed.host}${strippedPathname}`;
|
|
4963
|
+
}
|
|
4964
|
+
catch {
|
|
4965
|
+
return registryUrl.replace(/\/(?:registry|openclaw)\/?$/, '');
|
|
4966
|
+
}
|
|
4967
|
+
}
|
|
4968
|
+
function buildSkillUrl(slug) {
|
|
4969
|
+
return `${getSiteBaseUrl()}${buildSkillPath(slug)}`;
|
|
4970
|
+
}
|
|
4971
|
+
async function buildViewHeaders(output) {
|
|
4972
|
+
const token = await getValidToken();
|
|
4973
|
+
const headers = {
|
|
4974
|
+
'User-Agent': output === 'markdown'
|
|
4975
|
+
? 'skillscat-cli/0.1.0 OpenClaw/1.0'
|
|
4976
|
+
: 'skillscat-cli/0.1.0',
|
|
4977
|
+
Accept: output === 'markdown'
|
|
4978
|
+
? 'text/markdown, text/plain;q=0.9, */*;q=0.8'
|
|
4979
|
+
: 'text/html,application/xhtml+xml;q=0.9,*/*;q=0.8',
|
|
4980
|
+
};
|
|
4981
|
+
if (token) {
|
|
4982
|
+
headers.Authorization = `Bearer ${token}`;
|
|
4983
|
+
}
|
|
4984
|
+
return headers;
|
|
4985
|
+
}
|
|
4986
|
+
async function fetchSkillDocument(slug, output) {
|
|
4987
|
+
const url = buildSkillUrl(slug);
|
|
4988
|
+
const headers = await buildViewHeaders(output);
|
|
4989
|
+
const startTime = Date.now();
|
|
4990
|
+
verboseRequest('GET', url, headers);
|
|
4991
|
+
try {
|
|
4992
|
+
const response = await fetch(url, { headers });
|
|
4993
|
+
verboseResponse(response.status, response.statusText, Date.now() - startTime);
|
|
4994
|
+
if (!response.ok) {
|
|
4995
|
+
const httpError = parseHttpError(response.status, response.statusText);
|
|
4996
|
+
throw new ViewHttpError(httpError.message);
|
|
4997
|
+
}
|
|
4998
|
+
return response.text();
|
|
4999
|
+
}
|
|
5000
|
+
catch (err) {
|
|
5001
|
+
if (!(err instanceof ViewHttpError)) {
|
|
5002
|
+
const networkError = parseNetworkError(err);
|
|
5003
|
+
throw new Error(networkError.message);
|
|
5004
|
+
}
|
|
5005
|
+
throw err;
|
|
5006
|
+
}
|
|
5007
|
+
}
|
|
5008
|
+
function writeOutput(body) {
|
|
5009
|
+
console.log(body);
|
|
5010
|
+
}
|
|
5011
|
+
async function view(slug, options = {}) {
|
|
5012
|
+
try {
|
|
5013
|
+
parseSlug(slug);
|
|
5014
|
+
}
|
|
5015
|
+
catch {
|
|
5016
|
+
error('Invalid slug. Expected format: owner/name');
|
|
5017
|
+
process.exit(1);
|
|
5018
|
+
}
|
|
5019
|
+
if (options.output) {
|
|
5020
|
+
const output = normalizeOutputFormat(options.output);
|
|
5021
|
+
if (!output) {
|
|
5022
|
+
error('Invalid output format. Use `html` or `markdown`.');
|
|
5023
|
+
process.exit(1);
|
|
5024
|
+
}
|
|
5025
|
+
try {
|
|
5026
|
+
const body = await fetchSkillDocument(slug, output);
|
|
5027
|
+
writeOutput(body);
|
|
5028
|
+
return;
|
|
5029
|
+
}
|
|
5030
|
+
catch (err) {
|
|
5031
|
+
error(err instanceof Error ? err.message : 'Failed to fetch skill view');
|
|
5032
|
+
process.exit(1);
|
|
5033
|
+
}
|
|
5034
|
+
}
|
|
5035
|
+
const url = buildSkillUrl(slug);
|
|
5036
|
+
if (canOpenUrlInBrowser()) {
|
|
5037
|
+
const opened = await openUrlInBrowser(url);
|
|
5038
|
+
if (opened) {
|
|
5039
|
+
info$1(`Opened ${slug} in your browser.`);
|
|
5040
|
+
return;
|
|
5041
|
+
}
|
|
5042
|
+
warn('Unable to open a browser automatically. Printing markdown instead.');
|
|
5043
|
+
}
|
|
5044
|
+
else {
|
|
5045
|
+
warn('No browser environment detected. Printing markdown instead.');
|
|
5046
|
+
}
|
|
5047
|
+
try {
|
|
5048
|
+
const markdown = await fetchSkillDocument(slug, 'markdown');
|
|
5049
|
+
writeOutput(markdown);
|
|
5050
|
+
}
|
|
5051
|
+
catch (err) {
|
|
5052
|
+
error(err instanceof Error ? err.message : 'Failed to fetch skill view');
|
|
5053
|
+
process.exit(1);
|
|
5054
|
+
}
|
|
5055
|
+
}
|
|
5056
|
+
|
|
4551
5057
|
const DEFAULT_REGISTRY_URL = 'https://skills.cat/registry';
|
|
4552
5058
|
const VALID_KEYS = ['registry'];
|
|
4553
5059
|
async function configSet(key, value, options = {}) {
|
|
@@ -4639,7 +5145,8 @@ program
|
|
|
4639
5145
|
.alias('i')
|
|
4640
5146
|
.description('Add a skill from a repository')
|
|
4641
5147
|
.option('-g, --global', 'Install to user directory instead of project')
|
|
4642
|
-
.option('-a, --agent <agents...>', 'Target specific agents (e.g., claude-code, cursor)')
|
|
5148
|
+
.option('-a, --agent <agents...>', 'Target specific agents (e.g., claude-code, cursor, agents)')
|
|
5149
|
+
.option('-r, --repo', 'Treat <source> as a repository instead of an exact published skill slug')
|
|
4643
5150
|
.option('-s, --skill <skills...>', 'Install specific skills by name')
|
|
4644
5151
|
.option('-l, --list', 'List available skills without installing')
|
|
4645
5152
|
.option('-y, --yes', 'Skip confirmation prompts')
|
|
@@ -4671,6 +5178,14 @@ program
|
|
|
4671
5178
|
.option('-a, --agent <agents...>', 'Update for specific agents')
|
|
4672
5179
|
.option('--check', 'Check for updates without installing')
|
|
4673
5180
|
.action(update);
|
|
5181
|
+
program
|
|
5182
|
+
.command('convert <agent>')
|
|
5183
|
+
.alias('sync')
|
|
5184
|
+
.description('Copy skills from .agents into a specific agent directory')
|
|
5185
|
+
.option('--from <agent>', 'Source agent directory to copy from', 'agents')
|
|
5186
|
+
.option('-g, --global', 'Copy from user directory instead of project')
|
|
5187
|
+
.option('-f, --force', 'Overwrite existing skills in the target directory')
|
|
5188
|
+
.action(convert);
|
|
4674
5189
|
// Self-upgrade command
|
|
4675
5190
|
program
|
|
4676
5191
|
.command('self-upgrade')
|
|
@@ -4690,6 +5205,12 @@ program
|
|
|
4690
5205
|
.command('info <source>')
|
|
4691
5206
|
.description('Show detailed information about a skill or repository')
|
|
4692
5207
|
.action(info);
|
|
5208
|
+
// View command
|
|
5209
|
+
program
|
|
5210
|
+
.command('view <slug>')
|
|
5211
|
+
.description('Open a published skill in the browser or print its rendered output')
|
|
5212
|
+
.option('-o, --output <format>', 'Print `html` or `markdown` to stdout instead of opening a browser')
|
|
5213
|
+
.action(view);
|
|
4693
5214
|
// Login command
|
|
4694
5215
|
program
|
|
4695
5216
|
.command('login')
|
|
@@ -4721,6 +5242,12 @@ program
|
|
|
4721
5242
|
.command('submit [url]')
|
|
4722
5243
|
.description('Submit a GitHub repository to SkillsCat registry')
|
|
4723
5244
|
.action(submit);
|
|
5245
|
+
program
|
|
5246
|
+
.command('report <slug>')
|
|
5247
|
+
.description('Report a skill for security or copyright concerns')
|
|
5248
|
+
.option('-r, --reason <reason>', 'Report reason (security or copyright)')
|
|
5249
|
+
.option('-d, --details <details>', 'Optional report details')
|
|
5250
|
+
.action(report);
|
|
4724
5251
|
// Unpublish command
|
|
4725
5252
|
program
|
|
4726
5253
|
.command('unpublish <slug>')
|
|
@@ -3,12 +3,17 @@ export interface Agent {
|
|
|
3
3
|
name: string;
|
|
4
4
|
projectPath: string;
|
|
5
5
|
globalPath: string;
|
|
6
|
+
aliases?: string[];
|
|
6
7
|
}
|
|
8
|
+
export declare const FALLBACK_AGENT_ID = "agents";
|
|
7
9
|
export declare const AGENTS: Agent[];
|
|
10
|
+
export declare function getAgentBasePath(agent: Agent, global: boolean, cwd?: string): string;
|
|
8
11
|
/**
|
|
9
12
|
* Detect which agents are installed by checking for their config directories
|
|
10
13
|
*/
|
|
11
14
|
export declare function detectInstalledAgents(): Agent[];
|
|
15
|
+
export declare function detectProjectAgents(cwd?: string): Agent[];
|
|
16
|
+
export declare function detectPreferredAgents(global: boolean, cwd?: string): Agent[];
|
|
12
17
|
/**
|
|
13
18
|
* Get agent by ID
|
|
14
19
|
*/
|
|
@@ -17,8 +22,9 @@ export declare function getAgentById(id: string): Agent | undefined;
|
|
|
17
22
|
* Get agents by IDs
|
|
18
23
|
*/
|
|
19
24
|
export declare function getAgentsByIds(ids: string[]): Agent[];
|
|
25
|
+
export declare function getFallbackAgent(): Agent;
|
|
20
26
|
/**
|
|
21
27
|
* Get skill installation path for an agent
|
|
22
28
|
*/
|
|
23
|
-
export declare function getSkillPath(agent: Agent, skillName: string, global: boolean): string;
|
|
29
|
+
export declare function getSkillPath(agent: Agent, skillName: string, global: boolean, cwd?: string): string;
|
|
24
30
|
//# sourceMappingURL=agents.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agents.d.ts","sourceRoot":"","sources":["../../../src/utils/agents/agents.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,KAAK;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACpB;
|
|
1
|
+
{"version":3,"file":"agents.d.ts","sourceRoot":"","sources":["../../../src/utils/agents/agents.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,KAAK;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,eAAO,MAAM,iBAAiB,WAAW,CAAC;AAmB1C,eAAO,MAAM,MAAM,EAAE,KAAK,EAgIzB,CAAC;AAYF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,SAAgB,GAAG,MAAM,CAE3F;AAED;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,KAAK,EAAE,CAK/C;AAED,wBAAgB,mBAAmB,CAAC,GAAG,SAAgB,GAAG,KAAK,EAAE,CAEhE;AAOD,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,SAAgB,GAAG,KAAK,EAAE,CAanF;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,KAAK,GAAG,SAAS,CAK1D;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,KAAK,EAAE,CAErD;AAED,wBAAgB,gBAAgB,IAAI,KAAK,CAMxC;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,SAAgB,GAAG,MAAM,CAG1G"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../../../src/utils/core/browser.ts"],"names":[],"mappings":"AA8FA,wBAAgB,mBAAmB,IAAI,OAAO,CAM7C;AAED,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAYpE"}
|
|
@@ -14,4 +14,16 @@ export declare function parseSlug(slug: string): {
|
|
|
14
14
|
* @returns Path segment like "owner/name" (without leading slash)
|
|
15
15
|
*/
|
|
16
16
|
export declare function slugToPath(slug: string): string;
|
|
17
|
+
/**
|
|
18
|
+
* Encode a slug for use in /skills/[owner]/[...name] paths
|
|
19
|
+
* @param slug - Skill slug in format "owner/name[/nested]"
|
|
20
|
+
* @returns Encoded path segment like "owner/name" (without leading slash)
|
|
21
|
+
*/
|
|
22
|
+
export declare function encodeSlugForSkillPath(slug: string): string;
|
|
23
|
+
/**
|
|
24
|
+
* Build the canonical web skill path from a slug
|
|
25
|
+
* @param slug - Skill slug in format "owner/name[/nested]"
|
|
26
|
+
* @returns Path like "/skills/owner/name"
|
|
27
|
+
*/
|
|
28
|
+
export declare function buildSkillPath(slug: string): string;
|
|
17
29
|
//# sourceMappingURL=slug.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"slug.d.ts","sourceRoot":"","sources":["../../../src/utils/core/slug.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAMvE;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAG/C"}
|
|
1
|
+
{"version":3,"file":"slug.d.ts","sourceRoot":"","sources":["../../../src/utils/core/slug.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAMvE;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAG/C;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQ3D;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEnD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../../../src/utils/source/git.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,kBAAkB,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAW1E,UAAU,cAAc;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IACtB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AA6BD,MAAM,WAAW,kBAAkB;IACjC,OAAO,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC;IACrC,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAC7B,OAAO,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC;IACrC,UAAU,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC,CAAC;IACnD,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;IAC1D,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAChD,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACnE,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CACnE;AAkHD,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,UAAU,GAAG,kBAAkB,GAAG,IAAI,CAKtF;AAwRD;;GAEG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,UAAU,EAClB,OAAO,CAAC,EAAE;IAAE,cAAc,CAAC,EAAE,kBAAkB,GAAG,IAAI,CAAA;CAAE,GACvD,OAAO,CAAC,SAAS,EAAE,CAAC,CAgHtB;AAED,wBAAsB,wBAAwB,CAAC,MAAM,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAEvH;AAED,wBAAsB,mCAAmC,CACvD,MAAM,EAAE,UAAU,EAClB,aAAa,EAAE,MAAM,EACrB,OAAO,CAAC,EAAE;IAAE,cAAc,CAAC,EAAE,kBAAkB,GAAG,IAAI,CAAA;CAAE,GACvD,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAmB/B;
|
|
1
|
+
{"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../../../src/utils/source/git.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,kBAAkB,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAW1E,UAAU,cAAc;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IACtB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AA6BD,MAAM,WAAW,kBAAkB;IACjC,OAAO,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC;IACrC,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAC7B,OAAO,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC;IACrC,UAAU,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC,CAAC;IACnD,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAAC;IAC1D,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAChD,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACnE,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CACnE;AAkHD,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,UAAU,GAAG,kBAAkB,GAAG,IAAI,CAKtF;AAwRD;;GAEG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,UAAU,EAClB,OAAO,CAAC,EAAE;IAAE,cAAc,CAAC,EAAE,kBAAkB,GAAG,IAAI,CAAA;CAAE,GACvD,OAAO,CAAC,SAAS,EAAE,CAAC,CAgHtB;AAED,wBAAsB,wBAAwB,CAAC,MAAM,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAEvH;AAED,wBAAsB,mCAAmC,CACvD,MAAM,EAAE,UAAU,EAClB,aAAa,EAAE,MAAM,EACrB,OAAO,CAAC,EAAE;IAAE,cAAc,CAAC,EAAE,kBAAkB,GAAG,IAAI,CAAA;CAAE,GACvD,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAmB/B;AAmID;;GAEG;AACH,wBAAsB,UAAU,CAAC,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAGjG;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,UAAU,EAClB,SAAS,EAAE,MAAM,EACjB,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC;IAAE,SAAS,EAAE,OAAO,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAYrD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"source.d.ts","sourceRoot":"","sources":["../../../src/utils/source/source.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAE3C,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,QAAQ,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC1B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,kBAAkB,EAAE,CAAC;IACtC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,UAAU,CAAC;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAiF7D;AAED;;GAEG;AACH,eAAO,MAAM,qBAAqB,
|
|
1
|
+
{"version":3,"file":"source.d.ts","sourceRoot":"","sources":["../../../src/utils/source/source.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAE3C,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,QAAQ,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC1B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,kBAAkB,EAAE,CAAC;IACtC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,UAAU,CAAC;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAiF7D;AAED;;GAEG;AACH,eAAO,MAAM,qBAAqB,UAqBjC,CAAC;AAEF;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAgC3E"}
|
|
@@ -12,6 +12,7 @@ export interface InstalledSkill {
|
|
|
12
12
|
sha?: string;
|
|
13
13
|
path: string;
|
|
14
14
|
contentHash?: string;
|
|
15
|
+
installRoot?: string;
|
|
15
16
|
}
|
|
16
17
|
export interface InstalledSkillsDb {
|
|
17
18
|
version: number;
|
|
@@ -28,7 +29,13 @@ export declare function removeInstallation(skillName: string, options?: {
|
|
|
28
29
|
source?: RepoSource;
|
|
29
30
|
agents?: string[];
|
|
30
31
|
global?: boolean;
|
|
32
|
+
installRoot?: string;
|
|
31
33
|
}): void;
|
|
34
|
+
export declare function copyInstallationAgent(sourceAgentId: string, targetAgentId: string, options?: {
|
|
35
|
+
global?: boolean;
|
|
36
|
+
installRoot?: string;
|
|
37
|
+
sourceSkillDirs?: string[];
|
|
38
|
+
}): number;
|
|
32
39
|
/**
|
|
33
40
|
* Get all installed skills
|
|
34
41
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../../src/utils/storage/db.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../../src/utils/storage/db.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAGnD,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,UAAU,CAAC;AAEhD,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,cAAc,EAAE,CAAC;CAC1B;AAgND;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI,CAe9D;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE;IACR,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,GACA,IAAI,CAmCN;AAED,wBAAgB,qBAAqB,CACnC,aAAa,EAAE,MAAM,EACrB,aAAa,EAAE,MAAM,EACrB,OAAO,CAAC,EAAE;IACR,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;CAC5B,GACA,MAAM,CAwDR;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,cAAc,EAAE,CAGrD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CAG/E;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,UAAU,GAAG,OAAO,CAUhF;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,cAAc,EAAE,EAAE,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,cAAc,EAAE,CAK/G"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "skillscat",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "CLI for installing AI agent skills from SkillsCat registry",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -14,7 +14,10 @@
|
|
|
14
14
|
"dev": "rollup -c -w",
|
|
15
15
|
"typecheck": "tsc --noEmit",
|
|
16
16
|
"prepublishOnly": "npm run build",
|
|
17
|
-
"test": "
|
|
17
|
+
"test": "pnpm run test:unit",
|
|
18
|
+
"test:unit": "vitest run --config vitest.unit.config.ts",
|
|
19
|
+
"test:preview": "vitest run --config vitest.config.ts",
|
|
20
|
+
"test:all": "pnpm run test:unit && pnpm run test:preview"
|
|
18
21
|
},
|
|
19
22
|
"dependencies": {
|
|
20
23
|
"commander": "^12.1.0",
|