@anytio/pspm 0.8.0 → 0.9.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/CHANGELOG.md +33 -0
- package/README.md +370 -187
- package/dist/index.js +1033 -69
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -74,7 +74,7 @@ var init_fetcher = __esm({
|
|
|
74
74
|
});
|
|
75
75
|
|
|
76
76
|
// src/sdk/generated/index.ts
|
|
77
|
-
var getMeUrl, me, getDeleteSkillUrl, deleteSkill, getListSkillVersionsUrl, listSkillVersions, getGetSkillVersionUrl, getSkillVersion, getDeleteSkillVersionUrl, deleteSkillVersion, getPublishSkillUrl, publishSkill;
|
|
77
|
+
var getMeUrl, me, getExplorePublicSkillsUrl, explorePublicSkills, getDeleteSkillUrl, deleteSkill, getListSkillVersionsUrl, listSkillVersions, getGetSkillVersionUrl, getSkillVersion, getDeleteSkillVersionUrl, deleteSkillVersion, getPublishSkillUrl, publishSkill;
|
|
78
78
|
var init_generated = __esm({
|
|
79
79
|
"src/sdk/generated/index.ts"() {
|
|
80
80
|
init_fetcher();
|
|
@@ -90,6 +90,25 @@ var init_generated = __esm({
|
|
|
90
90
|
}
|
|
91
91
|
);
|
|
92
92
|
};
|
|
93
|
+
getExplorePublicSkillsUrl = (params) => {
|
|
94
|
+
const normalizedParams = new URLSearchParams();
|
|
95
|
+
Object.entries(params || {}).forEach(([key, value]) => {
|
|
96
|
+
if (value !== void 0) {
|
|
97
|
+
normalizedParams.append(key, value === null ? "null" : value.toString());
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
const stringifiedParams = normalizedParams.toString();
|
|
101
|
+
return stringifiedParams.length > 0 ? `/api/skills/-/explore?${stringifiedParams}` : `/api/skills/-/explore`;
|
|
102
|
+
};
|
|
103
|
+
explorePublicSkills = async (params, options) => {
|
|
104
|
+
return customFetch(
|
|
105
|
+
getExplorePublicSkillsUrl(params),
|
|
106
|
+
{
|
|
107
|
+
...options,
|
|
108
|
+
method: "GET"
|
|
109
|
+
}
|
|
110
|
+
);
|
|
111
|
+
};
|
|
93
112
|
getDeleteSkillUrl = (username, name) => {
|
|
94
113
|
return `/api/skills/@user/${username}/${name}`;
|
|
95
114
|
};
|
|
@@ -368,22 +387,54 @@ var init_errors = __esm({
|
|
|
368
387
|
};
|
|
369
388
|
}
|
|
370
389
|
});
|
|
390
|
+
|
|
391
|
+
// src/config.ts
|
|
392
|
+
var config_exports = {};
|
|
393
|
+
__export(config_exports, {
|
|
394
|
+
clearCredentials: () => clearCredentials,
|
|
395
|
+
findProjectConfig: () => findProjectConfig,
|
|
396
|
+
getCacheDir: () => getCacheDir,
|
|
397
|
+
getConfigPath: () => getConfigPath,
|
|
398
|
+
getLegacyLockfilePath: () => getLegacyLockfilePath,
|
|
399
|
+
getLegacySkillsDir: () => getLegacySkillsDir,
|
|
400
|
+
getLockfilePath: () => getLockfilePath,
|
|
401
|
+
getPspmDir: () => getPspmDir,
|
|
402
|
+
getRegistryUrl: () => getRegistryUrl,
|
|
403
|
+
getSkillsDir: () => getSkillsDir,
|
|
404
|
+
getTokenForRegistry: () => getTokenForRegistry,
|
|
405
|
+
isGlobalMode: () => isGlobalMode,
|
|
406
|
+
isLoggedIn: () => isLoggedIn,
|
|
407
|
+
readUserConfig: () => readUserConfig,
|
|
408
|
+
requireApiKey: () => requireApiKey,
|
|
409
|
+
resolveConfig: () => resolveConfig,
|
|
410
|
+
setCredentials: () => setCredentials,
|
|
411
|
+
setGlobalMode: () => setGlobalMode,
|
|
412
|
+
writeUserConfig: () => writeUserConfig
|
|
413
|
+
});
|
|
371
414
|
function getConfigPath() {
|
|
372
415
|
return join(homedir(), ".pspmrc");
|
|
373
416
|
}
|
|
374
417
|
function getLegacyConfigPath() {
|
|
375
418
|
return join(homedir(), ".pspm", "config.json");
|
|
376
419
|
}
|
|
420
|
+
function setGlobalMode(global) {
|
|
421
|
+
_globalMode = global;
|
|
422
|
+
}
|
|
423
|
+
function isGlobalMode() {
|
|
424
|
+
return _globalMode;
|
|
425
|
+
}
|
|
377
426
|
function getPspmDir() {
|
|
427
|
+
if (_globalMode) return join(homedir(), ".pspm");
|
|
378
428
|
return join(process.cwd(), ".pspm");
|
|
379
429
|
}
|
|
380
430
|
function getSkillsDir() {
|
|
381
|
-
return join(
|
|
431
|
+
return join(getPspmDir(), "skills");
|
|
382
432
|
}
|
|
383
433
|
function getCacheDir() {
|
|
384
|
-
return join(
|
|
434
|
+
return join(getPspmDir(), "cache");
|
|
385
435
|
}
|
|
386
436
|
function getLockfilePath() {
|
|
437
|
+
if (_globalMode) return join(homedir(), ".pspm", "pspm-lock.json");
|
|
387
438
|
return join(process.cwd(), "pspm-lock.json");
|
|
388
439
|
}
|
|
389
440
|
function getLegacyLockfilePath() {
|
|
@@ -637,11 +688,12 @@ async function getRegistryUrl() {
|
|
|
637
688
|
const resolved = await resolveConfig();
|
|
638
689
|
return resolved.registryUrl;
|
|
639
690
|
}
|
|
640
|
-
var DEFAULT_REGISTRY_URL;
|
|
691
|
+
var DEFAULT_REGISTRY_URL, _globalMode;
|
|
641
692
|
var init_config = __esm({
|
|
642
693
|
"src/config.ts"() {
|
|
643
694
|
init_errors();
|
|
644
695
|
DEFAULT_REGISTRY_URL = "https://registry.pspm.dev";
|
|
696
|
+
_globalMode = false;
|
|
645
697
|
}
|
|
646
698
|
});
|
|
647
699
|
async function loadIgnorePatterns(cwd = process.cwd()) {
|
|
@@ -1130,11 +1182,57 @@ function getGitHubSkillName(spec) {
|
|
|
1130
1182
|
function isGitHubSpecifier(specifier) {
|
|
1131
1183
|
return specifier.startsWith("github:");
|
|
1132
1184
|
}
|
|
1133
|
-
|
|
1185
|
+
function isGitHubUrl(input) {
|
|
1186
|
+
return /^https?:\/\/github\.com\/[^/]+\/[^/]+/.test(input);
|
|
1187
|
+
}
|
|
1188
|
+
function parseGitHubUrl(input) {
|
|
1189
|
+
const treeMatch = input.match(GITHUB_URL_TREE_PATTERN);
|
|
1190
|
+
if (treeMatch) {
|
|
1191
|
+
const [, owner, repo, ref, path] = treeMatch;
|
|
1192
|
+
if (!owner || !repo || !ref) return null;
|
|
1193
|
+
return {
|
|
1194
|
+
owner,
|
|
1195
|
+
repo,
|
|
1196
|
+
ref,
|
|
1197
|
+
path: path || void 0
|
|
1198
|
+
};
|
|
1199
|
+
}
|
|
1200
|
+
const repoMatch = input.match(GITHUB_URL_PATTERN);
|
|
1201
|
+
if (repoMatch) {
|
|
1202
|
+
const [, owner, repo] = repoMatch;
|
|
1203
|
+
if (!owner || !repo) return null;
|
|
1204
|
+
return { owner, repo };
|
|
1205
|
+
}
|
|
1206
|
+
return null;
|
|
1207
|
+
}
|
|
1208
|
+
function isGitHubShorthand(input) {
|
|
1209
|
+
if (input.includes(":") || input.startsWith(".") || input.startsWith("/") || input.startsWith("@")) {
|
|
1210
|
+
return false;
|
|
1211
|
+
}
|
|
1212
|
+
return GITHUB_SHORTHAND_PATTERN.test(input);
|
|
1213
|
+
}
|
|
1214
|
+
function parseGitHubShorthand(input) {
|
|
1215
|
+
if (input.includes(":") || input.startsWith(".") || input.startsWith("/") || input.startsWith("@")) {
|
|
1216
|
+
return null;
|
|
1217
|
+
}
|
|
1218
|
+
const match = input.match(GITHUB_SHORTHAND_PATTERN);
|
|
1219
|
+
if (!match) return null;
|
|
1220
|
+
const [, owner, repo, path] = match;
|
|
1221
|
+
if (!owner || !repo) return null;
|
|
1222
|
+
return {
|
|
1223
|
+
owner,
|
|
1224
|
+
repo,
|
|
1225
|
+
path: path || void 0
|
|
1226
|
+
};
|
|
1227
|
+
}
|
|
1228
|
+
var SPECIFIER_PATTERN, GITHUB_SPECIFIER_PATTERN, GITHUB_URL_TREE_PATTERN, GITHUB_URL_PATTERN, GITHUB_SHORTHAND_PATTERN;
|
|
1134
1229
|
var init_specifier = __esm({
|
|
1135
1230
|
"src/lib/specifier.ts"() {
|
|
1136
1231
|
SPECIFIER_PATTERN = /^@user\/([a-zA-Z0-9_-]+)\/([a-z][a-z0-9_-]*)(?:@(.+))?$/;
|
|
1137
1232
|
GITHUB_SPECIFIER_PATTERN = /^github:([a-zA-Z0-9_-]+)\/([a-zA-Z0-9_.-]+)(\/[^@]+)?(?:@(.+))?$/;
|
|
1233
|
+
GITHUB_URL_TREE_PATTERN = /^https?:\/\/github\.com\/([^/]+)\/([^/]+)\/tree\/([^/]+)(?:\/(.+))?$/;
|
|
1234
|
+
GITHUB_URL_PATTERN = /^https?:\/\/github\.com\/([^/]+)\/([^/]+?)(?:\.git)?\/?$/;
|
|
1235
|
+
GITHUB_SHORTHAND_PATTERN = /^([a-zA-Z0-9_-]+)\/([a-zA-Z0-9_.-]+)(?:\/(.+))?$/;
|
|
1138
1236
|
}
|
|
1139
1237
|
});
|
|
1140
1238
|
|
|
@@ -1150,12 +1248,15 @@ var init_lib = __esm({
|
|
|
1150
1248
|
init_version();
|
|
1151
1249
|
}
|
|
1152
1250
|
});
|
|
1153
|
-
function resolveAgentConfig(name, overrides) {
|
|
1154
|
-
if (overrides?.[name]) {
|
|
1251
|
+
function resolveAgentConfig(name, overrides, global) {
|
|
1252
|
+
if (!global && overrides?.[name]) {
|
|
1155
1253
|
return overrides[name];
|
|
1156
1254
|
}
|
|
1157
|
-
if (name in
|
|
1158
|
-
|
|
1255
|
+
if (name in AGENT_INFO) {
|
|
1256
|
+
const info = AGENT_INFO[name];
|
|
1257
|
+
return {
|
|
1258
|
+
skillsDir: global ? info.globalSkillsDir : info.skillsDir
|
|
1259
|
+
};
|
|
1159
1260
|
}
|
|
1160
1261
|
return null;
|
|
1161
1262
|
}
|
|
@@ -1193,47 +1294,221 @@ var AGENT_INFO, DEFAULT_AGENT_CONFIGS, ALL_AGENTS;
|
|
|
1193
1294
|
var init_agents = __esm({
|
|
1194
1295
|
"src/agents.ts"() {
|
|
1195
1296
|
AGENT_INFO = {
|
|
1297
|
+
adal: {
|
|
1298
|
+
displayName: "AdaL",
|
|
1299
|
+
skillsDir: ".adal/skills",
|
|
1300
|
+
globalSkillsDir: ".adal/skills"
|
|
1301
|
+
},
|
|
1302
|
+
amp: {
|
|
1303
|
+
displayName: "Amp",
|
|
1304
|
+
skillsDir: ".agents/skills",
|
|
1305
|
+
globalSkillsDir: ".config/agents/skills"
|
|
1306
|
+
},
|
|
1307
|
+
antigravity: {
|
|
1308
|
+
displayName: "Antigravity",
|
|
1309
|
+
skillsDir: ".agent/skills",
|
|
1310
|
+
globalSkillsDir: ".gemini/antigravity/skills"
|
|
1311
|
+
},
|
|
1312
|
+
augment: {
|
|
1313
|
+
displayName: "Augment",
|
|
1314
|
+
skillsDir: ".augment/skills",
|
|
1315
|
+
globalSkillsDir: ".augment/skills"
|
|
1316
|
+
},
|
|
1196
1317
|
"claude-code": {
|
|
1197
1318
|
displayName: "Claude Code",
|
|
1198
|
-
skillsDir: ".claude/skills"
|
|
1319
|
+
skillsDir: ".claude/skills",
|
|
1320
|
+
globalSkillsDir: ".claude/skills"
|
|
1321
|
+
},
|
|
1322
|
+
cline: {
|
|
1323
|
+
displayName: "Cline",
|
|
1324
|
+
skillsDir: ".agents/skills",
|
|
1325
|
+
globalSkillsDir: ".agents/skills"
|
|
1326
|
+
},
|
|
1327
|
+
codebuddy: {
|
|
1328
|
+
displayName: "CodeBuddy",
|
|
1329
|
+
skillsDir: ".codebuddy/skills",
|
|
1330
|
+
globalSkillsDir: ".codebuddy/skills"
|
|
1199
1331
|
},
|
|
1200
1332
|
codex: {
|
|
1201
1333
|
displayName: "Codex",
|
|
1202
|
-
skillsDir: ".
|
|
1334
|
+
skillsDir: ".agents/skills",
|
|
1335
|
+
globalSkillsDir: ".codex/skills"
|
|
1336
|
+
},
|
|
1337
|
+
"command-code": {
|
|
1338
|
+
displayName: "Command Code",
|
|
1339
|
+
skillsDir: ".commandcode/skills",
|
|
1340
|
+
globalSkillsDir: ".commandcode/skills"
|
|
1341
|
+
},
|
|
1342
|
+
continue: {
|
|
1343
|
+
displayName: "Continue",
|
|
1344
|
+
skillsDir: ".continue/skills",
|
|
1345
|
+
globalSkillsDir: ".continue/skills"
|
|
1346
|
+
},
|
|
1347
|
+
cortex: {
|
|
1348
|
+
displayName: "Cortex Code",
|
|
1349
|
+
skillsDir: ".cortex/skills",
|
|
1350
|
+
globalSkillsDir: ".snowflake/cortex/skills"
|
|
1351
|
+
},
|
|
1352
|
+
crush: {
|
|
1353
|
+
displayName: "Crush",
|
|
1354
|
+
skillsDir: ".crush/skills",
|
|
1355
|
+
globalSkillsDir: ".config/crush/skills"
|
|
1203
1356
|
},
|
|
1204
1357
|
cursor: {
|
|
1205
1358
|
displayName: "Cursor",
|
|
1206
|
-
skillsDir: ".
|
|
1359
|
+
skillsDir: ".agents/skills",
|
|
1360
|
+
globalSkillsDir: ".cursor/skills"
|
|
1361
|
+
},
|
|
1362
|
+
droid: {
|
|
1363
|
+
displayName: "Droid",
|
|
1364
|
+
skillsDir: ".factory/skills",
|
|
1365
|
+
globalSkillsDir: ".factory/skills"
|
|
1207
1366
|
},
|
|
1208
|
-
gemini: {
|
|
1367
|
+
"gemini-cli": {
|
|
1209
1368
|
displayName: "Gemini CLI",
|
|
1210
|
-
skillsDir: ".
|
|
1369
|
+
skillsDir: ".agents/skills",
|
|
1370
|
+
globalSkillsDir: ".gemini/skills"
|
|
1371
|
+
},
|
|
1372
|
+
"github-copilot": {
|
|
1373
|
+
displayName: "GitHub Copilot",
|
|
1374
|
+
skillsDir: ".agents/skills",
|
|
1375
|
+
globalSkillsDir: ".copilot/skills"
|
|
1376
|
+
},
|
|
1377
|
+
goose: {
|
|
1378
|
+
displayName: "Goose",
|
|
1379
|
+
skillsDir: ".goose/skills",
|
|
1380
|
+
globalSkillsDir: ".config/goose/skills"
|
|
1211
1381
|
},
|
|
1212
|
-
|
|
1382
|
+
"iflow-cli": {
|
|
1383
|
+
displayName: "iFlow CLI",
|
|
1384
|
+
skillsDir: ".iflow/skills",
|
|
1385
|
+
globalSkillsDir: ".iflow/skills"
|
|
1386
|
+
},
|
|
1387
|
+
junie: {
|
|
1388
|
+
displayName: "Junie",
|
|
1389
|
+
skillsDir: ".junie/skills",
|
|
1390
|
+
globalSkillsDir: ".junie/skills"
|
|
1391
|
+
},
|
|
1392
|
+
kilo: {
|
|
1393
|
+
displayName: "Kilo Code",
|
|
1394
|
+
skillsDir: ".kilocode/skills",
|
|
1395
|
+
globalSkillsDir: ".kilocode/skills"
|
|
1396
|
+
},
|
|
1397
|
+
"kimi-cli": {
|
|
1398
|
+
displayName: "Kimi Code CLI",
|
|
1399
|
+
skillsDir: ".agents/skills",
|
|
1400
|
+
globalSkillsDir: ".config/agents/skills"
|
|
1401
|
+
},
|
|
1402
|
+
"kiro-cli": {
|
|
1213
1403
|
displayName: "Kiro CLI",
|
|
1214
|
-
skillsDir: ".kiro/skills"
|
|
1404
|
+
skillsDir: ".kiro/skills",
|
|
1405
|
+
globalSkillsDir: ".kiro/skills"
|
|
1406
|
+
},
|
|
1407
|
+
kode: {
|
|
1408
|
+
displayName: "Kode",
|
|
1409
|
+
skillsDir: ".kode/skills",
|
|
1410
|
+
globalSkillsDir: ".kode/skills"
|
|
1411
|
+
},
|
|
1412
|
+
mcpjam: {
|
|
1413
|
+
displayName: "MCPJam",
|
|
1414
|
+
skillsDir: ".mcpjam/skills",
|
|
1415
|
+
globalSkillsDir: ".mcpjam/skills"
|
|
1416
|
+
},
|
|
1417
|
+
"mistral-vibe": {
|
|
1418
|
+
displayName: "Mistral Vibe",
|
|
1419
|
+
skillsDir: ".vibe/skills",
|
|
1420
|
+
globalSkillsDir: ".vibe/skills"
|
|
1421
|
+
},
|
|
1422
|
+
mux: {
|
|
1423
|
+
displayName: "Mux",
|
|
1424
|
+
skillsDir: ".mux/skills",
|
|
1425
|
+
globalSkillsDir: ".mux/skills"
|
|
1426
|
+
},
|
|
1427
|
+
neovate: {
|
|
1428
|
+
displayName: "Neovate",
|
|
1429
|
+
skillsDir: ".neovate/skills",
|
|
1430
|
+
globalSkillsDir: ".neovate/skills"
|
|
1431
|
+
},
|
|
1432
|
+
openclaw: {
|
|
1433
|
+
displayName: "OpenClaw",
|
|
1434
|
+
skillsDir: "skills",
|
|
1435
|
+
globalSkillsDir: ".openclaw/skills"
|
|
1215
1436
|
},
|
|
1216
1437
|
opencode: {
|
|
1217
1438
|
displayName: "OpenCode",
|
|
1218
|
-
skillsDir: ".
|
|
1439
|
+
skillsDir: ".agents/skills",
|
|
1440
|
+
globalSkillsDir: ".config/opencode/skills"
|
|
1441
|
+
},
|
|
1442
|
+
openhands: {
|
|
1443
|
+
displayName: "OpenHands",
|
|
1444
|
+
skillsDir: ".openhands/skills",
|
|
1445
|
+
globalSkillsDir: ".openhands/skills"
|
|
1446
|
+
},
|
|
1447
|
+
pi: {
|
|
1448
|
+
displayName: "Pi",
|
|
1449
|
+
skillsDir: ".pi/skills",
|
|
1450
|
+
globalSkillsDir: ".pi/agent/skills"
|
|
1451
|
+
},
|
|
1452
|
+
pochi: {
|
|
1453
|
+
displayName: "Pochi",
|
|
1454
|
+
skillsDir: ".pochi/skills",
|
|
1455
|
+
globalSkillsDir: ".pochi/skills"
|
|
1456
|
+
},
|
|
1457
|
+
qoder: {
|
|
1458
|
+
displayName: "Qoder",
|
|
1459
|
+
skillsDir: ".qoder/skills",
|
|
1460
|
+
globalSkillsDir: ".qoder/skills"
|
|
1461
|
+
},
|
|
1462
|
+
"qwen-code": {
|
|
1463
|
+
displayName: "Qwen Code",
|
|
1464
|
+
skillsDir: ".qwen/skills",
|
|
1465
|
+
globalSkillsDir: ".qwen/skills"
|
|
1466
|
+
},
|
|
1467
|
+
replit: {
|
|
1468
|
+
displayName: "Replit",
|
|
1469
|
+
skillsDir: ".agents/skills",
|
|
1470
|
+
globalSkillsDir: ".config/agents/skills"
|
|
1471
|
+
},
|
|
1472
|
+
roo: {
|
|
1473
|
+
displayName: "Roo Code",
|
|
1474
|
+
skillsDir: ".roo/skills",
|
|
1475
|
+
globalSkillsDir: ".roo/skills"
|
|
1476
|
+
},
|
|
1477
|
+
trae: {
|
|
1478
|
+
displayName: "Trae",
|
|
1479
|
+
skillsDir: ".trae/skills",
|
|
1480
|
+
globalSkillsDir: ".trae/skills"
|
|
1481
|
+
},
|
|
1482
|
+
"trae-cn": {
|
|
1483
|
+
displayName: "Trae CN",
|
|
1484
|
+
skillsDir: ".trae/skills",
|
|
1485
|
+
globalSkillsDir: ".trae-cn/skills"
|
|
1486
|
+
},
|
|
1487
|
+
universal: {
|
|
1488
|
+
displayName: "Universal",
|
|
1489
|
+
skillsDir: ".agents/skills",
|
|
1490
|
+
globalSkillsDir: ".config/agents/skills"
|
|
1491
|
+
},
|
|
1492
|
+
windsurf: {
|
|
1493
|
+
displayName: "Windsurf",
|
|
1494
|
+
skillsDir: ".windsurf/skills",
|
|
1495
|
+
globalSkillsDir: ".codeium/windsurf/skills"
|
|
1496
|
+
},
|
|
1497
|
+
zencoder: {
|
|
1498
|
+
displayName: "Zencoder",
|
|
1499
|
+
skillsDir: ".zencoder/skills",
|
|
1500
|
+
globalSkillsDir: ".zencoder/skills"
|
|
1219
1501
|
}
|
|
1220
1502
|
};
|
|
1221
|
-
DEFAULT_AGENT_CONFIGS =
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
"claude-code",
|
|
1231
|
-
"codex",
|
|
1232
|
-
"cursor",
|
|
1233
|
-
"gemini",
|
|
1234
|
-
"kiro",
|
|
1235
|
-
"opencode"
|
|
1236
|
-
];
|
|
1503
|
+
DEFAULT_AGENT_CONFIGS = Object.fromEntries(
|
|
1504
|
+
Object.entries(AGENT_INFO).map(([key, info]) => [
|
|
1505
|
+
key,
|
|
1506
|
+
{ skillsDir: info.skillsDir }
|
|
1507
|
+
])
|
|
1508
|
+
);
|
|
1509
|
+
ALL_AGENTS = Object.keys(
|
|
1510
|
+
AGENT_INFO
|
|
1511
|
+
).sort();
|
|
1237
1512
|
}
|
|
1238
1513
|
});
|
|
1239
1514
|
function getGitHubHeaders() {
|
|
@@ -1331,13 +1606,13 @@ async function extractGitHubPackage(spec, buffer, skillsDir) {
|
|
|
1331
1606
|
const sourcePath = join(tempDir, extractedDir);
|
|
1332
1607
|
const copySource = spec.path ? join(sourcePath, spec.path) : sourcePath;
|
|
1333
1608
|
if (spec.path) {
|
|
1334
|
-
const
|
|
1335
|
-
if (!
|
|
1609
|
+
const pathExists2 = await lstat(copySource).catch(() => null);
|
|
1610
|
+
if (!pathExists2) {
|
|
1336
1611
|
const rootEntries = await readdir(sourcePath);
|
|
1337
1612
|
const dirs = [];
|
|
1338
1613
|
for (const entry of rootEntries) {
|
|
1339
|
-
const
|
|
1340
|
-
if (
|
|
1614
|
+
const stat9 = await lstat(join(sourcePath, entry)).catch(() => null);
|
|
1615
|
+
if (stat9?.isDirectory() && !entry.startsWith(".")) {
|
|
1341
1616
|
dirs.push(entry);
|
|
1342
1617
|
}
|
|
1343
1618
|
}
|
|
@@ -1485,6 +1760,9 @@ async function writeLockfile(lockfile) {
|
|
|
1485
1760
|
if (lockfile.localPackages && Object.keys(lockfile.localPackages).length > 0) {
|
|
1486
1761
|
normalized.localPackages = lockfile.localPackages;
|
|
1487
1762
|
}
|
|
1763
|
+
if (lockfile.wellKnownPackages && Object.keys(lockfile.wellKnownPackages).length > 0) {
|
|
1764
|
+
normalized.wellKnownPackages = lockfile.wellKnownPackages;
|
|
1765
|
+
}
|
|
1488
1766
|
await writeFile(lockfilePath, `${JSON.stringify(normalized, null, 2)}
|
|
1489
1767
|
`);
|
|
1490
1768
|
}
|
|
@@ -1589,6 +1867,29 @@ async function addLocalToLockfile(specifier, entry) {
|
|
|
1589
1867
|
lockfile.localPackages[specifier] = entry;
|
|
1590
1868
|
await writeLockfile(lockfile);
|
|
1591
1869
|
}
|
|
1870
|
+
async function addWellKnownToLockfile(specifier, entry) {
|
|
1871
|
+
let lockfile = await readLockfile();
|
|
1872
|
+
if (!lockfile) {
|
|
1873
|
+
lockfile = await createEmptyLockfile();
|
|
1874
|
+
}
|
|
1875
|
+
if (!lockfile.wellKnownPackages) {
|
|
1876
|
+
lockfile.wellKnownPackages = {};
|
|
1877
|
+
}
|
|
1878
|
+
lockfile.wellKnownPackages[specifier] = entry;
|
|
1879
|
+
await writeLockfile(lockfile);
|
|
1880
|
+
}
|
|
1881
|
+
async function listLockfileWellKnownPackages() {
|
|
1882
|
+
const lockfile = await readLockfile();
|
|
1883
|
+
if (!lockfile?.wellKnownPackages) {
|
|
1884
|
+
return [];
|
|
1885
|
+
}
|
|
1886
|
+
return Object.entries(lockfile.wellKnownPackages).map(
|
|
1887
|
+
([specifier, entry]) => ({
|
|
1888
|
+
specifier,
|
|
1889
|
+
entry
|
|
1890
|
+
})
|
|
1891
|
+
);
|
|
1892
|
+
}
|
|
1592
1893
|
var init_lockfile2 = __esm({
|
|
1593
1894
|
"src/lockfile.ts"() {
|
|
1594
1895
|
init_config();
|
|
@@ -1596,6 +1897,9 @@ var init_lockfile2 = __esm({
|
|
|
1596
1897
|
}
|
|
1597
1898
|
});
|
|
1598
1899
|
function getManifestPath() {
|
|
1900
|
+
if (isGlobalMode()) {
|
|
1901
|
+
return join(homedir(), ".pspm", "pspm.json");
|
|
1902
|
+
}
|
|
1599
1903
|
return join(process.cwd(), "pspm.json");
|
|
1600
1904
|
}
|
|
1601
1905
|
async function readManifest() {
|
|
@@ -1674,8 +1978,23 @@ async function addLocalDependency(specifier, version3 = "*") {
|
|
|
1674
1978
|
manifest.localDependencies[specifier] = version3;
|
|
1675
1979
|
await writeManifest(manifest);
|
|
1676
1980
|
}
|
|
1981
|
+
async function addWellKnownDependency(baseUrl, skillNames) {
|
|
1982
|
+
const manifest = await ensureManifest();
|
|
1983
|
+
if (!manifest.wellKnownDependencies) {
|
|
1984
|
+
manifest.wellKnownDependencies = {};
|
|
1985
|
+
}
|
|
1986
|
+
const existing = manifest.wellKnownDependencies[baseUrl];
|
|
1987
|
+
if (Array.isArray(existing)) {
|
|
1988
|
+
const merged = [.../* @__PURE__ */ new Set([...existing, ...skillNames])];
|
|
1989
|
+
manifest.wellKnownDependencies[baseUrl] = merged;
|
|
1990
|
+
} else {
|
|
1991
|
+
manifest.wellKnownDependencies[baseUrl] = skillNames;
|
|
1992
|
+
}
|
|
1993
|
+
await writeManifest(manifest);
|
|
1994
|
+
}
|
|
1677
1995
|
var init_manifest2 = __esm({
|
|
1678
1996
|
"src/manifest.ts"() {
|
|
1997
|
+
init_config();
|
|
1679
1998
|
}
|
|
1680
1999
|
});
|
|
1681
2000
|
async function createAgentSymlinks(skills, options) {
|
|
@@ -1684,7 +2003,7 @@ async function createAgentSymlinks(skills, options) {
|
|
|
1684
2003
|
return;
|
|
1685
2004
|
}
|
|
1686
2005
|
for (const agentName of agents) {
|
|
1687
|
-
const config2 = resolveAgentConfig(agentName, agentConfigs);
|
|
2006
|
+
const config2 = resolveAgentConfig(agentName, agentConfigs, options.global);
|
|
1688
2007
|
if (!config2) {
|
|
1689
2008
|
console.warn(`Warning: Unknown agent "${agentName}", skipping symlinks`);
|
|
1690
2009
|
continue;
|
|
@@ -1756,6 +2075,9 @@ function getGitHubSkillPath(owner, repo, path) {
|
|
|
1756
2075
|
function getLocalSkillPath(skillName) {
|
|
1757
2076
|
return `.pspm/skills/_local/${skillName}`;
|
|
1758
2077
|
}
|
|
2078
|
+
function getWellKnownSkillPath(hostname, skillName) {
|
|
2079
|
+
return `.pspm/skills/_wellknown/${hostname}/${skillName}`;
|
|
2080
|
+
}
|
|
1759
2081
|
async function getLinkedAgents(skillName, agents, projectRoot, agentConfigs) {
|
|
1760
2082
|
const linkedAgents = [];
|
|
1761
2083
|
for (const agentName of agents) {
|
|
@@ -1777,6 +2099,182 @@ var init_symlinks = __esm({
|
|
|
1777
2099
|
init_agents();
|
|
1778
2100
|
}
|
|
1779
2101
|
});
|
|
2102
|
+
function isWellKnownSpecifier(input) {
|
|
2103
|
+
if (!input.startsWith("http://") && !input.startsWith("https://")) {
|
|
2104
|
+
return false;
|
|
2105
|
+
}
|
|
2106
|
+
try {
|
|
2107
|
+
const parsed = new URL(input);
|
|
2108
|
+
if (EXCLUDED_HOSTS.includes(parsed.hostname)) {
|
|
2109
|
+
return false;
|
|
2110
|
+
}
|
|
2111
|
+
if (input.endsWith(".git")) {
|
|
2112
|
+
return false;
|
|
2113
|
+
}
|
|
2114
|
+
return true;
|
|
2115
|
+
} catch {
|
|
2116
|
+
return false;
|
|
2117
|
+
}
|
|
2118
|
+
}
|
|
2119
|
+
function getWellKnownHostname(url) {
|
|
2120
|
+
try {
|
|
2121
|
+
const parsed = new URL(url);
|
|
2122
|
+
return parsed.hostname.replace(/^www\./, "");
|
|
2123
|
+
} catch {
|
|
2124
|
+
return url;
|
|
2125
|
+
}
|
|
2126
|
+
}
|
|
2127
|
+
function isValidSkillEntry(entry) {
|
|
2128
|
+
if (!entry || typeof entry !== "object") return false;
|
|
2129
|
+
const e = entry;
|
|
2130
|
+
if (typeof e.name !== "string" || e.name.length === 0) return false;
|
|
2131
|
+
if (typeof e.description !== "string" || e.description.length === 0)
|
|
2132
|
+
return false;
|
|
2133
|
+
if (!SKILL_NAME_PATTERN.test(e.name)) return false;
|
|
2134
|
+
if (!Array.isArray(e.files) || e.files.length === 0) return false;
|
|
2135
|
+
let hasSkillMd = false;
|
|
2136
|
+
for (const file of e.files) {
|
|
2137
|
+
if (typeof file !== "string") return false;
|
|
2138
|
+
if (file.startsWith("/") || file.startsWith("\\")) return false;
|
|
2139
|
+
if (file.includes("..")) return false;
|
|
2140
|
+
if (file.toLowerCase() === "skill.md") hasSkillMd = true;
|
|
2141
|
+
}
|
|
2142
|
+
if (!hasSkillMd) return false;
|
|
2143
|
+
return true;
|
|
2144
|
+
}
|
|
2145
|
+
function isValidIndex(data) {
|
|
2146
|
+
if (!data || typeof data !== "object") return false;
|
|
2147
|
+
const d = data;
|
|
2148
|
+
if (!Array.isArray(d.skills)) return false;
|
|
2149
|
+
return d.skills.every(isValidSkillEntry);
|
|
2150
|
+
}
|
|
2151
|
+
async function fetchWellKnownIndex(baseUrl) {
|
|
2152
|
+
const parsed = new URL(baseUrl);
|
|
2153
|
+
const pathRelativeUrl = `${baseUrl.replace(/\/$/, "")}/${WELL_KNOWN_PATH}/${INDEX_FILE}`;
|
|
2154
|
+
const pathRelativeBase = `${baseUrl.replace(/\/$/, "")}/${WELL_KNOWN_PATH}`;
|
|
2155
|
+
try {
|
|
2156
|
+
const response = await fetch(pathRelativeUrl, {
|
|
2157
|
+
signal: AbortSignal.timeout(1e4)
|
|
2158
|
+
});
|
|
2159
|
+
if (response.ok) {
|
|
2160
|
+
const data = await response.json();
|
|
2161
|
+
if (isValidIndex(data)) {
|
|
2162
|
+
return { index: data, resolvedBaseUrl: pathRelativeBase };
|
|
2163
|
+
}
|
|
2164
|
+
}
|
|
2165
|
+
} catch {
|
|
2166
|
+
}
|
|
2167
|
+
const rootUrl = `${parsed.protocol}//${parsed.host}/${WELL_KNOWN_PATH}/${INDEX_FILE}`;
|
|
2168
|
+
const rootBase = `${parsed.protocol}//${parsed.host}/${WELL_KNOWN_PATH}`;
|
|
2169
|
+
if (rootUrl !== pathRelativeUrl) {
|
|
2170
|
+
try {
|
|
2171
|
+
const response = await fetch(rootUrl, {
|
|
2172
|
+
signal: AbortSignal.timeout(1e4)
|
|
2173
|
+
});
|
|
2174
|
+
if (response.ok) {
|
|
2175
|
+
const data = await response.json();
|
|
2176
|
+
if (isValidIndex(data)) {
|
|
2177
|
+
return { index: data, resolvedBaseUrl: rootBase };
|
|
2178
|
+
}
|
|
2179
|
+
}
|
|
2180
|
+
} catch {
|
|
2181
|
+
}
|
|
2182
|
+
}
|
|
2183
|
+
return null;
|
|
2184
|
+
}
|
|
2185
|
+
async function fetchSkillFiles(baseUrl, entry) {
|
|
2186
|
+
const skillBaseUrl = `${baseUrl}/${entry.name}`;
|
|
2187
|
+
const files = /* @__PURE__ */ new Map();
|
|
2188
|
+
let skillMdContent = "";
|
|
2189
|
+
const results = await Promise.allSettled(
|
|
2190
|
+
entry.files.map(async (filePath) => {
|
|
2191
|
+
const fileUrl = `${skillBaseUrl}/${filePath}`;
|
|
2192
|
+
const response = await fetch(fileUrl, {
|
|
2193
|
+
signal: AbortSignal.timeout(1e4)
|
|
2194
|
+
});
|
|
2195
|
+
if (!response.ok) {
|
|
2196
|
+
throw new Error(`Failed to fetch ${fileUrl}: ${response.status}`);
|
|
2197
|
+
}
|
|
2198
|
+
const content = await response.text();
|
|
2199
|
+
return { filePath, content };
|
|
2200
|
+
})
|
|
2201
|
+
);
|
|
2202
|
+
for (const result of results) {
|
|
2203
|
+
if (result.status === "fulfilled") {
|
|
2204
|
+
files.set(result.value.filePath, result.value.content);
|
|
2205
|
+
if (result.value.filePath.toLowerCase() === "skill.md") {
|
|
2206
|
+
skillMdContent = result.value.content;
|
|
2207
|
+
}
|
|
2208
|
+
}
|
|
2209
|
+
}
|
|
2210
|
+
if (!skillMdContent) {
|
|
2211
|
+
return null;
|
|
2212
|
+
}
|
|
2213
|
+
return {
|
|
2214
|
+
name: entry.name,
|
|
2215
|
+
description: entry.description,
|
|
2216
|
+
content: skillMdContent,
|
|
2217
|
+
files,
|
|
2218
|
+
sourceUrl: `${skillBaseUrl}/SKILL.md`,
|
|
2219
|
+
indexEntry: entry
|
|
2220
|
+
};
|
|
2221
|
+
}
|
|
2222
|
+
async function fetchWellKnownSkills(url) {
|
|
2223
|
+
const result = await fetchWellKnownIndex(url);
|
|
2224
|
+
if (!result) return null;
|
|
2225
|
+
const { index, resolvedBaseUrl } = result;
|
|
2226
|
+
const hostname = getWellKnownHostname(url);
|
|
2227
|
+
const skillResults = await Promise.allSettled(
|
|
2228
|
+
index.skills.map((entry) => fetchSkillFiles(resolvedBaseUrl, entry))
|
|
2229
|
+
);
|
|
2230
|
+
const skills = [];
|
|
2231
|
+
for (const r of skillResults) {
|
|
2232
|
+
if (r.status === "fulfilled" && r.value) {
|
|
2233
|
+
skills.push(r.value);
|
|
2234
|
+
}
|
|
2235
|
+
}
|
|
2236
|
+
if (skills.length === 0) return null;
|
|
2237
|
+
return { skills, resolvedBaseUrl, hostname };
|
|
2238
|
+
}
|
|
2239
|
+
async function extractWellKnownSkill(skill, hostname, skillsDir) {
|
|
2240
|
+
const destPath = join(skillsDir, "_wellknown", hostname, skill.name);
|
|
2241
|
+
await rm(destPath, { recursive: true, force: true });
|
|
2242
|
+
await mkdir(destPath, { recursive: true });
|
|
2243
|
+
for (const [filePath, content] of skill.files) {
|
|
2244
|
+
const fullPath = join(destPath, filePath);
|
|
2245
|
+
if (!fullPath.startsWith(destPath)) {
|
|
2246
|
+
continue;
|
|
2247
|
+
}
|
|
2248
|
+
const { dirname: dirname7 } = await import('path');
|
|
2249
|
+
await mkdir(dirname7(fullPath), { recursive: true });
|
|
2250
|
+
await writeFile(fullPath, content, "utf-8");
|
|
2251
|
+
}
|
|
2252
|
+
return `.pspm/skills/_wellknown/${hostname}/${skill.name}`;
|
|
2253
|
+
}
|
|
2254
|
+
function calculateWellKnownIntegrity(skill) {
|
|
2255
|
+
const sortedEntries = [...skill.files.entries()].sort(
|
|
2256
|
+
([a], [b]) => a.localeCompare(b)
|
|
2257
|
+
);
|
|
2258
|
+
const combined = sortedEntries.map(([path, content]) => `${path}:${content}`).join("\n");
|
|
2259
|
+
return calculateIntegrity(Buffer.from(combined, "utf-8"));
|
|
2260
|
+
}
|
|
2261
|
+
function getWellKnownDisplayName(hostname, skillName) {
|
|
2262
|
+
return `${hostname}/${skillName} (well-known)`;
|
|
2263
|
+
}
|
|
2264
|
+
var WELL_KNOWN_PATH, INDEX_FILE, SKILL_NAME_PATTERN, EXCLUDED_HOSTS;
|
|
2265
|
+
var init_wellknown = __esm({
|
|
2266
|
+
"src/wellknown.ts"() {
|
|
2267
|
+
init_lib();
|
|
2268
|
+
WELL_KNOWN_PATH = ".well-known/skills";
|
|
2269
|
+
INDEX_FILE = "index.json";
|
|
2270
|
+
SKILL_NAME_PATTERN = /^[a-z0-9]([a-z0-9-]{0,62}[a-z0-9])?$/;
|
|
2271
|
+
EXCLUDED_HOSTS = [
|
|
2272
|
+
"github.com",
|
|
2273
|
+
"gitlab.com",
|
|
2274
|
+
"raw.githubusercontent.com"
|
|
2275
|
+
];
|
|
2276
|
+
}
|
|
2277
|
+
});
|
|
1780
2278
|
|
|
1781
2279
|
// src/commands/add.ts
|
|
1782
2280
|
var add_exports = {};
|
|
@@ -1799,6 +2297,10 @@ function normalizeToFileSpecifier(path) {
|
|
|
1799
2297
|
return `file:${path}`;
|
|
1800
2298
|
}
|
|
1801
2299
|
async function add(specifiers, options) {
|
|
2300
|
+
if (options.global) {
|
|
2301
|
+
setGlobalMode(true);
|
|
2302
|
+
console.log("Installing globally to ~/.pspm/\n");
|
|
2303
|
+
}
|
|
1802
2304
|
console.log("Resolving packages...\n");
|
|
1803
2305
|
const resolvedPackages = [];
|
|
1804
2306
|
const validationErrors = [];
|
|
@@ -1807,9 +2309,12 @@ async function add(specifiers, options) {
|
|
|
1807
2309
|
if (isLocalSpecifier2(specifier)) {
|
|
1808
2310
|
const resolved = await validateLocalPackage(specifier);
|
|
1809
2311
|
resolvedPackages.push(resolved);
|
|
1810
|
-
} else if (isGitHubSpecifier(specifier)) {
|
|
2312
|
+
} else if (isGitHubSpecifier(specifier) || isGitHubUrl(specifier) || isGitHubShorthand(specifier)) {
|
|
1811
2313
|
const resolved = await validateGitHubPackage(specifier);
|
|
1812
2314
|
resolvedPackages.push(resolved);
|
|
2315
|
+
} else if (isWellKnownSpecifier(specifier)) {
|
|
2316
|
+
const resolved = await validateWellKnownPackage(specifier);
|
|
2317
|
+
resolvedPackages.push(resolved);
|
|
1813
2318
|
} else {
|
|
1814
2319
|
const resolved = await validateRegistryPackage(specifier);
|
|
1815
2320
|
resolvedPackages.push(resolved);
|
|
@@ -1842,6 +2347,9 @@ async function add(specifiers, options) {
|
|
|
1842
2347
|
const localPackages = resolvedPackages.filter(
|
|
1843
2348
|
(p) => p.type === "local"
|
|
1844
2349
|
);
|
|
2350
|
+
const wellKnownPackages = resolvedPackages.filter(
|
|
2351
|
+
(p) => p.type === "wellknown"
|
|
2352
|
+
);
|
|
1845
2353
|
let resolutionResult = null;
|
|
1846
2354
|
if (registryPackages.length > 0) {
|
|
1847
2355
|
const rootDeps = {};
|
|
@@ -1944,6 +2452,24 @@ async function add(specifiers, options) {
|
|
|
1944
2452
|
error: message
|
|
1945
2453
|
});
|
|
1946
2454
|
console.error(`Failed to install ${resolved.specifier}: ${message}
|
|
2455
|
+
`);
|
|
2456
|
+
}
|
|
2457
|
+
}
|
|
2458
|
+
for (const resolved of wellKnownPackages) {
|
|
2459
|
+
try {
|
|
2460
|
+
await installWellKnownPackage(resolved, {
|
|
2461
|
+
...options,
|
|
2462
|
+
resolvedAgents: agents
|
|
2463
|
+
});
|
|
2464
|
+
results.push({ specifier: resolved.specifier, success: true });
|
|
2465
|
+
} catch (error) {
|
|
2466
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
2467
|
+
results.push({
|
|
2468
|
+
specifier: resolved.specifier,
|
|
2469
|
+
success: false,
|
|
2470
|
+
error: message
|
|
2471
|
+
});
|
|
2472
|
+
console.error(`Failed to install ${resolved.specifier}: ${message}
|
|
1947
2473
|
`);
|
|
1948
2474
|
}
|
|
1949
2475
|
}
|
|
@@ -1957,6 +2483,9 @@ Summary: ${succeeded} added, ${failed} failed`);
|
|
|
1957
2483
|
}
|
|
1958
2484
|
}
|
|
1959
2485
|
}
|
|
2486
|
+
function getSymlinkRoot() {
|
|
2487
|
+
return isGlobalMode() ? homedir() : process.cwd();
|
|
2488
|
+
}
|
|
1960
2489
|
async function installFromNode(node, options) {
|
|
1961
2490
|
const match = node.name.match(/^@user\/([^/]+)\/([^/]+)$/);
|
|
1962
2491
|
if (!match) {
|
|
@@ -1986,16 +2515,16 @@ async function installFromNode(node, options) {
|
|
|
1986
2515
|
const skillsDir = getSkillsDir();
|
|
1987
2516
|
const destDir = join(skillsDir, username, name);
|
|
1988
2517
|
await mkdir(destDir, { recursive: true });
|
|
1989
|
-
const { writeFile:
|
|
2518
|
+
const { writeFile: writeFile11 } = await import('fs/promises');
|
|
1990
2519
|
const tempFile = join(destDir, ".temp.tgz");
|
|
1991
|
-
await
|
|
2520
|
+
await writeFile11(tempFile, tarballBuffer);
|
|
1992
2521
|
const { exec: exec2 } = await import('child_process');
|
|
1993
2522
|
const { promisify: promisify2 } = await import('util');
|
|
1994
2523
|
const execAsync = promisify2(exec2);
|
|
1995
2524
|
try {
|
|
1996
2525
|
await rm(destDir, { recursive: true, force: true });
|
|
1997
2526
|
await mkdir(destDir, { recursive: true });
|
|
1998
|
-
await
|
|
2527
|
+
await writeFile11(tempFile, tarballBuffer);
|
|
1999
2528
|
await execAsync(
|
|
2000
2529
|
`tar -xzf "${tempFile}" -C "${destDir}" --strip-components=1`
|
|
2001
2530
|
);
|
|
@@ -2029,8 +2558,9 @@ async function installFromNode(node, options) {
|
|
|
2029
2558
|
};
|
|
2030
2559
|
await createAgentSymlinks([skillInfo], {
|
|
2031
2560
|
agents,
|
|
2032
|
-
projectRoot:
|
|
2033
|
-
agentConfigs: skillManifest?.agents
|
|
2561
|
+
projectRoot: getSymlinkRoot(),
|
|
2562
|
+
agentConfigs: skillManifest?.agents,
|
|
2563
|
+
global: isGlobalMode()
|
|
2034
2564
|
});
|
|
2035
2565
|
}
|
|
2036
2566
|
console.log(`Installed ${node.name}@${node.version}`);
|
|
@@ -2104,11 +2634,26 @@ async function validateRegistryPackage(specifier) {
|
|
|
2104
2634
|
}
|
|
2105
2635
|
};
|
|
2106
2636
|
}
|
|
2637
|
+
function parseAnyGitHubFormat(specifier) {
|
|
2638
|
+
if (isGitHubSpecifier(specifier)) {
|
|
2639
|
+
return parseGitHubSpecifier(specifier);
|
|
2640
|
+
}
|
|
2641
|
+
if (isGitHubUrl(specifier)) {
|
|
2642
|
+
return parseGitHubUrl(specifier);
|
|
2643
|
+
}
|
|
2644
|
+
if (isGitHubShorthand(specifier)) {
|
|
2645
|
+
return parseGitHubShorthand(specifier);
|
|
2646
|
+
}
|
|
2647
|
+
return null;
|
|
2648
|
+
}
|
|
2107
2649
|
async function validateGitHubPackage(specifier) {
|
|
2108
|
-
const parsed =
|
|
2650
|
+
const parsed = parseAnyGitHubFormat(specifier);
|
|
2109
2651
|
if (!parsed) {
|
|
2110
2652
|
throw new Error(
|
|
2111
|
-
`Invalid GitHub specifier "${specifier}".
|
|
2653
|
+
`Invalid GitHub specifier "${specifier}". Supported formats:
|
|
2654
|
+
github:owner/repo[/path][@ref]
|
|
2655
|
+
https://github.com/owner/repo[/tree/branch/path]
|
|
2656
|
+
owner/repo[/path]`
|
|
2112
2657
|
);
|
|
2113
2658
|
}
|
|
2114
2659
|
const ref = parsed.ref || "HEAD";
|
|
@@ -2159,8 +2704,9 @@ async function installGitHubPackage(resolved, options) {
|
|
|
2159
2704
|
};
|
|
2160
2705
|
await createAgentSymlinks([skillInfo], {
|
|
2161
2706
|
agents,
|
|
2162
|
-
projectRoot:
|
|
2163
|
-
agentConfigs: manifest?.agents
|
|
2707
|
+
projectRoot: getSymlinkRoot(),
|
|
2708
|
+
agentConfigs: manifest?.agents,
|
|
2709
|
+
global: isGlobalMode()
|
|
2164
2710
|
});
|
|
2165
2711
|
}
|
|
2166
2712
|
console.log(
|
|
@@ -2246,13 +2792,72 @@ async function installLocalPackage(resolved, options) {
|
|
|
2246
2792
|
};
|
|
2247
2793
|
await createAgentSymlinks([skillInfo], {
|
|
2248
2794
|
agents,
|
|
2249
|
-
projectRoot:
|
|
2250
|
-
agentConfigs: manifest?.agents
|
|
2795
|
+
projectRoot: getSymlinkRoot(),
|
|
2796
|
+
agentConfigs: manifest?.agents,
|
|
2797
|
+
global: isGlobalMode()
|
|
2251
2798
|
});
|
|
2252
2799
|
}
|
|
2253
2800
|
console.log(`Installed ${specifier} (local)`);
|
|
2254
2801
|
console.log(`Location: ${symlinkPath} -> ${resolvedPath}`);
|
|
2255
2802
|
}
|
|
2803
|
+
async function validateWellKnownPackage(specifier) {
|
|
2804
|
+
const hostname = getWellKnownHostname(specifier);
|
|
2805
|
+
console.log(`Discovering skills from ${hostname}...`);
|
|
2806
|
+
const result = await fetchWellKnownSkills(specifier);
|
|
2807
|
+
if (!result) {
|
|
2808
|
+
throw new Error(
|
|
2809
|
+
`No well-known skills found at ${specifier}
|
|
2810
|
+
Expected: ${specifier}/.well-known/skills/index.json`
|
|
2811
|
+
);
|
|
2812
|
+
}
|
|
2813
|
+
console.log(
|
|
2814
|
+
`Found ${result.skills.length} skill(s) from ${hostname}: ${result.skills.map((s) => s.name).join(", ")}`
|
|
2815
|
+
);
|
|
2816
|
+
return {
|
|
2817
|
+
type: "wellknown",
|
|
2818
|
+
specifier,
|
|
2819
|
+
hostname: result.hostname,
|
|
2820
|
+
skills: result.skills,
|
|
2821
|
+
resolvedBaseUrl: result.resolvedBaseUrl
|
|
2822
|
+
};
|
|
2823
|
+
}
|
|
2824
|
+
async function installWellKnownPackage(resolved, options) {
|
|
2825
|
+
const { specifier, hostname, skills } = resolved;
|
|
2826
|
+
const skillsDir = getSkillsDir();
|
|
2827
|
+
for (const skill of skills) {
|
|
2828
|
+
console.log(
|
|
2829
|
+
`Installing ${getWellKnownDisplayName(hostname, skill.name)}...`
|
|
2830
|
+
);
|
|
2831
|
+
const destPath = await extractWellKnownSkill(skill, hostname, skillsDir);
|
|
2832
|
+
const integrity = calculateWellKnownIntegrity(skill);
|
|
2833
|
+
const lockfileKey = `${specifier}#${skill.name}`;
|
|
2834
|
+
const entry = {
|
|
2835
|
+
version: "well-known",
|
|
2836
|
+
resolved: skill.sourceUrl,
|
|
2837
|
+
integrity,
|
|
2838
|
+
hostname,
|
|
2839
|
+
name: skill.name,
|
|
2840
|
+
files: [...skill.files.keys()]
|
|
2841
|
+
};
|
|
2842
|
+
await addWellKnownToLockfile(lockfileKey, entry);
|
|
2843
|
+
await addWellKnownDependency(specifier, [skill.name]);
|
|
2844
|
+
const agents = options.resolvedAgents;
|
|
2845
|
+
if (agents[0] !== "none") {
|
|
2846
|
+
const manifest = await readManifest();
|
|
2847
|
+
const skillInfo = {
|
|
2848
|
+
name: skill.name,
|
|
2849
|
+
sourcePath: getWellKnownSkillPath(hostname, skill.name)
|
|
2850
|
+
};
|
|
2851
|
+
await createAgentSymlinks([skillInfo], {
|
|
2852
|
+
agents,
|
|
2853
|
+
projectRoot: process.cwd(),
|
|
2854
|
+
agentConfigs: manifest?.agents
|
|
2855
|
+
});
|
|
2856
|
+
}
|
|
2857
|
+
console.log(`Installed ${getWellKnownDisplayName(hostname, skill.name)}`);
|
|
2858
|
+
console.log(`Location: ${destPath}`);
|
|
2859
|
+
}
|
|
2860
|
+
}
|
|
2256
2861
|
var init_add = __esm({
|
|
2257
2862
|
"src/commands/add.ts"() {
|
|
2258
2863
|
init_agents();
|
|
@@ -2264,6 +2869,7 @@ var init_add = __esm({
|
|
|
2264
2869
|
init_lockfile2();
|
|
2265
2870
|
init_manifest2();
|
|
2266
2871
|
init_symlinks();
|
|
2872
|
+
init_wellknown();
|
|
2267
2873
|
}
|
|
2268
2874
|
});
|
|
2269
2875
|
|
|
@@ -2332,18 +2938,18 @@ async function access(specifier, options) {
|
|
|
2332
2938
|
packageUsername = parsed.username;
|
|
2333
2939
|
} else {
|
|
2334
2940
|
const { readFile: readFile10 } = await import('fs/promises');
|
|
2335
|
-
const { join:
|
|
2941
|
+
const { join: join18 } = await import('path');
|
|
2336
2942
|
let manifest = null;
|
|
2337
2943
|
try {
|
|
2338
2944
|
const content = await readFile10(
|
|
2339
|
-
|
|
2945
|
+
join18(process.cwd(), "pspm.json"),
|
|
2340
2946
|
"utf-8"
|
|
2341
2947
|
);
|
|
2342
2948
|
manifest = JSON.parse(content);
|
|
2343
2949
|
} catch {
|
|
2344
2950
|
try {
|
|
2345
2951
|
const content = await readFile10(
|
|
2346
|
-
|
|
2952
|
+
join18(process.cwd(), "package.json"),
|
|
2347
2953
|
"utf-8"
|
|
2348
2954
|
);
|
|
2349
2955
|
manifest = JSON.parse(content);
|
|
@@ -2402,6 +3008,209 @@ async function access(specifier, options) {
|
|
|
2402
3008
|
|
|
2403
3009
|
// src/commands/index.ts
|
|
2404
3010
|
init_add();
|
|
3011
|
+
|
|
3012
|
+
// src/commands/audit.ts
|
|
3013
|
+
init_config();
|
|
3014
|
+
init_lib();
|
|
3015
|
+
init_lockfile2();
|
|
3016
|
+
async function audit(options) {
|
|
3017
|
+
try {
|
|
3018
|
+
const lockfile = await readLockfile();
|
|
3019
|
+
if (!lockfile) {
|
|
3020
|
+
if (options.json) {
|
|
3021
|
+
console.log(
|
|
3022
|
+
JSON.stringify({
|
|
3023
|
+
ok: false,
|
|
3024
|
+
issues: [
|
|
3025
|
+
{
|
|
3026
|
+
name: "-",
|
|
3027
|
+
source: "-",
|
|
3028
|
+
severity: "error",
|
|
3029
|
+
type: "no-lockfile",
|
|
3030
|
+
message: "No lockfile found. Run 'pspm install' first."
|
|
3031
|
+
}
|
|
3032
|
+
]
|
|
3033
|
+
})
|
|
3034
|
+
);
|
|
3035
|
+
} else {
|
|
3036
|
+
console.error("No lockfile found. Run 'pspm install' to create one.");
|
|
3037
|
+
}
|
|
3038
|
+
process.exit(1);
|
|
3039
|
+
}
|
|
3040
|
+
const issues = [];
|
|
3041
|
+
const skillsDir = getSkillsDir();
|
|
3042
|
+
const projectRoot = process.cwd();
|
|
3043
|
+
if (!options.json) {
|
|
3044
|
+
console.log("Auditing installed skills...\n");
|
|
3045
|
+
}
|
|
3046
|
+
const registrySkills = await listLockfileSkills();
|
|
3047
|
+
for (const { name: fullName, entry } of registrySkills) {
|
|
3048
|
+
const match = fullName.match(/^@user\/([^/]+)\/([^/]+)$/);
|
|
3049
|
+
if (!match) continue;
|
|
3050
|
+
const [, username, skillName] = match;
|
|
3051
|
+
const destDir = join(projectRoot, skillsDir, username, skillName);
|
|
3052
|
+
const exists = await pathExists(destDir);
|
|
3053
|
+
if (!exists) {
|
|
3054
|
+
issues.push({
|
|
3055
|
+
name: fullName,
|
|
3056
|
+
source: "registry",
|
|
3057
|
+
severity: "error",
|
|
3058
|
+
type: "missing",
|
|
3059
|
+
message: `Not installed on disk. Run 'pspm install' to restore.`
|
|
3060
|
+
});
|
|
3061
|
+
continue;
|
|
3062
|
+
}
|
|
3063
|
+
if (entry.deprecated) {
|
|
3064
|
+
issues.push({
|
|
3065
|
+
name: fullName,
|
|
3066
|
+
source: "registry",
|
|
3067
|
+
severity: "warning",
|
|
3068
|
+
type: "deprecated",
|
|
3069
|
+
message: `Deprecated: ${entry.deprecated}`
|
|
3070
|
+
});
|
|
3071
|
+
}
|
|
3072
|
+
const skillMdExists = await pathExists(join(destDir, "SKILL.md"));
|
|
3073
|
+
if (!skillMdExists) {
|
|
3074
|
+
issues.push({
|
|
3075
|
+
name: fullName,
|
|
3076
|
+
source: "registry",
|
|
3077
|
+
severity: "warning",
|
|
3078
|
+
type: "integrity",
|
|
3079
|
+
message: "Missing SKILL.md in installed directory. Package may be corrupted."
|
|
3080
|
+
});
|
|
3081
|
+
}
|
|
3082
|
+
}
|
|
3083
|
+
const githubSkills = await listLockfileGitHubPackages();
|
|
3084
|
+
for (const { specifier } of githubSkills) {
|
|
3085
|
+
const parsed = parseGitHubSpecifier(specifier);
|
|
3086
|
+
if (!parsed) continue;
|
|
3087
|
+
const destDir = parsed.path ? join(
|
|
3088
|
+
projectRoot,
|
|
3089
|
+
skillsDir,
|
|
3090
|
+
"_github",
|
|
3091
|
+
parsed.owner,
|
|
3092
|
+
parsed.repo,
|
|
3093
|
+
parsed.path
|
|
3094
|
+
) : join(projectRoot, skillsDir, "_github", parsed.owner, parsed.repo);
|
|
3095
|
+
const exists = await pathExists(destDir);
|
|
3096
|
+
if (!exists) {
|
|
3097
|
+
issues.push({
|
|
3098
|
+
name: specifier,
|
|
3099
|
+
source: "github",
|
|
3100
|
+
severity: "error",
|
|
3101
|
+
type: "missing",
|
|
3102
|
+
message: `Not installed on disk. Run 'pspm install' to restore.`
|
|
3103
|
+
});
|
|
3104
|
+
continue;
|
|
3105
|
+
}
|
|
3106
|
+
const skillMdExists = await pathExists(join(destDir, "SKILL.md"));
|
|
3107
|
+
if (!skillMdExists) {
|
|
3108
|
+
issues.push({
|
|
3109
|
+
name: specifier,
|
|
3110
|
+
source: "github",
|
|
3111
|
+
severity: "warning",
|
|
3112
|
+
type: "integrity",
|
|
3113
|
+
message: "Missing SKILL.md in installed directory. Package may be corrupted."
|
|
3114
|
+
});
|
|
3115
|
+
}
|
|
3116
|
+
}
|
|
3117
|
+
const wellKnownSkills = await listLockfileWellKnownPackages();
|
|
3118
|
+
for (const { specifier, entry } of wellKnownSkills) {
|
|
3119
|
+
const wkEntry = entry;
|
|
3120
|
+
const destDir = join(
|
|
3121
|
+
projectRoot,
|
|
3122
|
+
skillsDir,
|
|
3123
|
+
"_wellknown",
|
|
3124
|
+
wkEntry.hostname,
|
|
3125
|
+
wkEntry.name
|
|
3126
|
+
);
|
|
3127
|
+
const exists = await pathExists(destDir);
|
|
3128
|
+
if (!exists) {
|
|
3129
|
+
issues.push({
|
|
3130
|
+
name: specifier,
|
|
3131
|
+
source: "well-known",
|
|
3132
|
+
severity: "error",
|
|
3133
|
+
type: "missing",
|
|
3134
|
+
message: `Not installed on disk. Run 'pspm install' to restore.`
|
|
3135
|
+
});
|
|
3136
|
+
continue;
|
|
3137
|
+
}
|
|
3138
|
+
const skillMdExists = await pathExists(join(destDir, "SKILL.md"));
|
|
3139
|
+
if (!skillMdExists) {
|
|
3140
|
+
issues.push({
|
|
3141
|
+
name: specifier,
|
|
3142
|
+
source: "well-known",
|
|
3143
|
+
severity: "warning",
|
|
3144
|
+
type: "integrity",
|
|
3145
|
+
message: "Missing SKILL.md in installed directory. Package may be corrupted."
|
|
3146
|
+
});
|
|
3147
|
+
}
|
|
3148
|
+
}
|
|
3149
|
+
const errorCount = issues.filter((i) => i.severity === "error").length;
|
|
3150
|
+
const warningCount = issues.filter((i) => i.severity === "warning").length;
|
|
3151
|
+
if (options.json) {
|
|
3152
|
+
console.log(
|
|
3153
|
+
JSON.stringify(
|
|
3154
|
+
{
|
|
3155
|
+
ok: errorCount === 0,
|
|
3156
|
+
totalPackages: registrySkills.length + githubSkills.length + wellKnownSkills.length,
|
|
3157
|
+
issues
|
|
3158
|
+
},
|
|
3159
|
+
null,
|
|
3160
|
+
2
|
|
3161
|
+
)
|
|
3162
|
+
);
|
|
3163
|
+
if (errorCount > 0) process.exit(1);
|
|
3164
|
+
return;
|
|
3165
|
+
}
|
|
3166
|
+
if (issues.length === 0) {
|
|
3167
|
+
const totalPackages2 = registrySkills.length + githubSkills.length + wellKnownSkills.length;
|
|
3168
|
+
console.log(`Audited ${totalPackages2} package(s). No issues found.`);
|
|
3169
|
+
return;
|
|
3170
|
+
}
|
|
3171
|
+
const errors = issues.filter((i) => i.severity === "error");
|
|
3172
|
+
const warnings = issues.filter((i) => i.severity === "warning");
|
|
3173
|
+
if (errors.length > 0) {
|
|
3174
|
+
console.log("Errors:");
|
|
3175
|
+
for (const issue of errors) {
|
|
3176
|
+
console.log(
|
|
3177
|
+
` [${issue.type.toUpperCase()}] ${issue.name} (${issue.source})`
|
|
3178
|
+
);
|
|
3179
|
+
console.log(` ${issue.message}`);
|
|
3180
|
+
}
|
|
3181
|
+
console.log();
|
|
3182
|
+
}
|
|
3183
|
+
if (warnings.length > 0) {
|
|
3184
|
+
console.log("Warnings:");
|
|
3185
|
+
for (const issue of warnings) {
|
|
3186
|
+
console.log(
|
|
3187
|
+
` [${issue.type.toUpperCase()}] ${issue.name} (${issue.source})`
|
|
3188
|
+
);
|
|
3189
|
+
console.log(` ${issue.message}`);
|
|
3190
|
+
}
|
|
3191
|
+
console.log();
|
|
3192
|
+
}
|
|
3193
|
+
const totalPackages = registrySkills.length + githubSkills.length + wellKnownSkills.length;
|
|
3194
|
+
console.log(
|
|
3195
|
+
`Audited ${totalPackages} package(s): ${errorCount} error(s), ${warningCount} warning(s).`
|
|
3196
|
+
);
|
|
3197
|
+
if (errorCount > 0) {
|
|
3198
|
+
process.exit(1);
|
|
3199
|
+
}
|
|
3200
|
+
} catch (error) {
|
|
3201
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
3202
|
+
console.error(`Error: ${message}`);
|
|
3203
|
+
process.exit(1);
|
|
3204
|
+
}
|
|
3205
|
+
}
|
|
3206
|
+
async function pathExists(path) {
|
|
3207
|
+
try {
|
|
3208
|
+
await stat(path);
|
|
3209
|
+
return true;
|
|
3210
|
+
} catch {
|
|
3211
|
+
return false;
|
|
3212
|
+
}
|
|
3213
|
+
}
|
|
2405
3214
|
async function configInit(options) {
|
|
2406
3215
|
try {
|
|
2407
3216
|
const configPath = join(process.cwd(), ".pspmrc");
|
|
@@ -2799,12 +3608,17 @@ async function writeToCache(cacheDir, integrity, data) {
|
|
|
2799
3608
|
}
|
|
2800
3609
|
}
|
|
2801
3610
|
async function install(specifiers, options) {
|
|
3611
|
+
if (options.global) {
|
|
3612
|
+
const { setGlobalMode: setGlobalMode2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
3613
|
+
setGlobalMode2(true);
|
|
3614
|
+
}
|
|
2802
3615
|
if (specifiers.length > 0) {
|
|
2803
3616
|
const { add: add2 } = await Promise.resolve().then(() => (init_add(), add_exports));
|
|
2804
3617
|
await add2(specifiers, {
|
|
2805
3618
|
save: true,
|
|
2806
3619
|
agent: options.agent,
|
|
2807
|
-
yes: options.yes
|
|
3620
|
+
yes: options.yes,
|
|
3621
|
+
global: options.global
|
|
2808
3622
|
});
|
|
2809
3623
|
return;
|
|
2810
3624
|
}
|
|
@@ -3152,12 +3966,16 @@ Installing ${githubCount} GitHub skill(s)...
|
|
|
3152
3966
|
}
|
|
3153
3967
|
}
|
|
3154
3968
|
if (installedSkills.length > 0 && agents[0] !== "none") {
|
|
3155
|
-
|
|
3156
|
-
|
|
3969
|
+
const globalMode = isGlobalMode();
|
|
3970
|
+
console.log(
|
|
3971
|
+
`
|
|
3972
|
+
Creating symlinks for agent(s): ${agents.join(", ")}${globalMode ? " (global)" : ""}...`
|
|
3973
|
+
);
|
|
3157
3974
|
await createAgentSymlinks(installedSkills, {
|
|
3158
3975
|
agents,
|
|
3159
|
-
projectRoot: process.cwd(),
|
|
3160
|
-
agentConfigs
|
|
3976
|
+
projectRoot: globalMode ? homedir() : process.cwd(),
|
|
3977
|
+
agentConfigs,
|
|
3978
|
+
global: globalMode
|
|
3161
3979
|
});
|
|
3162
3980
|
console.log(" Symlinks created.");
|
|
3163
3981
|
}
|
|
@@ -3183,6 +4001,10 @@ init_manifest2();
|
|
|
3183
4001
|
init_symlinks();
|
|
3184
4002
|
async function link(options) {
|
|
3185
4003
|
try {
|
|
4004
|
+
if (options.global) {
|
|
4005
|
+
const { setGlobalMode: setGlobalMode2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
4006
|
+
setGlobalMode2(true);
|
|
4007
|
+
}
|
|
3186
4008
|
const manifest = await readManifest();
|
|
3187
4009
|
const agentConfigs = manifest?.agents;
|
|
3188
4010
|
let agents;
|
|
@@ -3235,10 +4057,12 @@ async function link(options) {
|
|
|
3235
4057
|
console.log(
|
|
3236
4058
|
`Creating symlinks for ${skills.length} skill(s) to agent(s): ${agents.join(", ")}...`
|
|
3237
4059
|
);
|
|
4060
|
+
const globalMode = options.global ?? false;
|
|
3238
4061
|
await createAgentSymlinks(skills, {
|
|
3239
4062
|
agents,
|
|
3240
|
-
projectRoot: process.cwd(),
|
|
3241
|
-
agentConfigs
|
|
4063
|
+
projectRoot: globalMode ? (await import('os')).homedir() : process.cwd(),
|
|
4064
|
+
agentConfigs,
|
|
4065
|
+
global: globalMode
|
|
3242
4066
|
});
|
|
3243
4067
|
console.log("Symlinks created successfully.");
|
|
3244
4068
|
console.log("\nLinked skills:");
|
|
@@ -3260,8 +4084,13 @@ init_manifest2();
|
|
|
3260
4084
|
init_symlinks();
|
|
3261
4085
|
async function list(options) {
|
|
3262
4086
|
try {
|
|
4087
|
+
if (options.global) {
|
|
4088
|
+
const { setGlobalMode: setGlobalMode2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
4089
|
+
setGlobalMode2(true);
|
|
4090
|
+
}
|
|
3263
4091
|
const registrySkills = await listLockfileSkills();
|
|
3264
4092
|
const githubSkills = await listLockfileGitHubPackages();
|
|
4093
|
+
const wellKnownSkills = await listLockfileWellKnownPackages();
|
|
3265
4094
|
const manifest = await readManifest();
|
|
3266
4095
|
const agentConfigs = manifest?.agents;
|
|
3267
4096
|
const availableAgents = getAvailableAgents(agentConfigs);
|
|
@@ -3330,6 +4159,34 @@ async function list(options) {
|
|
|
3330
4159
|
gitCommit: ghEntry.gitCommit
|
|
3331
4160
|
});
|
|
3332
4161
|
}
|
|
4162
|
+
for (const { specifier, entry } of wellKnownSkills) {
|
|
4163
|
+
const wkEntry = entry;
|
|
4164
|
+
const skillName = wkEntry.name;
|
|
4165
|
+
const sourcePath = getWellKnownSkillPath(wkEntry.hostname, skillName);
|
|
4166
|
+
const absolutePath = join(projectRoot, sourcePath);
|
|
4167
|
+
let status = "installed";
|
|
4168
|
+
try {
|
|
4169
|
+
await access$1(absolutePath);
|
|
4170
|
+
} catch {
|
|
4171
|
+
status = "missing";
|
|
4172
|
+
}
|
|
4173
|
+
const linkedAgents = await getLinkedAgents(
|
|
4174
|
+
skillName,
|
|
4175
|
+
availableAgents,
|
|
4176
|
+
projectRoot,
|
|
4177
|
+
agentConfigs
|
|
4178
|
+
);
|
|
4179
|
+
skills.push({
|
|
4180
|
+
name: skillName,
|
|
4181
|
+
fullName: specifier,
|
|
4182
|
+
version: "well-known",
|
|
4183
|
+
source: "well-known",
|
|
4184
|
+
sourcePath,
|
|
4185
|
+
status,
|
|
4186
|
+
linkedAgents,
|
|
4187
|
+
hostname: wkEntry.hostname
|
|
4188
|
+
});
|
|
4189
|
+
}
|
|
3333
4190
|
if (skills.length === 0) {
|
|
3334
4191
|
console.log("No skills installed.");
|
|
3335
4192
|
return;
|
|
@@ -3342,6 +4199,8 @@ async function list(options) {
|
|
|
3342
4199
|
for (const skill of skills) {
|
|
3343
4200
|
if (skill.source === "registry") {
|
|
3344
4201
|
console.log(` ${skill.fullName}@${skill.version} (registry)`);
|
|
4202
|
+
} else if (skill.source === "well-known") {
|
|
4203
|
+
console.log(` ${skill.name} (well-known: ${skill.hostname})`);
|
|
3345
4204
|
} else {
|
|
3346
4205
|
const refInfo = skill.gitRef ? `${skill.gitRef}@${skill.gitCommit?.slice(0, 7)}` : skill.version;
|
|
3347
4206
|
console.log(` ${skill.fullName} (${refInfo})`);
|
|
@@ -3360,9 +4219,13 @@ async function list(options) {
|
|
|
3360
4219
|
}
|
|
3361
4220
|
const registryCount = skills.filter((s) => s.source === "registry").length;
|
|
3362
4221
|
const githubCount = skills.filter((s) => s.source === "github").length;
|
|
4222
|
+
const wellKnownCount = skills.filter(
|
|
4223
|
+
(s) => s.source === "well-known"
|
|
4224
|
+
).length;
|
|
3363
4225
|
const parts = [];
|
|
3364
4226
|
if (registryCount > 0) parts.push(`${registryCount} registry`);
|
|
3365
4227
|
if (githubCount > 0) parts.push(`${githubCount} github`);
|
|
4228
|
+
if (wellKnownCount > 0) parts.push(`${wellKnownCount} well-known`);
|
|
3366
4229
|
console.log(`
|
|
3367
4230
|
Total: ${skills.length} skill(s) (${parts.join(", ")})`);
|
|
3368
4231
|
} catch (error) {
|
|
@@ -4334,6 +5197,88 @@ async function removeByShortName(shortName, agents, agentConfigs) {
|
|
|
4334
5197
|
process.exit(1);
|
|
4335
5198
|
}
|
|
4336
5199
|
|
|
5200
|
+
// src/commands/search.ts
|
|
5201
|
+
init_api_client();
|
|
5202
|
+
init_config();
|
|
5203
|
+
init_generated();
|
|
5204
|
+
async function search(query, options) {
|
|
5205
|
+
try {
|
|
5206
|
+
const config2 = await resolveConfig();
|
|
5207
|
+
const apiKey = getTokenForRegistry(config2, config2.registryUrl);
|
|
5208
|
+
configure2({ registryUrl: config2.registryUrl, apiKey });
|
|
5209
|
+
const limit = options.limit ?? 20;
|
|
5210
|
+
const sort = options.sort ?? "downloads";
|
|
5211
|
+
if (!options.json) {
|
|
5212
|
+
if (query) {
|
|
5213
|
+
console.log(`Searching for "${query}"...
|
|
5214
|
+
`);
|
|
5215
|
+
} else {
|
|
5216
|
+
console.log("Browsing skills...\n");
|
|
5217
|
+
}
|
|
5218
|
+
}
|
|
5219
|
+
const response = await explorePublicSkills({
|
|
5220
|
+
search: query,
|
|
5221
|
+
sort,
|
|
5222
|
+
limit,
|
|
5223
|
+
page: 1
|
|
5224
|
+
});
|
|
5225
|
+
if (response.status !== 200) {
|
|
5226
|
+
console.error("Error: Failed to search skills");
|
|
5227
|
+
process.exit(1);
|
|
5228
|
+
}
|
|
5229
|
+
const { skills, total } = response.data;
|
|
5230
|
+
if (skills.length === 0) {
|
|
5231
|
+
if (query) {
|
|
5232
|
+
console.log(`No skills found matching "${query}".`);
|
|
5233
|
+
} else {
|
|
5234
|
+
console.log("No skills published yet.");
|
|
5235
|
+
}
|
|
5236
|
+
return;
|
|
5237
|
+
}
|
|
5238
|
+
if (options.json) {
|
|
5239
|
+
console.log(JSON.stringify(skills, null, 2));
|
|
5240
|
+
return;
|
|
5241
|
+
}
|
|
5242
|
+
for (const skill of skills) {
|
|
5243
|
+
const name = `@user/${skill.username}/${skill.name}`;
|
|
5244
|
+
const desc = skill.description ? ` - ${skill.description.slice(0, 80)}${skill.description.length > 80 ? "..." : ""}` : "";
|
|
5245
|
+
const downloads = skill.totalDownloads > 0 ? ` (${formatDownloads(skill.totalDownloads)} downloads)` : "";
|
|
5246
|
+
console.log(` ${name}${downloads}`);
|
|
5247
|
+
if (desc) {
|
|
5248
|
+
console.log(` ${desc.trim()}`);
|
|
5249
|
+
}
|
|
5250
|
+
}
|
|
5251
|
+
const showing = Math.min(skills.length, limit);
|
|
5252
|
+
if (total > showing) {
|
|
5253
|
+
console.log(`
|
|
5254
|
+
Showing ${showing} of ${total} results.`);
|
|
5255
|
+
} else {
|
|
5256
|
+
console.log(`
|
|
5257
|
+
${total} skill(s) found.`);
|
|
5258
|
+
}
|
|
5259
|
+
if (skills.length > 0) {
|
|
5260
|
+
const first = skills[0];
|
|
5261
|
+
console.log(
|
|
5262
|
+
`
|
|
5263
|
+
Install with: pspm add @user/${first.username}/${first.name}`
|
|
5264
|
+
);
|
|
5265
|
+
}
|
|
5266
|
+
} catch (error) {
|
|
5267
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
5268
|
+
console.error(`Error: ${message}`);
|
|
5269
|
+
process.exit(1);
|
|
5270
|
+
}
|
|
5271
|
+
}
|
|
5272
|
+
function formatDownloads(count) {
|
|
5273
|
+
if (count >= 1e6) {
|
|
5274
|
+
return `${(count / 1e6).toFixed(1)}M`;
|
|
5275
|
+
}
|
|
5276
|
+
if (count >= 1e3) {
|
|
5277
|
+
return `${(count / 1e3).toFixed(1)}k`;
|
|
5278
|
+
}
|
|
5279
|
+
return String(count);
|
|
5280
|
+
}
|
|
5281
|
+
|
|
4337
5282
|
// src/commands/unpublish.ts
|
|
4338
5283
|
init_api_client();
|
|
4339
5284
|
init_config();
|
|
@@ -4745,45 +5690,64 @@ program.command("migrate").description(
|
|
|
4745
5690
|
await migrate({ dryRun: options.dryRun });
|
|
4746
5691
|
});
|
|
4747
5692
|
program.command("add <specifiers...>").description(
|
|
4748
|
-
"Add
|
|
5693
|
+
"Add skills from registry, GitHub, local paths, or well-known URLs"
|
|
4749
5694
|
).option("--save", "Save to lockfile (default)").option(
|
|
4750
5695
|
"--agent <agents>",
|
|
4751
5696
|
'Comma-separated agents for symlinks (default: all agents, use "none" to skip)'
|
|
4752
|
-
).option("-y, --yes", "Skip agent selection prompt and use defaults").action(async (specifiers, options) => {
|
|
5697
|
+
).option("-g, --global", "Install to user home directory instead of project").option("-y, --yes", "Skip agent selection prompt and use defaults").action(async (specifiers, options) => {
|
|
4753
5698
|
await add(specifiers, {
|
|
4754
5699
|
save: options.save ?? true,
|
|
4755
5700
|
agent: options.agent,
|
|
4756
|
-
yes: options.yes
|
|
5701
|
+
yes: options.yes,
|
|
5702
|
+
global: options.global
|
|
4757
5703
|
});
|
|
4758
5704
|
});
|
|
4759
5705
|
program.command("remove <name>").alias("rm").description("Remove an installed skill").action(async (name) => {
|
|
4760
5706
|
await remove(name);
|
|
4761
5707
|
});
|
|
4762
|
-
program.command("list").alias("ls").description("List installed skills").option("--json", "Output as JSON").action(async (options) => {
|
|
4763
|
-
await list({ json: options.json });
|
|
5708
|
+
program.command("list").alias("ls").description("List installed skills").option("--json", "Output as JSON").option("-g, --global", "List globally installed skills").action(async (options) => {
|
|
5709
|
+
await list({ json: options.json, global: options.global });
|
|
4764
5710
|
});
|
|
4765
5711
|
program.command("install [specifiers...]").alias("i").description(
|
|
4766
5712
|
"Install skills from lockfile, or add and install specific packages"
|
|
4767
5713
|
).option("--frozen-lockfile", "Fail if lockfile is missing or outdated").option("--dir <path>", "Install skills to a specific directory").option(
|
|
4768
5714
|
"--agent <agents>",
|
|
4769
5715
|
'Comma-separated agents for symlinks (default: all agents, use "none" to skip)'
|
|
4770
|
-
).option("-y, --yes", "Skip agent selection prompt and use defaults").action(async (specifiers, options) => {
|
|
5716
|
+
).option("-g, --global", "Install to user home directory instead of project").option("-y, --yes", "Skip agent selection prompt and use defaults").action(async (specifiers, options) => {
|
|
4771
5717
|
await install(specifiers, {
|
|
4772
5718
|
frozenLockfile: options.frozenLockfile,
|
|
4773
5719
|
dir: options.dir,
|
|
4774
5720
|
agent: options.agent,
|
|
4775
|
-
yes: options.yes
|
|
5721
|
+
yes: options.yes,
|
|
5722
|
+
global: options.global
|
|
4776
5723
|
});
|
|
4777
5724
|
});
|
|
4778
5725
|
program.command("link").description("Recreate agent symlinks without reinstalling").option(
|
|
4779
5726
|
"--agent <agents>",
|
|
4780
5727
|
'Comma-separated agents for symlinks (default: all agents, use "none" to skip)'
|
|
4781
|
-
).option("-y, --yes", "Skip agent selection prompt and use defaults").action(async (options) => {
|
|
4782
|
-
await link({
|
|
5728
|
+
).option("-g, --global", "Recreate global agent symlinks").option("-y, --yes", "Skip agent selection prompt and use defaults").action(async (options) => {
|
|
5729
|
+
await link({
|
|
5730
|
+
agent: options.agent,
|
|
5731
|
+
yes: options.yes,
|
|
5732
|
+
global: options.global
|
|
5733
|
+
});
|
|
4783
5734
|
});
|
|
4784
5735
|
program.command("update").description("Update all skills to latest compatible versions").option("--dry-run", "Show what would be updated without making changes").action(async (options) => {
|
|
4785
5736
|
await update({ dryRun: options.dryRun });
|
|
4786
5737
|
});
|
|
5738
|
+
program.command("search [query]").alias("find").description("Search and discover skills from the registry").option(
|
|
5739
|
+
"-s, --sort <sort>",
|
|
5740
|
+
"Sort by: downloads, recent, name (default: downloads)"
|
|
5741
|
+
).option("-l, --limit <n>", "Maximum results (default: 20)", Number.parseInt).option("--json", "Output as JSON").action(async (query, options) => {
|
|
5742
|
+
await search(query, {
|
|
5743
|
+
sort: options.sort,
|
|
5744
|
+
limit: options.limit,
|
|
5745
|
+
json: options.json
|
|
5746
|
+
});
|
|
5747
|
+
});
|
|
5748
|
+
program.command("audit").description("Verify integrity of installed skills and check for issues").option("--json", "Output as JSON").action(async (options) => {
|
|
5749
|
+
await audit({ json: options.json });
|
|
5750
|
+
});
|
|
4787
5751
|
program.command("outdated [packages...]").description("Check for outdated skills").option("--json", "Output as JSON").option("--all", "Include up-to-date packages").action(async (packages, options) => {
|
|
4788
5752
|
await outdated(packages, { json: options.json, all: options.all });
|
|
4789
5753
|
});
|