@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/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(process.cwd(), ".pspm", "skills");
431
+ return join(getPspmDir(), "skills");
382
432
  }
383
433
  function getCacheDir() {
384
- return join(process.cwd(), ".pspm", "cache");
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
- var SPECIFIER_PATTERN, GITHUB_SPECIFIER_PATTERN;
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 DEFAULT_AGENT_CONFIGS) {
1158
- return DEFAULT_AGENT_CONFIGS[name];
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: ".codex/skills"
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: ".cursor/skills"
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: ".gemini/skills"
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
- kiro: {
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: ".opencode/skills"
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
- "claude-code": { skillsDir: AGENT_INFO["claude-code"].skillsDir },
1223
- codex: { skillsDir: AGENT_INFO.codex.skillsDir },
1224
- cursor: { skillsDir: AGENT_INFO.cursor.skillsDir },
1225
- gemini: { skillsDir: AGENT_INFO.gemini.skillsDir },
1226
- kiro: { skillsDir: AGENT_INFO.kiro.skillsDir },
1227
- opencode: { skillsDir: AGENT_INFO.opencode.skillsDir }
1228
- };
1229
- ALL_AGENTS = [
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 pathExists = await lstat(copySource).catch(() => null);
1335
- if (!pathExists) {
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 stat8 = await lstat(join(sourcePath, entry)).catch(() => null);
1340
- if (stat8?.isDirectory() && !entry.startsWith(".")) {
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: writeFile10 } = await import('fs/promises');
2518
+ const { writeFile: writeFile11 } = await import('fs/promises');
1990
2519
  const tempFile = join(destDir, ".temp.tgz");
1991
- await writeFile10(tempFile, tarballBuffer);
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 writeFile10(tempFile, tarballBuffer);
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: process.cwd(),
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 = parseGitHubSpecifier(specifier);
2650
+ const parsed = parseAnyGitHubFormat(specifier);
2109
2651
  if (!parsed) {
2110
2652
  throw new Error(
2111
- `Invalid GitHub specifier "${specifier}". Use format: github:{owner}/{repo}[/{path}][@{ref}]`
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: process.cwd(),
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: process.cwd(),
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: join16 } = await import('path');
2941
+ const { join: join18 } = await import('path');
2336
2942
  let manifest = null;
2337
2943
  try {
2338
2944
  const content = await readFile10(
2339
- join16(process.cwd(), "pspm.json"),
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
- join16(process.cwd(), "package.json"),
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
- console.log(`
3156
- Creating symlinks for agent(s): ${agents.join(", ")}...`);
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 one or more skills (e.g., @user/bsheng/vite_slides@^2.0.0 or github:owner/repo/path@ref)"
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({ agent: options.agent, yes: options.yes });
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
  });