@anytio/pspm 0.8.0 → 0.9.2

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
@@ -5,8 +5,8 @@ import { join, dirname, basename, resolve, relative } from 'path';
5
5
  import * as ini from 'ini';
6
6
  import ignore from 'ignore';
7
7
  import { createHash, randomBytes } from 'crypto';
8
- import * as semver from 'semver';
9
- import semver__default from 'semver';
8
+ import * as semver2 from 'semver';
9
+ import semver2__default from 'semver';
10
10
  import { checkbox } from '@inquirer/prompts';
11
11
  import { readFileSync } from 'fs';
12
12
  import { fileURLToPath, URL as URL$1 } from 'url';
@@ -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
  };
@@ -239,6 +258,58 @@ async function undeprecateSkillVersion(username, skillName, version3) {
239
258
  };
240
259
  }
241
260
  }
261
+ async function listGithubSkillVersions(owner, repo, name) {
262
+ const config2 = getConfig();
263
+ try {
264
+ const response = await fetch(
265
+ `${config2.baseUrl}/api/skills/@github/${owner}/${repo}/${name}/versions`,
266
+ {
267
+ method: "GET",
268
+ headers: {
269
+ "Content-Type": "application/json",
270
+ ...config2.apiKey ? { Authorization: `Bearer ${config2.apiKey}` } : {}
271
+ }
272
+ }
273
+ );
274
+ if (!response.ok) {
275
+ const error = await response.text();
276
+ return { status: response.status, error };
277
+ }
278
+ const data = await response.json();
279
+ return { status: response.status, data };
280
+ } catch (error) {
281
+ return {
282
+ status: 500,
283
+ error: error instanceof Error ? error.message : "Unknown error"
284
+ };
285
+ }
286
+ }
287
+ async function getGithubSkillVersion(owner, repo, name, version3) {
288
+ const config2 = getConfig();
289
+ try {
290
+ const response = await fetch(
291
+ `${config2.baseUrl}/api/skills/@github/${owner}/${repo}/${name}/versions/${version3}`,
292
+ {
293
+ method: "GET",
294
+ headers: {
295
+ "Content-Type": "application/json",
296
+ ...config2.apiKey ? { Authorization: `Bearer ${config2.apiKey}` } : {}
297
+ }
298
+ }
299
+ );
300
+ if (!response.ok) {
301
+ const error = await response.text();
302
+ return { status: response.status, error };
303
+ }
304
+ const data = await response.json();
305
+ return { status: response.status, data };
306
+ } catch (error) {
307
+ return {
308
+ status: 500,
309
+ error: error instanceof Error ? error.message : "Unknown error"
310
+ };
311
+ }
312
+ }
242
313
  async function changeSkillAccess(username, skillName, input) {
243
314
  const config2 = getConfig();
244
315
  if (!config2) {
@@ -368,22 +439,54 @@ var init_errors = __esm({
368
439
  };
369
440
  }
370
441
  });
442
+
443
+ // src/config.ts
444
+ var config_exports = {};
445
+ __export(config_exports, {
446
+ clearCredentials: () => clearCredentials,
447
+ findProjectConfig: () => findProjectConfig,
448
+ getCacheDir: () => getCacheDir,
449
+ getConfigPath: () => getConfigPath,
450
+ getLegacyLockfilePath: () => getLegacyLockfilePath,
451
+ getLegacySkillsDir: () => getLegacySkillsDir,
452
+ getLockfilePath: () => getLockfilePath,
453
+ getPspmDir: () => getPspmDir,
454
+ getRegistryUrl: () => getRegistryUrl,
455
+ getSkillsDir: () => getSkillsDir,
456
+ getTokenForRegistry: () => getTokenForRegistry,
457
+ isGlobalMode: () => isGlobalMode,
458
+ isLoggedIn: () => isLoggedIn,
459
+ readUserConfig: () => readUserConfig,
460
+ requireApiKey: () => requireApiKey,
461
+ resolveConfig: () => resolveConfig,
462
+ setCredentials: () => setCredentials,
463
+ setGlobalMode: () => setGlobalMode,
464
+ writeUserConfig: () => writeUserConfig
465
+ });
371
466
  function getConfigPath() {
372
467
  return join(homedir(), ".pspmrc");
373
468
  }
374
469
  function getLegacyConfigPath() {
375
470
  return join(homedir(), ".pspm", "config.json");
376
471
  }
472
+ function setGlobalMode(global) {
473
+ _globalMode = global;
474
+ }
475
+ function isGlobalMode() {
476
+ return _globalMode;
477
+ }
377
478
  function getPspmDir() {
479
+ if (_globalMode) return join(homedir(), ".pspm");
378
480
  return join(process.cwd(), ".pspm");
379
481
  }
380
482
  function getSkillsDir() {
381
- return join(process.cwd(), ".pspm", "skills");
483
+ return join(getPspmDir(), "skills");
382
484
  }
383
485
  function getCacheDir() {
384
- return join(process.cwd(), ".pspm", "cache");
486
+ return join(getPspmDir(), "cache");
385
487
  }
386
488
  function getLockfilePath() {
489
+ if (_globalMode) return join(homedir(), ".pspm", "pspm-lock.json");
387
490
  return join(process.cwd(), "pspm-lock.json");
388
491
  }
389
492
  function getLegacyLockfilePath() {
@@ -637,11 +740,12 @@ async function getRegistryUrl() {
637
740
  const resolved = await resolveConfig();
638
741
  return resolved.registryUrl;
639
742
  }
640
- var DEFAULT_REGISTRY_URL;
743
+ var DEFAULT_REGISTRY_URL, _globalMode;
641
744
  var init_config = __esm({
642
745
  "src/config.ts"() {
643
746
  init_errors();
644
747
  DEFAULT_REGISTRY_URL = "https://registry.pspm.dev";
748
+ _globalMode = false;
645
749
  }
646
750
  });
647
751
  async function loadIgnorePatterns(cwd = process.cwd()) {
@@ -734,22 +838,98 @@ var init_manifest = __esm({
734
838
  PSPM_SCHEMA_URL = "https://pspm.dev/schema/v1/pspm.json";
735
839
  }
736
840
  });
737
- function resolveVersion(range, availableVersions) {
738
- const sorted = availableVersions.filter((v) => semver.valid(v)).sort((a, b) => semver.rcompare(a, b));
841
+ var init_integrity2 = __esm({
842
+ "../../packages/shared/pspm-types/src/integrity.ts"() {
843
+ }
844
+ });
845
+
846
+ // ../../packages/shared/pspm-types/src/local.ts
847
+ var init_local = __esm({
848
+ "../../packages/shared/pspm-types/src/local.ts"() {
849
+ }
850
+ });
851
+
852
+ // ../../packages/shared/pspm-types/src/lockfile.ts
853
+ var init_lockfile2 = __esm({
854
+ "../../packages/shared/pspm-types/src/lockfile.ts"() {
855
+ }
856
+ });
857
+
858
+ // ../../packages/shared/pspm-types/src/manifest.ts
859
+ var init_manifest2 = __esm({
860
+ "../../packages/shared/pspm-types/src/manifest.ts"() {
861
+ }
862
+ });
863
+
864
+ // ../../packages/shared/pspm-types/src/specifier.ts
865
+ function parseRegistrySpecifier(specifier) {
866
+ const match = specifier.match(REGISTRY_SPECIFIER_PATTERN);
867
+ if (!match) {
868
+ return null;
869
+ }
870
+ const namespace = match[1];
871
+ const owner = match[2];
872
+ const name = match[3];
873
+ const subname = match[4];
874
+ const versionRange = match[5];
875
+ if (!owner || !name) {
876
+ return null;
877
+ }
878
+ if (namespace === "github" && !subname) {
879
+ return null;
880
+ }
881
+ if (namespace !== "github" && subname) {
882
+ return null;
883
+ }
884
+ return {
885
+ namespace,
886
+ owner,
887
+ name,
888
+ subname: subname || void 0,
889
+ versionRange: versionRange || void 0
890
+ };
891
+ }
892
+ var REGISTRY_SPECIFIER_PATTERN;
893
+ var init_specifier = __esm({
894
+ "../../packages/shared/pspm-types/src/specifier.ts"() {
895
+ REGISTRY_SPECIFIER_PATTERN = /^@(user|org|github)\/([a-zA-Z0-9_-]+)\/([a-zA-Z0-9._-]+)(?:\/([a-z][a-z0-9-]*))?(?:@(.+))?$/;
896
+ }
897
+ });
898
+ var init_version = __esm({
899
+ "../../packages/shared/pspm-types/src/version.ts"() {
900
+ }
901
+ });
902
+
903
+ // ../../packages/shared/pspm-types/src/index.ts
904
+ var init_src = __esm({
905
+ "../../packages/shared/pspm-types/src/index.ts"() {
906
+ init_integrity2();
907
+ init_local();
908
+ init_lockfile2();
909
+ init_manifest2();
910
+ init_specifier();
911
+ init_version();
912
+ }
913
+ });
914
+ function resolveVersion2(range, availableVersions) {
915
+ const sorted = availableVersions.filter((v) => semver2.valid(v)).sort((a, b) => semver2.rcompare(a, b));
739
916
  if (!range || range === "latest" || range === "*") {
740
917
  return sorted[0] ?? null;
741
918
  }
742
- return semver.maxSatisfying(sorted, range);
919
+ return semver2.maxSatisfying(sorted, range);
920
+ }
921
+ function isNewerVersion2(a, b) {
922
+ return semver2.gt(a, b);
743
923
  }
744
924
  function findHighestSatisfying(ranges, availableVersions) {
745
- const sorted = availableVersions.filter((v) => semver.valid(v)).sort((a, b) => semver.rcompare(a, b));
925
+ const sorted = availableVersions.filter((v) => semver2.valid(v)).sort((a, b) => semver2.rcompare(a, b));
746
926
  if (sorted.length === 0) return null;
747
927
  const normalizedRanges = ranges.map(
748
928
  (r) => !r || r === "latest" || r === "*" ? "*" : r
749
929
  );
750
930
  for (const version3 of sorted) {
751
931
  const satisfiesAll = normalizedRanges.every(
752
- (range) => semver.satisfies(version3, range)
932
+ (range) => semver2.satisfies(version3, range)
753
933
  );
754
934
  if (satisfiesAll) {
755
935
  return version3;
@@ -757,7 +937,7 @@ function findHighestSatisfying(ranges, availableVersions) {
757
937
  }
758
938
  return null;
759
939
  }
760
- var init_version = __esm({
940
+ var init_version2 = __esm({
761
941
  "src/lib/version.ts"() {
762
942
  }
763
943
  });
@@ -820,8 +1000,8 @@ async function resolveRecursive(rootDeps, config2) {
820
1000
  continue;
821
1001
  }
822
1002
  processing.add(name);
823
- const match = name.match(/^@user\/([^/]+)\/([^/]+)$/);
824
- if (!match) {
1003
+ const parsed = parseRegistrySpecifier(name);
1004
+ if (!parsed) {
825
1005
  graph.errors.push({
826
1006
  type: "package_not_found",
827
1007
  package: name,
@@ -829,10 +1009,23 @@ async function resolveRecursive(rootDeps, config2) {
829
1009
  });
830
1010
  continue;
831
1011
  }
832
- const [, username, skillName] = match;
833
1012
  try {
834
- const versionsResponse = await listSkillVersions(username, skillName);
835
- if (versionsResponse.status !== 200) {
1013
+ let versionsData;
1014
+ let versionsStatus;
1015
+ if (parsed.namespace === "github" && parsed.subname) {
1016
+ const resp = await listGithubSkillVersions(
1017
+ parsed.owner,
1018
+ parsed.name,
1019
+ parsed.subname
1020
+ );
1021
+ versionsStatus = resp.status;
1022
+ versionsData = resp.data;
1023
+ } else {
1024
+ const resp = await listSkillVersions(parsed.owner, parsed.name);
1025
+ versionsStatus = resp.status;
1026
+ versionsData = resp.status === 200 ? resp.data : void 0;
1027
+ }
1028
+ if (versionsStatus !== 200 || !versionsData) {
836
1029
  graph.errors.push({
837
1030
  type: "package_not_found",
838
1031
  package: name,
@@ -840,8 +1033,7 @@ async function resolveRecursive(rootDeps, config2) {
840
1033
  });
841
1034
  continue;
842
1035
  }
843
- const versions = versionsResponse.data;
844
- if (versions.length === 0) {
1036
+ if (versionsData.length === 0) {
845
1037
  graph.errors.push({
846
1038
  type: "package_not_found",
847
1039
  package: name,
@@ -849,7 +1041,7 @@ async function resolveRecursive(rootDeps, config2) {
849
1041
  });
850
1042
  continue;
851
1043
  }
852
- const availableVersions = versions.map((v) => v.version);
1044
+ const availableVersions = versionsData.map((v) => v.version);
853
1045
  const resolvedVersion = findHighestSatisfying(
854
1046
  [versionRange],
855
1047
  availableVersions
@@ -862,12 +1054,28 @@ async function resolveRecursive(rootDeps, config2) {
862
1054
  });
863
1055
  continue;
864
1056
  }
865
- const versionResponse = await getSkillVersion(
866
- username,
867
- skillName,
868
- resolvedVersion
869
- );
870
- if (versionResponse.status !== 200 || !versionResponse.data) {
1057
+ let versionData = null;
1058
+ if (parsed.namespace === "github" && parsed.subname) {
1059
+ const resp = await getGithubSkillVersion(
1060
+ parsed.owner,
1061
+ parsed.name,
1062
+ parsed.subname,
1063
+ resolvedVersion
1064
+ );
1065
+ if (resp.status === 200 && resp.data) {
1066
+ versionData = resp.data;
1067
+ }
1068
+ } else {
1069
+ const resp = await getSkillVersion(
1070
+ parsed.owner,
1071
+ parsed.name,
1072
+ resolvedVersion
1073
+ );
1074
+ if (resp.status === 200 && resp.data) {
1075
+ versionData = resp.data;
1076
+ }
1077
+ }
1078
+ if (!versionData) {
871
1079
  graph.errors.push({
872
1080
  type: "fetch_error",
873
1081
  package: name,
@@ -875,20 +1083,19 @@ async function resolveRecursive(rootDeps, config2) {
875
1083
  });
876
1084
  continue;
877
1085
  }
878
- const versionInfo = versionResponse.data;
879
- const manifest = versionInfo.manifest;
1086
+ const manifest = versionData.manifest;
880
1087
  const dependencies = manifest?.dependencies ?? {};
881
1088
  const node = {
882
1089
  name,
883
1090
  version: resolvedVersion,
884
1091
  versionRange,
885
- downloadUrl: versionInfo.downloadUrl,
886
- integrity: `sha256-${Buffer.from(versionInfo.checksum, "hex").toString("base64")}`,
1092
+ downloadUrl: versionData.downloadUrl,
1093
+ integrity: `sha256-${Buffer.from(versionData.checksum, "hex").toString("base64")}`,
887
1094
  depth,
888
1095
  dependencies,
889
1096
  dependents: [dependent],
890
1097
  isDirect: depth === 0,
891
- deprecated: versionInfo.deprecationMessage ?? void 0
1098
+ deprecated: versionData.deprecationMessage ?? void 0
892
1099
  };
893
1100
  graph.nodes.set(name, node);
894
1101
  for (const [depName, depRange] of Object.entries(dependencies)) {
@@ -915,14 +1122,23 @@ async function resolveRecursive(rootDeps, config2) {
915
1122
  const uniqueDependents = [...new Set(ranges.map((r) => r.dependent))];
916
1123
  node.dependents = uniqueDependents;
917
1124
  const allRanges = ranges.map((r) => r.range);
918
- const match = name.match(/^@user\/([^/]+)\/([^/]+)$/);
919
- if (!match) continue;
920
- const [, username, skillName] = match;
1125
+ const p2Parsed = parseRegistrySpecifier(name);
1126
+ if (!p2Parsed) continue;
921
1127
  try {
922
- const versionsResponse = await listSkillVersions(username, skillName);
923
- if (versionsResponse.status !== 200) continue;
924
- const versions = versionsResponse.data;
925
- const availableVersions = versions.map((v) => v.version);
1128
+ let p2Versions;
1129
+ if (p2Parsed.namespace === "github" && p2Parsed.subname) {
1130
+ const resp = await listGithubSkillVersions(
1131
+ p2Parsed.owner,
1132
+ p2Parsed.name,
1133
+ p2Parsed.subname
1134
+ );
1135
+ p2Versions = resp.status === 200 ? resp.data : void 0;
1136
+ } else {
1137
+ const resp = await listSkillVersions(p2Parsed.owner, p2Parsed.name);
1138
+ p2Versions = resp.status === 200 ? resp.data : void 0;
1139
+ }
1140
+ if (!p2Versions) continue;
1141
+ const availableVersions = p2Versions.map((v) => v.version);
926
1142
  const finalVersion = findHighestSatisfying(allRanges, availableVersions);
927
1143
  if (!finalVersion) {
928
1144
  graph.conflicts.push({
@@ -941,18 +1157,33 @@ async function resolveRecursive(rootDeps, config2) {
941
1157
  continue;
942
1158
  }
943
1159
  if (finalVersion !== node.version) {
944
- const versionResponse = await getSkillVersion(
945
- username,
946
- skillName,
947
- finalVersion
948
- );
949
- if (versionResponse.status === 200 && versionResponse.data) {
950
- const versionInfo = versionResponse.data;
1160
+ let p2VersionData = null;
1161
+ if (p2Parsed.namespace === "github" && p2Parsed.subname) {
1162
+ const resp = await getGithubSkillVersion(
1163
+ p2Parsed.owner,
1164
+ p2Parsed.name,
1165
+ p2Parsed.subname,
1166
+ finalVersion
1167
+ );
1168
+ if (resp.status === 200 && resp.data) {
1169
+ p2VersionData = resp.data;
1170
+ }
1171
+ } else {
1172
+ const resp = await getSkillVersion(
1173
+ p2Parsed.owner,
1174
+ p2Parsed.name,
1175
+ finalVersion
1176
+ );
1177
+ if (resp.status === 200 && resp.data) {
1178
+ p2VersionData = resp.data;
1179
+ }
1180
+ }
1181
+ if (p2VersionData) {
951
1182
  node.version = finalVersion;
952
- node.downloadUrl = versionInfo.downloadUrl;
953
- node.integrity = `sha256-${Buffer.from(versionInfo.checksum, "hex").toString("base64")}`;
954
- node.deprecated = versionInfo.deprecationMessage ?? void 0;
955
- const manifest = versionInfo.manifest;
1183
+ node.downloadUrl = p2VersionData.downloadUrl;
1184
+ node.integrity = `sha256-${Buffer.from(p2VersionData.checksum, "hex").toString("base64")}`;
1185
+ node.deprecated = p2VersionData.deprecationMessage ?? void 0;
1186
+ const manifest = p2VersionData.manifest;
956
1187
  node.dependencies = manifest?.dependencies ?? {};
957
1188
  }
958
1189
  }
@@ -1067,30 +1298,55 @@ function printResolutionErrors(errors, conflicts = []) {
1067
1298
  var MAX_DEPENDENCY_DEPTH;
1068
1299
  var init_resolver = __esm({
1069
1300
  "src/lib/resolver.ts"() {
1301
+ init_src();
1070
1302
  init_api_client();
1071
- init_version();
1303
+ init_version2();
1072
1304
  MAX_DEPENDENCY_DEPTH = 5;
1073
1305
  }
1074
1306
  });
1075
1307
 
1076
1308
  // src/lib/specifier.ts
1077
- function parseSkillSpecifier(specifier) {
1078
- const match = specifier.match(SPECIFIER_PATTERN);
1309
+ function parseRegistrySpecifier2(specifier) {
1310
+ const match = specifier.match(REGISTRY_SPECIFIER_PATTERN2);
1079
1311
  if (!match) {
1080
1312
  return null;
1081
1313
  }
1082
- const username = match[1];
1083
- const name = match[2];
1084
- if (!username || !name) {
1314
+ const namespace = match[1];
1315
+ const owner = match[2];
1316
+ const name = match[3];
1317
+ const subname = match[4];
1318
+ const versionRange = match[5];
1319
+ if (!owner || !name) {
1320
+ return null;
1321
+ }
1322
+ if (namespace === "github" && !subname) {
1323
+ return null;
1324
+ }
1325
+ if (namespace !== "github" && subname) {
1085
1326
  return null;
1086
1327
  }
1087
1328
  return {
1088
- username,
1329
+ namespace,
1330
+ owner,
1089
1331
  name,
1090
- versionRange: match[3]
1332
+ subname: subname || void 0,
1333
+ versionRange: versionRange || void 0
1091
1334
  };
1092
1335
  }
1093
- function parseGitHubSpecifier(specifier) {
1336
+ function generateRegistryIdentifier2(spec) {
1337
+ let base = `@${spec.namespace}/${spec.owner}/${spec.name}`;
1338
+ if (spec.subname) {
1339
+ base += `/${spec.subname}`;
1340
+ }
1341
+ if (spec.versionRange) {
1342
+ base += `@${spec.versionRange}`;
1343
+ }
1344
+ return base;
1345
+ }
1346
+ function isRegistrySpecifier2(specifier) {
1347
+ return specifier.startsWith("@user/") || specifier.startsWith("@org/") || specifier.startsWith("@github/");
1348
+ }
1349
+ function parseGitHubSpecifier2(specifier) {
1094
1350
  const match = specifier.match(GITHUB_SPECIFIER_PATTERN);
1095
1351
  if (!match) {
1096
1352
  return null;
@@ -1107,7 +1363,7 @@ function parseGitHubSpecifier(specifier) {
1107
1363
  ref: ref || void 0
1108
1364
  };
1109
1365
  }
1110
- function formatGitHubSpecifier(spec) {
1366
+ function formatGitHubSpecifier2(spec) {
1111
1367
  let result = `github:${spec.owner}/${spec.repo}`;
1112
1368
  if (spec.path) {
1113
1369
  result += `/${spec.path}`;
@@ -1117,7 +1373,7 @@ function formatGitHubSpecifier(spec) {
1117
1373
  }
1118
1374
  return result;
1119
1375
  }
1120
- function getGitHubSkillName(spec) {
1376
+ function getGitHubSkillName2(spec) {
1121
1377
  if (spec.path) {
1122
1378
  const segments = spec.path.split("/").filter(Boolean);
1123
1379
  const lastSegment = segments[segments.length - 1];
@@ -1127,14 +1383,60 @@ function getGitHubSkillName(spec) {
1127
1383
  }
1128
1384
  return spec.repo;
1129
1385
  }
1130
- function isGitHubSpecifier(specifier) {
1386
+ function isGitHubSpecifier2(specifier) {
1131
1387
  return specifier.startsWith("github:");
1132
1388
  }
1133
- var SPECIFIER_PATTERN, GITHUB_SPECIFIER_PATTERN;
1134
- var init_specifier = __esm({
1389
+ function isGitHubUrl(input) {
1390
+ return /^https?:\/\/github\.com\/[^/]+\/[^/]+/.test(input);
1391
+ }
1392
+ function parseGitHubUrl(input) {
1393
+ const treeMatch = input.match(GITHUB_URL_TREE_PATTERN);
1394
+ if (treeMatch) {
1395
+ const [, owner, repo, ref, path] = treeMatch;
1396
+ if (!owner || !repo || !ref) return null;
1397
+ return {
1398
+ owner,
1399
+ repo,
1400
+ ref,
1401
+ path: path || void 0
1402
+ };
1403
+ }
1404
+ const repoMatch = input.match(GITHUB_URL_PATTERN);
1405
+ if (repoMatch) {
1406
+ const [, owner, repo] = repoMatch;
1407
+ if (!owner || !repo) return null;
1408
+ return { owner, repo };
1409
+ }
1410
+ return null;
1411
+ }
1412
+ function isGitHubShorthand(input) {
1413
+ if (input.includes(":") || input.startsWith(".") || input.startsWith("/") || input.startsWith("@")) {
1414
+ return false;
1415
+ }
1416
+ return GITHUB_SHORTHAND_PATTERN.test(input);
1417
+ }
1418
+ function parseGitHubShorthand(input) {
1419
+ if (input.includes(":") || input.startsWith(".") || input.startsWith("/") || input.startsWith("@")) {
1420
+ return null;
1421
+ }
1422
+ const match = input.match(GITHUB_SHORTHAND_PATTERN);
1423
+ if (!match) return null;
1424
+ const [, owner, repo, path] = match;
1425
+ if (!owner || !repo) return null;
1426
+ return {
1427
+ owner,
1428
+ repo,
1429
+ path: path || void 0
1430
+ };
1431
+ }
1432
+ var REGISTRY_SPECIFIER_PATTERN2, GITHUB_SPECIFIER_PATTERN, GITHUB_URL_TREE_PATTERN, GITHUB_URL_PATTERN, GITHUB_SHORTHAND_PATTERN;
1433
+ var init_specifier2 = __esm({
1135
1434
  "src/lib/specifier.ts"() {
1136
- SPECIFIER_PATTERN = /^@user\/([a-zA-Z0-9_-]+)\/([a-z][a-z0-9_-]*)(?:@(.+))?$/;
1435
+ REGISTRY_SPECIFIER_PATTERN2 = /^@(user|org|github)\/([a-zA-Z0-9_-]+)\/([a-zA-Z0-9._-]+)(?:\/([a-z][a-z0-9-]*))?(?:@(.+))?$/;
1137
1436
  GITHUB_SPECIFIER_PATTERN = /^github:([a-zA-Z0-9_-]+)\/([a-zA-Z0-9_.-]+)(\/[^@]+)?(?:@(.+))?$/;
1437
+ GITHUB_URL_TREE_PATTERN = /^https?:\/\/github\.com\/([^/]+)\/([^/]+)\/tree\/([^/]+)(?:\/(.+))?$/;
1438
+ GITHUB_URL_PATTERN = /^https?:\/\/github\.com\/([^/]+)\/([^/]+?)(?:\.git)?\/?$/;
1439
+ GITHUB_SHORTHAND_PATTERN = /^([a-zA-Z0-9_-]+)\/([a-zA-Z0-9_.-]+)(?:\/(.+))?$/;
1138
1440
  }
1139
1441
  });
1140
1442
 
@@ -1146,16 +1448,19 @@ var init_lib = __esm({
1146
1448
  init_lockfile();
1147
1449
  init_manifest();
1148
1450
  init_resolver();
1149
- init_specifier();
1150
- init_version();
1451
+ init_specifier2();
1452
+ init_version2();
1151
1453
  }
1152
1454
  });
1153
- function resolveAgentConfig(name, overrides) {
1154
- if (overrides?.[name]) {
1455
+ function resolveAgentConfig(name, overrides, global) {
1456
+ if (!global && overrides?.[name]) {
1155
1457
  return overrides[name];
1156
1458
  }
1157
- if (name in DEFAULT_AGENT_CONFIGS) {
1158
- return DEFAULT_AGENT_CONFIGS[name];
1459
+ if (name in AGENT_INFO) {
1460
+ const info = AGENT_INFO[name];
1461
+ return {
1462
+ skillsDir: global ? info.globalSkillsDir : info.skillsDir
1463
+ };
1159
1464
  }
1160
1465
  return null;
1161
1466
  }
@@ -1193,47 +1498,221 @@ var AGENT_INFO, DEFAULT_AGENT_CONFIGS, ALL_AGENTS;
1193
1498
  var init_agents = __esm({
1194
1499
  "src/agents.ts"() {
1195
1500
  AGENT_INFO = {
1501
+ adal: {
1502
+ displayName: "AdaL",
1503
+ skillsDir: ".adal/skills",
1504
+ globalSkillsDir: ".adal/skills"
1505
+ },
1506
+ amp: {
1507
+ displayName: "Amp",
1508
+ skillsDir: ".agents/skills",
1509
+ globalSkillsDir: ".config/agents/skills"
1510
+ },
1511
+ antigravity: {
1512
+ displayName: "Antigravity",
1513
+ skillsDir: ".agent/skills",
1514
+ globalSkillsDir: ".gemini/antigravity/skills"
1515
+ },
1516
+ augment: {
1517
+ displayName: "Augment",
1518
+ skillsDir: ".augment/skills",
1519
+ globalSkillsDir: ".augment/skills"
1520
+ },
1196
1521
  "claude-code": {
1197
1522
  displayName: "Claude Code",
1198
- skillsDir: ".claude/skills"
1523
+ skillsDir: ".claude/skills",
1524
+ globalSkillsDir: ".claude/skills"
1525
+ },
1526
+ cline: {
1527
+ displayName: "Cline",
1528
+ skillsDir: ".agents/skills",
1529
+ globalSkillsDir: ".agents/skills"
1530
+ },
1531
+ codebuddy: {
1532
+ displayName: "CodeBuddy",
1533
+ skillsDir: ".codebuddy/skills",
1534
+ globalSkillsDir: ".codebuddy/skills"
1199
1535
  },
1200
1536
  codex: {
1201
1537
  displayName: "Codex",
1202
- skillsDir: ".codex/skills"
1538
+ skillsDir: ".agents/skills",
1539
+ globalSkillsDir: ".codex/skills"
1540
+ },
1541
+ "command-code": {
1542
+ displayName: "Command Code",
1543
+ skillsDir: ".commandcode/skills",
1544
+ globalSkillsDir: ".commandcode/skills"
1545
+ },
1546
+ continue: {
1547
+ displayName: "Continue",
1548
+ skillsDir: ".continue/skills",
1549
+ globalSkillsDir: ".continue/skills"
1550
+ },
1551
+ cortex: {
1552
+ displayName: "Cortex Code",
1553
+ skillsDir: ".cortex/skills",
1554
+ globalSkillsDir: ".snowflake/cortex/skills"
1555
+ },
1556
+ crush: {
1557
+ displayName: "Crush",
1558
+ skillsDir: ".crush/skills",
1559
+ globalSkillsDir: ".config/crush/skills"
1203
1560
  },
1204
1561
  cursor: {
1205
1562
  displayName: "Cursor",
1206
- skillsDir: ".cursor/skills"
1563
+ skillsDir: ".agents/skills",
1564
+ globalSkillsDir: ".cursor/skills"
1565
+ },
1566
+ droid: {
1567
+ displayName: "Droid",
1568
+ skillsDir: ".factory/skills",
1569
+ globalSkillsDir: ".factory/skills"
1207
1570
  },
1208
- gemini: {
1571
+ "gemini-cli": {
1209
1572
  displayName: "Gemini CLI",
1210
- skillsDir: ".gemini/skills"
1573
+ skillsDir: ".agents/skills",
1574
+ globalSkillsDir: ".gemini/skills"
1575
+ },
1576
+ "github-copilot": {
1577
+ displayName: "GitHub Copilot",
1578
+ skillsDir: ".agents/skills",
1579
+ globalSkillsDir: ".copilot/skills"
1580
+ },
1581
+ goose: {
1582
+ displayName: "Goose",
1583
+ skillsDir: ".goose/skills",
1584
+ globalSkillsDir: ".config/goose/skills"
1211
1585
  },
1212
- kiro: {
1586
+ "iflow-cli": {
1587
+ displayName: "iFlow CLI",
1588
+ skillsDir: ".iflow/skills",
1589
+ globalSkillsDir: ".iflow/skills"
1590
+ },
1591
+ junie: {
1592
+ displayName: "Junie",
1593
+ skillsDir: ".junie/skills",
1594
+ globalSkillsDir: ".junie/skills"
1595
+ },
1596
+ kilo: {
1597
+ displayName: "Kilo Code",
1598
+ skillsDir: ".kilocode/skills",
1599
+ globalSkillsDir: ".kilocode/skills"
1600
+ },
1601
+ "kimi-cli": {
1602
+ displayName: "Kimi Code CLI",
1603
+ skillsDir: ".agents/skills",
1604
+ globalSkillsDir: ".config/agents/skills"
1605
+ },
1606
+ "kiro-cli": {
1213
1607
  displayName: "Kiro CLI",
1214
- skillsDir: ".kiro/skills"
1608
+ skillsDir: ".kiro/skills",
1609
+ globalSkillsDir: ".kiro/skills"
1610
+ },
1611
+ kode: {
1612
+ displayName: "Kode",
1613
+ skillsDir: ".kode/skills",
1614
+ globalSkillsDir: ".kode/skills"
1615
+ },
1616
+ mcpjam: {
1617
+ displayName: "MCPJam",
1618
+ skillsDir: ".mcpjam/skills",
1619
+ globalSkillsDir: ".mcpjam/skills"
1620
+ },
1621
+ "mistral-vibe": {
1622
+ displayName: "Mistral Vibe",
1623
+ skillsDir: ".vibe/skills",
1624
+ globalSkillsDir: ".vibe/skills"
1625
+ },
1626
+ mux: {
1627
+ displayName: "Mux",
1628
+ skillsDir: ".mux/skills",
1629
+ globalSkillsDir: ".mux/skills"
1630
+ },
1631
+ neovate: {
1632
+ displayName: "Neovate",
1633
+ skillsDir: ".neovate/skills",
1634
+ globalSkillsDir: ".neovate/skills"
1635
+ },
1636
+ openclaw: {
1637
+ displayName: "OpenClaw",
1638
+ skillsDir: "skills",
1639
+ globalSkillsDir: ".openclaw/skills"
1215
1640
  },
1216
1641
  opencode: {
1217
1642
  displayName: "OpenCode",
1218
- skillsDir: ".opencode/skills"
1643
+ skillsDir: ".agents/skills",
1644
+ globalSkillsDir: ".config/opencode/skills"
1645
+ },
1646
+ openhands: {
1647
+ displayName: "OpenHands",
1648
+ skillsDir: ".openhands/skills",
1649
+ globalSkillsDir: ".openhands/skills"
1650
+ },
1651
+ pi: {
1652
+ displayName: "Pi",
1653
+ skillsDir: ".pi/skills",
1654
+ globalSkillsDir: ".pi/agent/skills"
1655
+ },
1656
+ pochi: {
1657
+ displayName: "Pochi",
1658
+ skillsDir: ".pochi/skills",
1659
+ globalSkillsDir: ".pochi/skills"
1660
+ },
1661
+ qoder: {
1662
+ displayName: "Qoder",
1663
+ skillsDir: ".qoder/skills",
1664
+ globalSkillsDir: ".qoder/skills"
1665
+ },
1666
+ "qwen-code": {
1667
+ displayName: "Qwen Code",
1668
+ skillsDir: ".qwen/skills",
1669
+ globalSkillsDir: ".qwen/skills"
1670
+ },
1671
+ replit: {
1672
+ displayName: "Replit",
1673
+ skillsDir: ".agents/skills",
1674
+ globalSkillsDir: ".config/agents/skills"
1675
+ },
1676
+ roo: {
1677
+ displayName: "Roo Code",
1678
+ skillsDir: ".roo/skills",
1679
+ globalSkillsDir: ".roo/skills"
1680
+ },
1681
+ trae: {
1682
+ displayName: "Trae",
1683
+ skillsDir: ".trae/skills",
1684
+ globalSkillsDir: ".trae/skills"
1685
+ },
1686
+ "trae-cn": {
1687
+ displayName: "Trae CN",
1688
+ skillsDir: ".trae/skills",
1689
+ globalSkillsDir: ".trae-cn/skills"
1690
+ },
1691
+ universal: {
1692
+ displayName: "Universal",
1693
+ skillsDir: ".agents/skills",
1694
+ globalSkillsDir: ".config/agents/skills"
1695
+ },
1696
+ windsurf: {
1697
+ displayName: "Windsurf",
1698
+ skillsDir: ".windsurf/skills",
1699
+ globalSkillsDir: ".codeium/windsurf/skills"
1700
+ },
1701
+ zencoder: {
1702
+ displayName: "Zencoder",
1703
+ skillsDir: ".zencoder/skills",
1704
+ globalSkillsDir: ".zencoder/skills"
1219
1705
  }
1220
1706
  };
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
- ];
1707
+ DEFAULT_AGENT_CONFIGS = Object.fromEntries(
1708
+ Object.entries(AGENT_INFO).map(([key, info]) => [
1709
+ key,
1710
+ { skillsDir: info.skillsDir }
1711
+ ])
1712
+ );
1713
+ ALL_AGENTS = Object.keys(
1714
+ AGENT_INFO
1715
+ ).sort();
1237
1716
  }
1238
1717
  });
1239
1718
  function getGitHubHeaders() {
@@ -1331,13 +1810,13 @@ async function extractGitHubPackage(spec, buffer, skillsDir) {
1331
1810
  const sourcePath = join(tempDir, extractedDir);
1332
1811
  const copySource = spec.path ? join(sourcePath, spec.path) : sourcePath;
1333
1812
  if (spec.path) {
1334
- const pathExists = await lstat(copySource).catch(() => null);
1335
- if (!pathExists) {
1813
+ const pathExists2 = await lstat(copySource).catch(() => null);
1814
+ if (!pathExists2) {
1336
1815
  const rootEntries = await readdir(sourcePath);
1337
1816
  const dirs = [];
1338
1817
  for (const entry of rootEntries) {
1339
- const stat8 = await lstat(join(sourcePath, entry)).catch(() => null);
1340
- if (stat8?.isDirectory() && !entry.startsWith(".")) {
1818
+ const stat9 = await lstat(join(sourcePath, entry)).catch(() => null);
1819
+ if (stat9?.isDirectory() && !entry.startsWith(".")) {
1341
1820
  dirs.push(entry);
1342
1821
  }
1343
1822
  }
@@ -1485,6 +1964,9 @@ async function writeLockfile(lockfile) {
1485
1964
  if (lockfile.localPackages && Object.keys(lockfile.localPackages).length > 0) {
1486
1965
  normalized.localPackages = lockfile.localPackages;
1487
1966
  }
1967
+ if (lockfile.wellKnownPackages && Object.keys(lockfile.wellKnownPackages).length > 0) {
1968
+ normalized.wellKnownPackages = lockfile.wellKnownPackages;
1969
+ }
1488
1970
  await writeFile(lockfilePath, `${JSON.stringify(normalized, null, 2)}
1489
1971
  `);
1490
1972
  }
@@ -1589,13 +2071,39 @@ async function addLocalToLockfile(specifier, entry) {
1589
2071
  lockfile.localPackages[specifier] = entry;
1590
2072
  await writeLockfile(lockfile);
1591
2073
  }
1592
- var init_lockfile2 = __esm({
2074
+ async function addWellKnownToLockfile(specifier, entry) {
2075
+ let lockfile = await readLockfile();
2076
+ if (!lockfile) {
2077
+ lockfile = await createEmptyLockfile();
2078
+ }
2079
+ if (!lockfile.wellKnownPackages) {
2080
+ lockfile.wellKnownPackages = {};
2081
+ }
2082
+ lockfile.wellKnownPackages[specifier] = entry;
2083
+ await writeLockfile(lockfile);
2084
+ }
2085
+ async function listLockfileWellKnownPackages() {
2086
+ const lockfile = await readLockfile();
2087
+ if (!lockfile?.wellKnownPackages) {
2088
+ return [];
2089
+ }
2090
+ return Object.entries(lockfile.wellKnownPackages).map(
2091
+ ([specifier, entry]) => ({
2092
+ specifier,
2093
+ entry
2094
+ })
2095
+ );
2096
+ }
2097
+ var init_lockfile3 = __esm({
1593
2098
  "src/lockfile.ts"() {
1594
2099
  init_config();
1595
2100
  init_lib();
1596
2101
  }
1597
2102
  });
1598
2103
  function getManifestPath() {
2104
+ if (isGlobalMode()) {
2105
+ return join(homedir(), ".pspm", "pspm.json");
2106
+ }
1599
2107
  return join(process.cwd(), "pspm.json");
1600
2108
  }
1601
2109
  async function readManifest() {
@@ -1674,8 +2182,23 @@ async function addLocalDependency(specifier, version3 = "*") {
1674
2182
  manifest.localDependencies[specifier] = version3;
1675
2183
  await writeManifest(manifest);
1676
2184
  }
1677
- var init_manifest2 = __esm({
2185
+ async function addWellKnownDependency(baseUrl, skillNames) {
2186
+ const manifest = await ensureManifest();
2187
+ if (!manifest.wellKnownDependencies) {
2188
+ manifest.wellKnownDependencies = {};
2189
+ }
2190
+ const existing = manifest.wellKnownDependencies[baseUrl];
2191
+ if (Array.isArray(existing)) {
2192
+ const merged = [.../* @__PURE__ */ new Set([...existing, ...skillNames])];
2193
+ manifest.wellKnownDependencies[baseUrl] = merged;
2194
+ } else {
2195
+ manifest.wellKnownDependencies[baseUrl] = skillNames;
2196
+ }
2197
+ await writeManifest(manifest);
2198
+ }
2199
+ var init_manifest3 = __esm({
1678
2200
  "src/manifest.ts"() {
2201
+ init_config();
1679
2202
  }
1680
2203
  });
1681
2204
  async function createAgentSymlinks(skills, options) {
@@ -1684,7 +2207,7 @@ async function createAgentSymlinks(skills, options) {
1684
2207
  return;
1685
2208
  }
1686
2209
  for (const agentName of agents) {
1687
- const config2 = resolveAgentConfig(agentName, agentConfigs);
2210
+ const config2 = resolveAgentConfig(agentName, agentConfigs, options.global);
1688
2211
  if (!config2) {
1689
2212
  console.warn(`Warning: Unknown agent "${agentName}", skipping symlinks`);
1690
2213
  continue;
@@ -1744,8 +2267,19 @@ async function removeAgentSymlinks(skillName, options) {
1744
2267
  }
1745
2268
  }
1746
2269
  }
1747
- function getRegistrySkillPath(username, skillName) {
1748
- return `.pspm/skills/${username}/${skillName}`;
2270
+ function getRegistrySkillPath(ownerOrNamespace, skillNameOrOwner, skillName) {
2271
+ if (skillName !== void 0) {
2272
+ const namespace = ownerOrNamespace;
2273
+ const owner = skillNameOrOwner;
2274
+ if (namespace === "org") {
2275
+ return `.pspm/skills/_org/${owner}/${skillName}`;
2276
+ }
2277
+ if (namespace === "github") {
2278
+ return `.pspm/skills/_github-registry/${owner}/${skillName}`;
2279
+ }
2280
+ return `.pspm/skills/${owner}/${skillName}`;
2281
+ }
2282
+ return `.pspm/skills/${ownerOrNamespace}/${skillNameOrOwner}`;
1749
2283
  }
1750
2284
  function getGitHubSkillPath(owner, repo, path) {
1751
2285
  if (path) {
@@ -1756,6 +2290,9 @@ function getGitHubSkillPath(owner, repo, path) {
1756
2290
  function getLocalSkillPath(skillName) {
1757
2291
  return `.pspm/skills/_local/${skillName}`;
1758
2292
  }
2293
+ function getWellKnownSkillPath(hostname, skillName) {
2294
+ return `.pspm/skills/_wellknown/${hostname}/${skillName}`;
2295
+ }
1759
2296
  async function getLinkedAgents(skillName, agents, projectRoot, agentConfigs) {
1760
2297
  const linkedAgents = [];
1761
2298
  for (const agentName of agents) {
@@ -1777,13 +2314,189 @@ var init_symlinks = __esm({
1777
2314
  init_agents();
1778
2315
  }
1779
2316
  });
2317
+ function isWellKnownSpecifier(input) {
2318
+ if (!input.startsWith("http://") && !input.startsWith("https://")) {
2319
+ return false;
2320
+ }
2321
+ try {
2322
+ const parsed = new URL(input);
2323
+ if (EXCLUDED_HOSTS.includes(parsed.hostname)) {
2324
+ return false;
2325
+ }
2326
+ if (input.endsWith(".git")) {
2327
+ return false;
2328
+ }
2329
+ return true;
2330
+ } catch {
2331
+ return false;
2332
+ }
2333
+ }
2334
+ function getWellKnownHostname(url) {
2335
+ try {
2336
+ const parsed = new URL(url);
2337
+ return parsed.hostname.replace(/^www\./, "");
2338
+ } catch {
2339
+ return url;
2340
+ }
2341
+ }
2342
+ function isValidSkillEntry(entry) {
2343
+ if (!entry || typeof entry !== "object") return false;
2344
+ const e = entry;
2345
+ if (typeof e.name !== "string" || e.name.length === 0) return false;
2346
+ if (typeof e.description !== "string" || e.description.length === 0)
2347
+ return false;
2348
+ if (!SKILL_NAME_PATTERN.test(e.name)) return false;
2349
+ if (!Array.isArray(e.files) || e.files.length === 0) return false;
2350
+ let hasSkillMd = false;
2351
+ for (const file of e.files) {
2352
+ if (typeof file !== "string") return false;
2353
+ if (file.startsWith("/") || file.startsWith("\\")) return false;
2354
+ if (file.includes("..")) return false;
2355
+ if (file.toLowerCase() === "skill.md") hasSkillMd = true;
2356
+ }
2357
+ if (!hasSkillMd) return false;
2358
+ return true;
2359
+ }
2360
+ function isValidIndex(data) {
2361
+ if (!data || typeof data !== "object") return false;
2362
+ const d = data;
2363
+ if (!Array.isArray(d.skills)) return false;
2364
+ return d.skills.every(isValidSkillEntry);
2365
+ }
2366
+ async function fetchWellKnownIndex(baseUrl) {
2367
+ const parsed = new URL(baseUrl);
2368
+ const pathRelativeUrl = `${baseUrl.replace(/\/$/, "")}/${WELL_KNOWN_PATH}/${INDEX_FILE}`;
2369
+ const pathRelativeBase = `${baseUrl.replace(/\/$/, "")}/${WELL_KNOWN_PATH}`;
2370
+ try {
2371
+ const response = await fetch(pathRelativeUrl, {
2372
+ signal: AbortSignal.timeout(1e4)
2373
+ });
2374
+ if (response.ok) {
2375
+ const data = await response.json();
2376
+ if (isValidIndex(data)) {
2377
+ return { index: data, resolvedBaseUrl: pathRelativeBase };
2378
+ }
2379
+ }
2380
+ } catch {
2381
+ }
2382
+ const rootUrl = `${parsed.protocol}//${parsed.host}/${WELL_KNOWN_PATH}/${INDEX_FILE}`;
2383
+ const rootBase = `${parsed.protocol}//${parsed.host}/${WELL_KNOWN_PATH}`;
2384
+ if (rootUrl !== pathRelativeUrl) {
2385
+ try {
2386
+ const response = await fetch(rootUrl, {
2387
+ signal: AbortSignal.timeout(1e4)
2388
+ });
2389
+ if (response.ok) {
2390
+ const data = await response.json();
2391
+ if (isValidIndex(data)) {
2392
+ return { index: data, resolvedBaseUrl: rootBase };
2393
+ }
2394
+ }
2395
+ } catch {
2396
+ }
2397
+ }
2398
+ return null;
2399
+ }
2400
+ async function fetchSkillFiles(baseUrl, entry) {
2401
+ const skillBaseUrl = `${baseUrl}/${entry.name}`;
2402
+ const files = /* @__PURE__ */ new Map();
2403
+ let skillMdContent = "";
2404
+ const results = await Promise.allSettled(
2405
+ entry.files.map(async (filePath) => {
2406
+ const fileUrl = `${skillBaseUrl}/${filePath}`;
2407
+ const response = await fetch(fileUrl, {
2408
+ signal: AbortSignal.timeout(1e4)
2409
+ });
2410
+ if (!response.ok) {
2411
+ throw new Error(`Failed to fetch ${fileUrl}: ${response.status}`);
2412
+ }
2413
+ const content = await response.text();
2414
+ return { filePath, content };
2415
+ })
2416
+ );
2417
+ for (const result of results) {
2418
+ if (result.status === "fulfilled") {
2419
+ files.set(result.value.filePath, result.value.content);
2420
+ if (result.value.filePath.toLowerCase() === "skill.md") {
2421
+ skillMdContent = result.value.content;
2422
+ }
2423
+ }
2424
+ }
2425
+ if (!skillMdContent) {
2426
+ return null;
2427
+ }
2428
+ return {
2429
+ name: entry.name,
2430
+ description: entry.description,
2431
+ content: skillMdContent,
2432
+ files,
2433
+ sourceUrl: `${skillBaseUrl}/SKILL.md`,
2434
+ indexEntry: entry
2435
+ };
2436
+ }
2437
+ async function fetchWellKnownSkills(url) {
2438
+ const result = await fetchWellKnownIndex(url);
2439
+ if (!result) return null;
2440
+ const { index, resolvedBaseUrl } = result;
2441
+ const hostname = getWellKnownHostname(url);
2442
+ const skillResults = await Promise.allSettled(
2443
+ index.skills.map((entry) => fetchSkillFiles(resolvedBaseUrl, entry))
2444
+ );
2445
+ const skills = [];
2446
+ for (const r of skillResults) {
2447
+ if (r.status === "fulfilled" && r.value) {
2448
+ skills.push(r.value);
2449
+ }
2450
+ }
2451
+ if (skills.length === 0) return null;
2452
+ return { skills, resolvedBaseUrl, hostname };
2453
+ }
2454
+ async function extractWellKnownSkill(skill, hostname, skillsDir) {
2455
+ const destPath = join(skillsDir, "_wellknown", hostname, skill.name);
2456
+ await rm(destPath, { recursive: true, force: true });
2457
+ await mkdir(destPath, { recursive: true });
2458
+ for (const [filePath, content] of skill.files) {
2459
+ const fullPath = join(destPath, filePath);
2460
+ if (!fullPath.startsWith(destPath)) {
2461
+ continue;
2462
+ }
2463
+ const { dirname: dirname7 } = await import('path');
2464
+ await mkdir(dirname7(fullPath), { recursive: true });
2465
+ await writeFile(fullPath, content, "utf-8");
2466
+ }
2467
+ return `.pspm/skills/_wellknown/${hostname}/${skill.name}`;
2468
+ }
2469
+ function calculateWellKnownIntegrity(skill) {
2470
+ const sortedEntries = [...skill.files.entries()].sort(
2471
+ ([a], [b]) => a.localeCompare(b)
2472
+ );
2473
+ const combined = sortedEntries.map(([path, content]) => `${path}:${content}`).join("\n");
2474
+ return calculateIntegrity(Buffer.from(combined, "utf-8"));
2475
+ }
2476
+ function getWellKnownDisplayName(hostname, skillName) {
2477
+ return `${hostname}/${skillName} (well-known)`;
2478
+ }
2479
+ var WELL_KNOWN_PATH, INDEX_FILE, SKILL_NAME_PATTERN, EXCLUDED_HOSTS;
2480
+ var init_wellknown = __esm({
2481
+ "src/wellknown.ts"() {
2482
+ init_lib();
2483
+ WELL_KNOWN_PATH = ".well-known/skills";
2484
+ INDEX_FILE = "index.json";
2485
+ SKILL_NAME_PATTERN = /^[a-z0-9]([a-z0-9-]{0,62}[a-z0-9])?$/;
2486
+ EXCLUDED_HOSTS = [
2487
+ "github.com",
2488
+ "gitlab.com",
2489
+ "raw.githubusercontent.com"
2490
+ ];
2491
+ }
2492
+ });
1780
2493
 
1781
2494
  // src/commands/add.ts
1782
2495
  var add_exports = {};
1783
2496
  __export(add_exports, {
1784
2497
  add: () => add
1785
2498
  });
1786
- function isLocalSpecifier2(specifier) {
2499
+ function isLocalSpecifier3(specifier) {
1787
2500
  return specifier.startsWith("file:") || specifier.startsWith("./") || specifier.startsWith("../");
1788
2501
  }
1789
2502
  function parseLocalPath(specifier) {
@@ -1792,27 +2505,43 @@ function parseLocalPath(specifier) {
1792
2505
  }
1793
2506
  return specifier;
1794
2507
  }
1795
- function normalizeToFileSpecifier(path) {
2508
+ function normalizeToFileSpecifier2(path) {
1796
2509
  if (path.startsWith("file:")) {
1797
2510
  return path;
1798
2511
  }
1799
2512
  return `file:${path}`;
1800
2513
  }
1801
2514
  async function add(specifiers, options) {
2515
+ if (options.global) {
2516
+ setGlobalMode(true);
2517
+ console.log("Installing globally to ~/.pspm/\n");
2518
+ }
1802
2519
  console.log("Resolving packages...\n");
1803
2520
  const resolvedPackages = [];
1804
2521
  const validationErrors = [];
1805
2522
  for (const specifier of specifiers) {
1806
2523
  try {
1807
- if (isLocalSpecifier2(specifier)) {
2524
+ if (isLocalSpecifier3(specifier)) {
1808
2525
  const resolved = await validateLocalPackage(specifier);
1809
2526
  resolvedPackages.push(resolved);
1810
- } else if (isGitHubSpecifier(specifier)) {
2527
+ } else if (isGitHubSpecifier2(specifier) || isGitHubUrl(specifier) || isGitHubShorthand(specifier)) {
1811
2528
  const resolved = await validateGitHubPackage(specifier);
1812
2529
  resolvedPackages.push(resolved);
1813
- } else {
2530
+ } else if (isWellKnownSpecifier(specifier)) {
2531
+ const resolved = await validateWellKnownPackage(specifier);
2532
+ resolvedPackages.push(resolved);
2533
+ } else if (isRegistrySpecifier2(specifier)) {
1814
2534
  const resolved = await validateRegistryPackage(specifier);
1815
2535
  resolvedPackages.push(resolved);
2536
+ } else {
2537
+ throw new Error(
2538
+ `Unknown specifier format "${specifier}". Supported formats:
2539
+ @user/{username}/{name}[@version] (registry)
2540
+ @org/{orgname}/{name}[@version] (organization)
2541
+ github:owner/repo[/path][@ref] (github)
2542
+ file:./path/to/skill (local)
2543
+ owner/repo (github shorthand)`
2544
+ );
1816
2545
  }
1817
2546
  } catch (error) {
1818
2547
  const message = error instanceof Error ? error.message : "Unknown error";
@@ -1842,11 +2571,19 @@ async function add(specifiers, options) {
1842
2571
  const localPackages = resolvedPackages.filter(
1843
2572
  (p) => p.type === "local"
1844
2573
  );
2574
+ const wellKnownPackages = resolvedPackages.filter(
2575
+ (p) => p.type === "wellknown"
2576
+ );
1845
2577
  let resolutionResult = null;
1846
2578
  if (registryPackages.length > 0) {
1847
2579
  const rootDeps = {};
1848
2580
  for (const pkg of registryPackages) {
1849
- const fullName = `@user/${pkg.username}/${pkg.name}`;
2581
+ const fullName = generateRegistryIdentifier2({
2582
+ namespace: pkg.namespace,
2583
+ owner: pkg.owner,
2584
+ name: pkg.name,
2585
+ subname: pkg.subname
2586
+ });
1850
2587
  rootDeps[fullName] = pkg.versionRange || `^${pkg.resolvedVersion}`;
1851
2588
  }
1852
2589
  console.log("Resolving dependencies...");
@@ -1944,6 +2681,24 @@ async function add(specifiers, options) {
1944
2681
  error: message
1945
2682
  });
1946
2683
  console.error(`Failed to install ${resolved.specifier}: ${message}
2684
+ `);
2685
+ }
2686
+ }
2687
+ for (const resolved of wellKnownPackages) {
2688
+ try {
2689
+ await installWellKnownPackage(resolved, {
2690
+ ...options,
2691
+ resolvedAgents: agents
2692
+ });
2693
+ results.push({ specifier: resolved.specifier, success: true });
2694
+ } catch (error) {
2695
+ const message = error instanceof Error ? error.message : "Unknown error";
2696
+ results.push({
2697
+ specifier: resolved.specifier,
2698
+ success: false,
2699
+ error: message
2700
+ });
2701
+ console.error(`Failed to install ${resolved.specifier}: ${message}
1947
2702
  `);
1948
2703
  }
1949
2704
  }
@@ -1957,12 +2712,15 @@ Summary: ${succeeded} added, ${failed} failed`);
1957
2712
  }
1958
2713
  }
1959
2714
  }
2715
+ function getSymlinkRoot() {
2716
+ return isGlobalMode() ? homedir() : process.cwd();
2717
+ }
1960
2718
  async function installFromNode(node, options) {
1961
- const match = node.name.match(/^@user\/([^/]+)\/([^/]+)$/);
1962
- if (!match) {
2719
+ const parsed = parseRegistrySpecifier2(node.name);
2720
+ if (!parsed) {
1963
2721
  throw new Error(`Invalid package name: ${node.name}`);
1964
2722
  }
1965
- const [, username, name] = match;
2723
+ const { namespace, owner, name, subname } = parsed;
1966
2724
  console.log(`Installing ${node.name}@${node.version}...`);
1967
2725
  const config2 = await resolveConfig();
1968
2726
  const apiKey = getTokenForRegistry(config2, config2.registryUrl);
@@ -1984,18 +2742,26 @@ async function installFromNode(node, options) {
1984
2742
  throw new Error("Checksum verification failed");
1985
2743
  }
1986
2744
  const skillsDir = getSkillsDir();
1987
- const destDir = join(skillsDir, username, name);
2745
+ const effectiveSkillName = subname ?? name;
2746
+ let destDir;
2747
+ if (namespace === "org") {
2748
+ destDir = join(skillsDir, "_org", owner, effectiveSkillName);
2749
+ } else if (namespace === "github" && subname) {
2750
+ destDir = join(skillsDir, "_github-registry", owner, name, subname);
2751
+ } else {
2752
+ destDir = join(skillsDir, owner, effectiveSkillName);
2753
+ }
1988
2754
  await mkdir(destDir, { recursive: true });
1989
- const { writeFile: writeFile10 } = await import('fs/promises');
2755
+ const { writeFile: writeFile11 } = await import('fs/promises');
1990
2756
  const tempFile = join(destDir, ".temp.tgz");
1991
- await writeFile10(tempFile, tarballBuffer);
2757
+ await writeFile11(tempFile, tarballBuffer);
1992
2758
  const { exec: exec2 } = await import('child_process');
1993
2759
  const { promisify: promisify2 } = await import('util');
1994
2760
  const execAsync = promisify2(exec2);
1995
2761
  try {
1996
2762
  await rm(destDir, { recursive: true, force: true });
1997
2763
  await mkdir(destDir, { recursive: true });
1998
- await writeFile10(tempFile, tarballBuffer);
2764
+ await writeFile11(tempFile, tarballBuffer);
1999
2765
  await execAsync(
2000
2766
  `tar -xzf "${tempFile}" -C "${destDir}" --strip-components=1`
2001
2767
  );
@@ -2023,14 +2789,16 @@ async function installFromNode(node, options) {
2023
2789
  const agents = options.resolvedAgents;
2024
2790
  if (agents[0] !== "none") {
2025
2791
  const skillManifest = await readManifest();
2792
+ const pathSkillName = namespace === "github" && subname ? `${name}/${subname}` : name;
2026
2793
  const skillInfo = {
2027
- name,
2028
- sourcePath: getRegistrySkillPath(username, name)
2794
+ name: effectiveSkillName,
2795
+ sourcePath: getRegistrySkillPath(namespace, owner, pathSkillName)
2029
2796
  };
2030
2797
  await createAgentSymlinks([skillInfo], {
2031
2798
  agents,
2032
- projectRoot: process.cwd(),
2033
- agentConfigs: skillManifest?.agents
2799
+ projectRoot: getSymlinkRoot(),
2800
+ agentConfigs: skillManifest?.agents,
2801
+ global: isGlobalMode()
2034
2802
  });
2035
2803
  }
2036
2804
  console.log(`Installed ${node.name}@${node.version}`);
@@ -2040,75 +2808,127 @@ async function validateRegistryPackage(specifier) {
2040
2808
  const config2 = await resolveConfig();
2041
2809
  const registryUrl = config2.registryUrl;
2042
2810
  const apiKey = getTokenForRegistry(config2, registryUrl);
2043
- const parsed = parseSkillSpecifier(specifier);
2811
+ const parsed = parseRegistrySpecifier2(specifier);
2044
2812
  if (!parsed) {
2045
2813
  throw new Error(
2046
- `Invalid skill specifier "${specifier}". Use format: @user/{username}/{name}[@{version}]`
2814
+ `Invalid skill specifier "${specifier}". Use format: @user/{username}/{name}[@{version}] or @org/{orgname}/{name}[@{version}]`
2047
2815
  );
2048
2816
  }
2049
- const { username, name, versionRange } = parsed;
2817
+ const { namespace, owner, name, subname, versionRange } = parsed;
2818
+ const fullName = generateRegistryIdentifier2({
2819
+ namespace,
2820
+ owner,
2821
+ name,
2822
+ subname
2823
+ });
2050
2824
  configure2({ registryUrl, apiKey });
2051
2825
  console.log(`Resolving ${specifier}...`);
2052
- const versionsResponse = await listSkillVersions(username, name);
2053
- if (versionsResponse.status !== 200) {
2054
- if (versionsResponse.status === 401) {
2055
- if (!apiKey) {
2826
+ let versions;
2827
+ if (namespace === "github" && subname) {
2828
+ const versionsResponse = await listGithubSkillVersions(
2829
+ owner,
2830
+ name,
2831
+ subname
2832
+ );
2833
+ if (versionsResponse.status !== 200 || !versionsResponse.data) {
2834
+ if (versionsResponse.status === 401) {
2056
2835
  throw new Error(
2057
- `Package @user/${username}/${name} requires authentication. Please run 'pspm login' to authenticate`
2836
+ apiKey ? `Access denied to ${fullName}. You may not have permission to access this private package.` : `Package ${fullName} requires authentication. Please run 'pspm login' to authenticate`
2058
2837
  );
2059
2838
  }
2060
- throw new Error(
2061
- `Access denied to @user/${username}/${name}. You may not have permission to access this private package.`
2839
+ throw new Error(versionsResponse.error || `Skill ${fullName} not found`);
2840
+ }
2841
+ versions = versionsResponse.data;
2842
+ } else {
2843
+ const versionsResponse = await listSkillVersions(owner, name);
2844
+ if (versionsResponse.status !== 200) {
2845
+ if (versionsResponse.status === 401) {
2846
+ if (!apiKey) {
2847
+ throw new Error(
2848
+ `Package ${fullName} requires authentication. Please run 'pspm login' to authenticate`
2849
+ );
2850
+ }
2851
+ throw new Error(
2852
+ `Access denied to ${fullName}. You may not have permission to access this private package.`
2853
+ );
2854
+ }
2855
+ const errorMessage = extractApiErrorMessage(
2856
+ versionsResponse,
2857
+ `Skill ${fullName} not found`
2062
2858
  );
2859
+ throw new Error(errorMessage);
2063
2860
  }
2064
- const errorMessage = extractApiErrorMessage(
2065
- versionsResponse,
2066
- `Skill @user/${username}/${name} not found`
2067
- );
2068
- throw new Error(errorMessage);
2861
+ versions = versionsResponse.data;
2069
2862
  }
2070
- const versions = versionsResponse.data;
2071
2863
  if (versions.length === 0) {
2072
- throw new Error(`Skill @user/${username}/${name} not found`);
2864
+ throw new Error(`Skill ${fullName} not found`);
2073
2865
  }
2074
2866
  const versionStrings = versions.map((v) => v.version);
2075
- const resolvedVersion = resolveVersion(versionRange || "*", versionStrings);
2867
+ const resolvedVersion = resolveVersion2(versionRange || "*", versionStrings);
2076
2868
  if (!resolvedVersion) {
2077
2869
  throw new Error(
2078
- `No version matching "${versionRange || "latest"}" found for @user/${username}/${name}. Available versions: ${versionStrings.join(", ")}`
2870
+ `No version matching "${versionRange || "latest"}" found for ${fullName}. Available versions: ${versionStrings.join(", ")}`
2079
2871
  );
2080
2872
  }
2081
- const versionResponse = await getSkillVersion(
2082
- username,
2083
- name,
2084
- resolvedVersion
2085
- );
2086
- if (versionResponse.status !== 200 || !versionResponse.data) {
2087
- const errorMessage = extractApiErrorMessage(
2088
- versionResponse,
2089
- `Version ${resolvedVersion} not found`
2873
+ let downloadUrl;
2874
+ let checksum;
2875
+ if (namespace === "github" && subname) {
2876
+ const versionResponse = await getGithubSkillVersion(
2877
+ owner,
2878
+ name,
2879
+ subname,
2880
+ resolvedVersion
2090
2881
  );
2091
- throw new Error(errorMessage);
2882
+ if (versionResponse.status !== 200 || !versionResponse.data) {
2883
+ throw new Error(`Version ${resolvedVersion} not found for ${fullName}`);
2884
+ }
2885
+ downloadUrl = versionResponse.data.downloadUrl;
2886
+ checksum = versionResponse.data.checksum;
2887
+ } else {
2888
+ const versionResponse = await getSkillVersion(owner, name, resolvedVersion);
2889
+ if (versionResponse.status !== 200 || !versionResponse.data) {
2890
+ const errorMessage = extractApiErrorMessage(
2891
+ versionResponse,
2892
+ `Version ${resolvedVersion} not found`
2893
+ );
2894
+ throw new Error(errorMessage);
2895
+ }
2896
+ downloadUrl = versionResponse.data.downloadUrl;
2897
+ checksum = versionResponse.data.checksum;
2092
2898
  }
2093
- console.log(`Resolved @user/${username}/${name}@${resolvedVersion}`);
2899
+ console.log(`Resolved ${fullName}@${resolvedVersion}`);
2094
2900
  return {
2095
2901
  type: "registry",
2096
2902
  specifier,
2097
- username,
2903
+ namespace,
2904
+ owner,
2098
2905
  name,
2906
+ subname,
2099
2907
  versionRange,
2100
2908
  resolvedVersion,
2101
- versionInfo: {
2102
- downloadUrl: versionResponse.data.downloadUrl,
2103
- checksum: versionResponse.data.checksum
2104
- }
2909
+ versionInfo: { downloadUrl, checksum }
2105
2910
  };
2106
2911
  }
2912
+ function parseAnyGitHubFormat(specifier) {
2913
+ if (isGitHubSpecifier2(specifier)) {
2914
+ return parseGitHubSpecifier2(specifier);
2915
+ }
2916
+ if (isGitHubUrl(specifier)) {
2917
+ return parseGitHubUrl(specifier);
2918
+ }
2919
+ if (isGitHubShorthand(specifier)) {
2920
+ return parseGitHubShorthand(specifier);
2921
+ }
2922
+ return null;
2923
+ }
2107
2924
  async function validateGitHubPackage(specifier) {
2108
- const parsed = parseGitHubSpecifier(specifier);
2925
+ const parsed = parseAnyGitHubFormat(specifier);
2109
2926
  if (!parsed) {
2110
2927
  throw new Error(
2111
- `Invalid GitHub specifier "${specifier}". Use format: github:{owner}/{repo}[/{path}][@{ref}]`
2928
+ `Invalid GitHub specifier "${specifier}". Supported formats:
2929
+ github:owner/repo[/path][@ref]
2930
+ https://github.com/owner/repo[/tree/branch/path]
2931
+ owner/repo[/path]`
2112
2932
  );
2113
2933
  }
2114
2934
  const ref = parsed.ref || "HEAD";
@@ -2134,7 +2954,7 @@ async function installGitHubPackage(resolved, options) {
2134
2954
  downloadResult.buffer,
2135
2955
  skillsDir
2136
2956
  );
2137
- const lockfileSpecifier = formatGitHubSpecifier({
2957
+ const lockfileSpecifier = formatGitHubSpecifier2({
2138
2958
  owner: parsed.owner,
2139
2959
  repo: parsed.repo,
2140
2960
  path: parsed.path
@@ -2152,15 +2972,16 @@ async function installGitHubPackage(resolved, options) {
2152
2972
  const agents = options.resolvedAgents;
2153
2973
  if (agents[0] !== "none") {
2154
2974
  const manifest = await readManifest();
2155
- const skillName = getGitHubSkillName(parsed);
2975
+ const skillName = getGitHubSkillName2(parsed);
2156
2976
  const skillInfo = {
2157
2977
  name: skillName,
2158
2978
  sourcePath: getGitHubSkillPath(parsed.owner, parsed.repo, parsed.path)
2159
2979
  };
2160
2980
  await createAgentSymlinks([skillInfo], {
2161
2981
  agents,
2162
- projectRoot: process.cwd(),
2163
- agentConfigs: manifest?.agents
2982
+ projectRoot: getSymlinkRoot(),
2983
+ agentConfigs: manifest?.agents,
2984
+ global: isGlobalMode()
2164
2985
  });
2165
2986
  }
2166
2987
  console.log(
@@ -2171,7 +2992,7 @@ async function installGitHubPackage(resolved, options) {
2171
2992
  async function validateLocalPackage(specifier) {
2172
2993
  const path = parseLocalPath(specifier);
2173
2994
  const resolvedPath = resolve(process.cwd(), path);
2174
- const normalizedSpecifier = normalizeToFileSpecifier(path);
2995
+ const normalizedSpecifier = normalizeToFileSpecifier2(path);
2175
2996
  console.log(`Resolving ${specifier}...`);
2176
2997
  try {
2177
2998
  const stats = await stat(resolvedPath);
@@ -2246,13 +3067,72 @@ async function installLocalPackage(resolved, options) {
2246
3067
  };
2247
3068
  await createAgentSymlinks([skillInfo], {
2248
3069
  agents,
2249
- projectRoot: process.cwd(),
2250
- agentConfigs: manifest?.agents
3070
+ projectRoot: getSymlinkRoot(),
3071
+ agentConfigs: manifest?.agents,
3072
+ global: isGlobalMode()
2251
3073
  });
2252
3074
  }
2253
3075
  console.log(`Installed ${specifier} (local)`);
2254
3076
  console.log(`Location: ${symlinkPath} -> ${resolvedPath}`);
2255
3077
  }
3078
+ async function validateWellKnownPackage(specifier) {
3079
+ const hostname = getWellKnownHostname(specifier);
3080
+ console.log(`Discovering skills from ${hostname}...`);
3081
+ const result = await fetchWellKnownSkills(specifier);
3082
+ if (!result) {
3083
+ throw new Error(
3084
+ `No well-known skills found at ${specifier}
3085
+ Expected: ${specifier}/.well-known/skills/index.json`
3086
+ );
3087
+ }
3088
+ console.log(
3089
+ `Found ${result.skills.length} skill(s) from ${hostname}: ${result.skills.map((s) => s.name).join(", ")}`
3090
+ );
3091
+ return {
3092
+ type: "wellknown",
3093
+ specifier,
3094
+ hostname: result.hostname,
3095
+ skills: result.skills,
3096
+ resolvedBaseUrl: result.resolvedBaseUrl
3097
+ };
3098
+ }
3099
+ async function installWellKnownPackage(resolved, options) {
3100
+ const { specifier, hostname, skills } = resolved;
3101
+ const skillsDir = getSkillsDir();
3102
+ for (const skill of skills) {
3103
+ console.log(
3104
+ `Installing ${getWellKnownDisplayName(hostname, skill.name)}...`
3105
+ );
3106
+ const destPath = await extractWellKnownSkill(skill, hostname, skillsDir);
3107
+ const integrity = calculateWellKnownIntegrity(skill);
3108
+ const lockfileKey = `${specifier}#${skill.name}`;
3109
+ const entry = {
3110
+ version: "well-known",
3111
+ resolved: skill.sourceUrl,
3112
+ integrity,
3113
+ hostname,
3114
+ name: skill.name,
3115
+ files: [...skill.files.keys()]
3116
+ };
3117
+ await addWellKnownToLockfile(lockfileKey, entry);
3118
+ await addWellKnownDependency(specifier, [skill.name]);
3119
+ const agents = options.resolvedAgents;
3120
+ if (agents[0] !== "none") {
3121
+ const manifest = await readManifest();
3122
+ const skillInfo = {
3123
+ name: skill.name,
3124
+ sourcePath: getWellKnownSkillPath(hostname, skill.name)
3125
+ };
3126
+ await createAgentSymlinks([skillInfo], {
3127
+ agents,
3128
+ projectRoot: process.cwd(),
3129
+ agentConfigs: manifest?.agents
3130
+ });
3131
+ }
3132
+ console.log(`Installed ${getWellKnownDisplayName(hostname, skill.name)}`);
3133
+ console.log(`Location: ${destPath}`);
3134
+ }
3135
+ }
2256
3136
  var init_add = __esm({
2257
3137
  "src/commands/add.ts"() {
2258
3138
  init_agents();
@@ -2261,9 +3141,10 @@ var init_add = __esm({
2261
3141
  init_errors();
2262
3142
  init_github();
2263
3143
  init_lib();
2264
- init_lockfile2();
2265
- init_manifest2();
3144
+ init_lockfile3();
3145
+ init_manifest3();
2266
3146
  init_symlinks();
3147
+ init_wellknown();
2267
3148
  }
2268
3149
  });
2269
3150
 
@@ -2271,7 +3152,7 @@ var init_add = __esm({
2271
3152
  init_api_client();
2272
3153
  init_config();
2273
3154
  init_lib();
2274
- function isLocalSpecifier(specifier) {
3155
+ function isLocalSpecifier2(specifier) {
2275
3156
  return specifier.startsWith("file:") || specifier.startsWith("./") || specifier.startsWith("../");
2276
3157
  }
2277
3158
  async function access(specifier, options) {
@@ -2290,8 +3171,8 @@ async function access(specifier, options) {
2290
3171
  let packageName;
2291
3172
  let packageUsername;
2292
3173
  if (specifier) {
2293
- if (isGitHubSpecifier(specifier)) {
2294
- const ghSpec = parseGitHubSpecifier(specifier);
3174
+ if (isGitHubSpecifier2(specifier)) {
3175
+ const ghSpec = parseGitHubSpecifier2(specifier);
2295
3176
  if (ghSpec) {
2296
3177
  console.error(`Error: Cannot change visibility of GitHub packages.`);
2297
3178
  console.error(
@@ -2306,7 +3187,7 @@ async function access(specifier, options) {
2306
3187
  }
2307
3188
  process.exit(1);
2308
3189
  }
2309
- if (isLocalSpecifier(specifier)) {
3190
+ if (isLocalSpecifier2(specifier)) {
2310
3191
  console.error(`Error: Cannot change visibility of local packages.`);
2311
3192
  console.error(
2312
3193
  ` "${specifier}" is a local directory, not a registry package.`
@@ -2316,10 +3197,12 @@ async function access(specifier, options) {
2316
3197
  );
2317
3198
  process.exit(1);
2318
3199
  }
2319
- const parsed = parseSkillSpecifier(specifier);
3200
+ const parsed = parseRegistrySpecifier2(specifier);
2320
3201
  if (!parsed) {
2321
3202
  console.error(`Error: Invalid package specifier "${specifier}".`);
2322
- console.error(` Use format: @user/{username}/{name}`);
3203
+ console.error(
3204
+ ` Use format: @user/{username}/{name} or @org/{orgname}/{name}`
3205
+ );
2323
3206
  console.error(``);
2324
3207
  console.error(` Examples:`);
2325
3208
  console.error(` pspm access @user/myname/my-skill --public`);
@@ -2329,21 +3212,21 @@ async function access(specifier, options) {
2329
3212
  process.exit(1);
2330
3213
  }
2331
3214
  packageName = parsed.name;
2332
- packageUsername = parsed.username;
3215
+ packageUsername = parsed.owner;
2333
3216
  } else {
2334
3217
  const { readFile: readFile10 } = await import('fs/promises');
2335
- const { join: join16 } = await import('path');
3218
+ const { join: join18 } = await import('path');
2336
3219
  let manifest = null;
2337
3220
  try {
2338
3221
  const content = await readFile10(
2339
- join16(process.cwd(), "pspm.json"),
3222
+ join18(process.cwd(), "pspm.json"),
2340
3223
  "utf-8"
2341
3224
  );
2342
3225
  manifest = JSON.parse(content);
2343
3226
  } catch {
2344
3227
  try {
2345
3228
  const content = await readFile10(
2346
- join16(process.cwd(), "package.json"),
3229
+ join18(process.cwd(), "package.json"),
2347
3230
  "utf-8"
2348
3231
  );
2349
3232
  manifest = JSON.parse(content);
@@ -2385,7 +3268,7 @@ async function access(specifier, options) {
2385
3268
  }
2386
3269
  const result = response.data;
2387
3270
  console.log(
2388
- `+ @user/${result.username}/${result.name} is now ${result.visibility}`
3271
+ `+ @${result.namespace ?? "user"}/${result.username}/${result.name} is now ${result.visibility}`
2389
3272
  );
2390
3273
  if (visibility === "public") {
2391
3274
  console.log("");
@@ -2402,6 +3285,209 @@ async function access(specifier, options) {
2402
3285
 
2403
3286
  // src/commands/index.ts
2404
3287
  init_add();
3288
+
3289
+ // src/commands/audit.ts
3290
+ init_config();
3291
+ init_lib();
3292
+ init_lockfile3();
3293
+ async function audit(options) {
3294
+ try {
3295
+ const lockfile = await readLockfile();
3296
+ if (!lockfile) {
3297
+ if (options.json) {
3298
+ console.log(
3299
+ JSON.stringify({
3300
+ ok: false,
3301
+ issues: [
3302
+ {
3303
+ name: "-",
3304
+ source: "-",
3305
+ severity: "error",
3306
+ type: "no-lockfile",
3307
+ message: "No lockfile found. Run 'pspm install' first."
3308
+ }
3309
+ ]
3310
+ })
3311
+ );
3312
+ } else {
3313
+ console.error("No lockfile found. Run 'pspm install' to create one.");
3314
+ }
3315
+ process.exit(1);
3316
+ }
3317
+ const issues = [];
3318
+ const skillsDir = getSkillsDir();
3319
+ const projectRoot = process.cwd();
3320
+ if (!options.json) {
3321
+ console.log("Auditing installed skills...\n");
3322
+ }
3323
+ const registrySkills = await listLockfileSkills();
3324
+ for (const { name: fullName, entry } of registrySkills) {
3325
+ const match = fullName.match(/^@user\/([^/]+)\/([^/]+)$/);
3326
+ if (!match) continue;
3327
+ const [, username, skillName] = match;
3328
+ const destDir = join(projectRoot, skillsDir, username, skillName);
3329
+ const exists = await pathExists(destDir);
3330
+ if (!exists) {
3331
+ issues.push({
3332
+ name: fullName,
3333
+ source: "registry",
3334
+ severity: "error",
3335
+ type: "missing",
3336
+ message: `Not installed on disk. Run 'pspm install' to restore.`
3337
+ });
3338
+ continue;
3339
+ }
3340
+ if (entry.deprecated) {
3341
+ issues.push({
3342
+ name: fullName,
3343
+ source: "registry",
3344
+ severity: "warning",
3345
+ type: "deprecated",
3346
+ message: `Deprecated: ${entry.deprecated}`
3347
+ });
3348
+ }
3349
+ const skillMdExists = await pathExists(join(destDir, "SKILL.md"));
3350
+ if (!skillMdExists) {
3351
+ issues.push({
3352
+ name: fullName,
3353
+ source: "registry",
3354
+ severity: "warning",
3355
+ type: "integrity",
3356
+ message: "Missing SKILL.md in installed directory. Package may be corrupted."
3357
+ });
3358
+ }
3359
+ }
3360
+ const githubSkills = await listLockfileGitHubPackages();
3361
+ for (const { specifier } of githubSkills) {
3362
+ const parsed = parseGitHubSpecifier2(specifier);
3363
+ if (!parsed) continue;
3364
+ const destDir = parsed.path ? join(
3365
+ projectRoot,
3366
+ skillsDir,
3367
+ "_github",
3368
+ parsed.owner,
3369
+ parsed.repo,
3370
+ parsed.path
3371
+ ) : join(projectRoot, skillsDir, "_github", parsed.owner, parsed.repo);
3372
+ const exists = await pathExists(destDir);
3373
+ if (!exists) {
3374
+ issues.push({
3375
+ name: specifier,
3376
+ source: "github",
3377
+ severity: "error",
3378
+ type: "missing",
3379
+ message: `Not installed on disk. Run 'pspm install' to restore.`
3380
+ });
3381
+ continue;
3382
+ }
3383
+ const skillMdExists = await pathExists(join(destDir, "SKILL.md"));
3384
+ if (!skillMdExists) {
3385
+ issues.push({
3386
+ name: specifier,
3387
+ source: "github",
3388
+ severity: "warning",
3389
+ type: "integrity",
3390
+ message: "Missing SKILL.md in installed directory. Package may be corrupted."
3391
+ });
3392
+ }
3393
+ }
3394
+ const wellKnownSkills = await listLockfileWellKnownPackages();
3395
+ for (const { specifier, entry } of wellKnownSkills) {
3396
+ const wkEntry = entry;
3397
+ const destDir = join(
3398
+ projectRoot,
3399
+ skillsDir,
3400
+ "_wellknown",
3401
+ wkEntry.hostname,
3402
+ wkEntry.name
3403
+ );
3404
+ const exists = await pathExists(destDir);
3405
+ if (!exists) {
3406
+ issues.push({
3407
+ name: specifier,
3408
+ source: "well-known",
3409
+ severity: "error",
3410
+ type: "missing",
3411
+ message: `Not installed on disk. Run 'pspm install' to restore.`
3412
+ });
3413
+ continue;
3414
+ }
3415
+ const skillMdExists = await pathExists(join(destDir, "SKILL.md"));
3416
+ if (!skillMdExists) {
3417
+ issues.push({
3418
+ name: specifier,
3419
+ source: "well-known",
3420
+ severity: "warning",
3421
+ type: "integrity",
3422
+ message: "Missing SKILL.md in installed directory. Package may be corrupted."
3423
+ });
3424
+ }
3425
+ }
3426
+ const errorCount = issues.filter((i) => i.severity === "error").length;
3427
+ const warningCount = issues.filter((i) => i.severity === "warning").length;
3428
+ if (options.json) {
3429
+ console.log(
3430
+ JSON.stringify(
3431
+ {
3432
+ ok: errorCount === 0,
3433
+ totalPackages: registrySkills.length + githubSkills.length + wellKnownSkills.length,
3434
+ issues
3435
+ },
3436
+ null,
3437
+ 2
3438
+ )
3439
+ );
3440
+ if (errorCount > 0) process.exit(1);
3441
+ return;
3442
+ }
3443
+ if (issues.length === 0) {
3444
+ const totalPackages2 = registrySkills.length + githubSkills.length + wellKnownSkills.length;
3445
+ console.log(`Audited ${totalPackages2} package(s). No issues found.`);
3446
+ return;
3447
+ }
3448
+ const errors = issues.filter((i) => i.severity === "error");
3449
+ const warnings = issues.filter((i) => i.severity === "warning");
3450
+ if (errors.length > 0) {
3451
+ console.log("Errors:");
3452
+ for (const issue of errors) {
3453
+ console.log(
3454
+ ` [${issue.type.toUpperCase()}] ${issue.name} (${issue.source})`
3455
+ );
3456
+ console.log(` ${issue.message}`);
3457
+ }
3458
+ console.log();
3459
+ }
3460
+ if (warnings.length > 0) {
3461
+ console.log("Warnings:");
3462
+ for (const issue of warnings) {
3463
+ console.log(
3464
+ ` [${issue.type.toUpperCase()}] ${issue.name} (${issue.source})`
3465
+ );
3466
+ console.log(` ${issue.message}`);
3467
+ }
3468
+ console.log();
3469
+ }
3470
+ const totalPackages = registrySkills.length + githubSkills.length + wellKnownSkills.length;
3471
+ console.log(
3472
+ `Audited ${totalPackages} package(s): ${errorCount} error(s), ${warningCount} warning(s).`
3473
+ );
3474
+ if (errorCount > 0) {
3475
+ process.exit(1);
3476
+ }
3477
+ } catch (error) {
3478
+ const message = error instanceof Error ? error.message : "Unknown error";
3479
+ console.error(`Error: ${message}`);
3480
+ process.exit(1);
3481
+ }
3482
+ }
3483
+ async function pathExists(path) {
3484
+ try {
3485
+ await stat(path);
3486
+ return true;
3487
+ } catch {
3488
+ return false;
3489
+ }
3490
+ }
2405
3491
  async function configInit(options) {
2406
3492
  try {
2407
3493
  const configPath = join(process.cwd(), ".pspmrc");
@@ -2471,14 +3557,19 @@ async function deprecate(specifier, message, options) {
2471
3557
  try {
2472
3558
  const apiKey = await requireApiKey();
2473
3559
  const registryUrl = await getRegistryUrl();
2474
- const parsed = parseSkillSpecifier(specifier);
3560
+ const parsed = parseRegistrySpecifier2(specifier);
2475
3561
  if (!parsed) {
2476
3562
  console.error(
2477
- `Error: Invalid skill specifier "${specifier}". Use format: @user/{username}/{name}@{version}`
3563
+ `Error: Invalid skill specifier "${specifier}". Use format: @user/{username}/{name}@{version} or @org/{orgname}/{name}@{version}`
2478
3564
  );
2479
3565
  process.exit(1);
2480
3566
  }
2481
- const { username, name, versionRange } = parsed;
3567
+ const { owner, name, versionRange } = parsed;
3568
+ const fullName = generateRegistryIdentifier2({
3569
+ namespace: parsed.namespace,
3570
+ owner,
3571
+ name
3572
+ });
2482
3573
  if (!versionRange) {
2483
3574
  console.error(
2484
3575
  "Error: Version is required for deprecation. Use format: @user/{username}/{name}@{version}"
@@ -2487,23 +3578,15 @@ async function deprecate(specifier, message, options) {
2487
3578
  }
2488
3579
  configure2({ registryUrl, apiKey });
2489
3580
  if (options.undo) {
2490
- console.log(
2491
- `Removing deprecation from @user/${username}/${name}@${versionRange}...`
2492
- );
2493
- const response = await undeprecateSkillVersion(
2494
- username,
2495
- name,
2496
- versionRange
2497
- );
3581
+ console.log(`Removing deprecation from ${fullName}@${versionRange}...`);
3582
+ const response = await undeprecateSkillVersion(owner, name, versionRange);
2498
3583
  if (response.status !== 200) {
2499
3584
  console.error(
2500
3585
  `Error: ${response.error || "Failed to remove deprecation"}`
2501
3586
  );
2502
3587
  process.exit(1);
2503
3588
  }
2504
- console.log(
2505
- `Removed deprecation from @user/${username}/${name}@${versionRange}`
2506
- );
3589
+ console.log(`Removed deprecation from ${fullName}@${versionRange}`);
2507
3590
  } else {
2508
3591
  if (!message) {
2509
3592
  console.error(
@@ -2511,9 +3594,9 @@ async function deprecate(specifier, message, options) {
2511
3594
  );
2512
3595
  process.exit(1);
2513
3596
  }
2514
- console.log(`Deprecating @user/${username}/${name}@${versionRange}...`);
3597
+ console.log(`Deprecating ${fullName}@${versionRange}...`);
2515
3598
  const response = await deprecateSkillVersion(
2516
- username,
3599
+ owner,
2517
3600
  name,
2518
3601
  versionRange,
2519
3602
  message
@@ -2524,7 +3607,7 @@ async function deprecate(specifier, message, options) {
2524
3607
  );
2525
3608
  process.exit(1);
2526
3609
  }
2527
- console.log(`Deprecated @user/${username}/${name}@${versionRange}`);
3610
+ console.log(`Deprecated ${fullName}@${versionRange}`);
2528
3611
  console.log(`Message: ${message}`);
2529
3612
  console.log("");
2530
3613
  console.log(
@@ -2764,8 +3847,8 @@ init_config();
2764
3847
  init_errors();
2765
3848
  init_github();
2766
3849
  init_lib();
2767
- init_lockfile2();
2768
- init_manifest2();
3850
+ init_lockfile3();
3851
+ init_manifest3();
2769
3852
  init_symlinks();
2770
3853
  function getCacheFilePath(cacheDir, integrity) {
2771
3854
  const match = integrity.match(/^sha256-(.+)$/);
@@ -2799,12 +3882,17 @@ async function writeToCache(cacheDir, integrity, data) {
2799
3882
  }
2800
3883
  }
2801
3884
  async function install(specifiers, options) {
3885
+ if (options.global) {
3886
+ const { setGlobalMode: setGlobalMode2 } = await Promise.resolve().then(() => (init_config(), config_exports));
3887
+ setGlobalMode2(true);
3888
+ }
2802
3889
  if (specifiers.length > 0) {
2803
3890
  const { add: add2 } = await Promise.resolve().then(() => (init_add(), add_exports));
2804
3891
  await add2(specifiers, {
2805
3892
  save: true,
2806
3893
  agent: options.agent,
2807
- yes: options.yes
3894
+ yes: options.yes,
3895
+ global: options.global
2808
3896
  });
2809
3897
  return;
2810
3898
  }
@@ -2845,14 +3933,14 @@ async function installFromLockfile(options) {
2845
3933
  `);
2846
3934
  configure2({ registryUrl, apiKey });
2847
3935
  for (const { fullName, versionRange } of missingDeps) {
2848
- const parsed = parseSkillSpecifier(fullName);
3936
+ const parsed = parseRegistrySpecifier2(fullName);
2849
3937
  if (!parsed) {
2850
3938
  console.error(`Error: Invalid dependency specifier: ${fullName}`);
2851
3939
  continue;
2852
3940
  }
2853
- const { username, name } = parsed;
3941
+ const { owner, name } = parsed;
2854
3942
  console.log(`Resolving ${fullName}@${versionRange}...`);
2855
- const versionsResponse = await listSkillVersions(username, name);
3943
+ const versionsResponse = await listSkillVersions(owner, name);
2856
3944
  if (versionsResponse.status !== 200) {
2857
3945
  const errorMessage = extractApiErrorMessage(
2858
3946
  versionsResponse,
@@ -2869,14 +3957,14 @@ async function installFromLockfile(options) {
2869
3957
  const versionStrings = versions.map(
2870
3958
  (v) => v.version
2871
3959
  );
2872
- const resolved = resolveVersion(versionRange || "*", versionStrings);
3960
+ const resolved = resolveVersion2(versionRange || "*", versionStrings);
2873
3961
  if (!resolved) {
2874
3962
  console.error(
2875
3963
  `Error: No version matching "${versionRange}" for ${fullName}`
2876
3964
  );
2877
3965
  continue;
2878
3966
  }
2879
- const versionResponse = await getSkillVersion(username, name, resolved);
3967
+ const versionResponse = await getSkillVersion(owner, name, resolved);
2880
3968
  if (versionResponse.status !== 200 || !versionResponse.data) {
2881
3969
  const errorMessage = extractApiErrorMessage(
2882
3970
  versionResponse,
@@ -2936,7 +4024,7 @@ Resolving ${missingGitHubDeps.length} GitHub dependency(ies)...
2936
4024
  `
2937
4025
  );
2938
4026
  for (const { specifier, ref } of missingGitHubDeps) {
2939
- const parsed = parseGitHubSpecifier(specifier);
4027
+ const parsed = parseGitHubSpecifier2(specifier);
2940
4028
  if (!parsed) {
2941
4029
  console.error(`Error: Invalid GitHub specifier: ${specifier}`);
2942
4030
  continue;
@@ -2996,12 +4084,12 @@ Installing ${packageCount} registry skill(s)...
2996
4084
  const installOrder = computeInstallOrder(packages);
2997
4085
  const entries = installOrder.filter((name) => packages[name]).map((name) => [name, packages[name]]);
2998
4086
  for (const [fullName, entry] of entries) {
2999
- const match = fullName.match(/^@user\/([^/]+)\/([^/]+)$/);
3000
- if (!match) {
4087
+ const parsedName = parseRegistrySpecifier2(fullName);
4088
+ if (!parsedName) {
3001
4089
  console.warn(`Warning: Invalid skill name in lockfile: ${fullName}`);
3002
4090
  continue;
3003
4091
  }
3004
- const [, username, name] = match;
4092
+ const { namespace: ns, owner: pkgOwner, name, subname } = parsedName;
3005
4093
  console.log(`Installing ${fullName}@${entry.version}...`);
3006
4094
  let tarballBuffer;
3007
4095
  let fromCache = false;
@@ -3050,7 +4138,21 @@ Installing ${packageCount} registry skill(s)...
3050
4138
  }
3051
4139
  await writeToCache(cacheDir, entry.integrity, tarballBuffer);
3052
4140
  }
3053
- const destDir = join(skillsDir, username, name);
4141
+ const effectiveSkillName = subname ?? name;
4142
+ let destDir;
4143
+ if (ns === "org") {
4144
+ destDir = join(skillsDir, "_org", pkgOwner, effectiveSkillName);
4145
+ } else if (ns === "github" && subname) {
4146
+ destDir = join(
4147
+ skillsDir,
4148
+ "_github-registry",
4149
+ pkgOwner,
4150
+ name,
4151
+ subname
4152
+ );
4153
+ } else {
4154
+ destDir = join(skillsDir, pkgOwner, effectiveSkillName);
4155
+ }
3054
4156
  await rm(destDir, { recursive: true, force: true });
3055
4157
  await mkdir(destDir, { recursive: true });
3056
4158
  const tempFile = join(destDir, ".temp.tgz");
@@ -3068,9 +4170,10 @@ Installing ${packageCount} registry skill(s)...
3068
4170
  console.log(
3069
4171
  ` Installed to ${destDir}${fromCache ? " (from cache)" : ""}`
3070
4172
  );
4173
+ const pathSkillName = ns === "github" && subname ? `${name}/${subname}` : name;
3071
4174
  installedSkills.push({
3072
- name,
3073
- sourcePath: getRegistrySkillPath(username, name)
4175
+ name: effectiveSkillName,
4176
+ sourcePath: getRegistrySkillPath(ns, pkgOwner, pathSkillName)
3074
4177
  });
3075
4178
  }
3076
4179
  }
@@ -3081,7 +4184,7 @@ Installing ${packageCount} registry skill(s)...
3081
4184
  Installing ${githubCount} GitHub skill(s)...
3082
4185
  `);
3083
4186
  for (const [specifier, entry] of Object.entries(githubPackages)) {
3084
- const parsed = parseGitHubSpecifier(specifier);
4187
+ const parsed = parseGitHubSpecifier2(specifier);
3085
4188
  if (!parsed) {
3086
4189
  console.warn(
3087
4190
  `Warning: Invalid GitHub specifier in lockfile: ${specifier}`
@@ -3136,7 +4239,7 @@ Installing ${githubCount} GitHub skill(s)...
3136
4239
  console.log(
3137
4240
  ` Installed to ${destPath}${fromCache ? " (from cache)" : ""}`
3138
4241
  );
3139
- const skillName = getGitHubSkillName(parsed);
4242
+ const skillName = getGitHubSkillName2(parsed);
3140
4243
  installedSkills.push({
3141
4244
  name: skillName,
3142
4245
  sourcePath: getGitHubSkillPath(
@@ -3152,12 +4255,16 @@ Installing ${githubCount} GitHub skill(s)...
3152
4255
  }
3153
4256
  }
3154
4257
  if (installedSkills.length > 0 && agents[0] !== "none") {
3155
- console.log(`
3156
- Creating symlinks for agent(s): ${agents.join(", ")}...`);
4258
+ const globalMode = isGlobalMode();
4259
+ console.log(
4260
+ `
4261
+ Creating symlinks for agent(s): ${agents.join(", ")}${globalMode ? " (global)" : ""}...`
4262
+ );
3157
4263
  await createAgentSymlinks(installedSkills, {
3158
4264
  agents,
3159
- projectRoot: process.cwd(),
3160
- agentConfigs
4265
+ projectRoot: globalMode ? homedir() : process.cwd(),
4266
+ agentConfigs,
4267
+ global: globalMode
3161
4268
  });
3162
4269
  console.log(" Symlinks created.");
3163
4270
  }
@@ -3178,11 +4285,15 @@ All ${totalCount} skill(s) installed.`);
3178
4285
  // src/commands/link.ts
3179
4286
  init_agents();
3180
4287
  init_lib();
3181
- init_lockfile2();
3182
- init_manifest2();
4288
+ init_lockfile3();
4289
+ init_manifest3();
3183
4290
  init_symlinks();
3184
4291
  async function link(options) {
3185
4292
  try {
4293
+ if (options.global) {
4294
+ const { setGlobalMode: setGlobalMode2 } = await Promise.resolve().then(() => (init_config(), config_exports));
4295
+ setGlobalMode2(true);
4296
+ }
3186
4297
  const manifest = await readManifest();
3187
4298
  const agentConfigs = manifest?.agents;
3188
4299
  let agents;
@@ -3203,26 +4314,32 @@ async function link(options) {
3203
4314
  const skills = [];
3204
4315
  const registrySkills = await listLockfileSkills();
3205
4316
  for (const { name } of registrySkills) {
3206
- const parsed = parseSkillSpecifier(name);
4317
+ const parsed = parseRegistrySpecifier2(name);
3207
4318
  if (!parsed) {
3208
4319
  console.warn(`Warning: Invalid skill name in lockfile: ${name}`);
3209
4320
  continue;
3210
4321
  }
4322
+ const effectiveName = parsed.subname ?? parsed.name;
4323
+ const pathName = parsed.namespace === "github" && parsed.subname ? `${parsed.name}/${parsed.subname}` : parsed.name;
3211
4324
  skills.push({
3212
- name: parsed.name,
3213
- sourcePath: getRegistrySkillPath(parsed.username, parsed.name)
4325
+ name: effectiveName,
4326
+ sourcePath: getRegistrySkillPath(
4327
+ parsed.namespace,
4328
+ parsed.owner,
4329
+ pathName
4330
+ )
3214
4331
  });
3215
4332
  }
3216
4333
  const githubSkills = await listLockfileGitHubPackages();
3217
4334
  for (const { specifier } of githubSkills) {
3218
- const parsed = parseGitHubSpecifier(specifier);
4335
+ const parsed = parseGitHubSpecifier2(specifier);
3219
4336
  if (!parsed) {
3220
4337
  console.warn(
3221
4338
  `Warning: Invalid GitHub specifier in lockfile: ${specifier}`
3222
4339
  );
3223
4340
  continue;
3224
4341
  }
3225
- const skillName = getGitHubSkillName(parsed);
4342
+ const skillName = getGitHubSkillName2(parsed);
3226
4343
  skills.push({
3227
4344
  name: skillName,
3228
4345
  sourcePath: getGitHubSkillPath(parsed.owner, parsed.repo, parsed.path)
@@ -3235,10 +4352,12 @@ async function link(options) {
3235
4352
  console.log(
3236
4353
  `Creating symlinks for ${skills.length} skill(s) to agent(s): ${agents.join(", ")}...`
3237
4354
  );
4355
+ const globalMode = options.global ?? false;
3238
4356
  await createAgentSymlinks(skills, {
3239
4357
  agents,
3240
- projectRoot: process.cwd(),
3241
- agentConfigs
4358
+ projectRoot: globalMode ? (await import('os')).homedir() : process.cwd(),
4359
+ agentConfigs,
4360
+ global: globalMode
3242
4361
  });
3243
4362
  console.log("Symlinks created successfully.");
3244
4363
  console.log("\nLinked skills:");
@@ -3255,23 +4374,33 @@ async function link(options) {
3255
4374
  // src/commands/list.ts
3256
4375
  init_agents();
3257
4376
  init_lib();
3258
- init_lockfile2();
3259
- init_manifest2();
4377
+ init_lockfile3();
4378
+ init_manifest3();
3260
4379
  init_symlinks();
3261
4380
  async function list(options) {
3262
4381
  try {
4382
+ if (options.global) {
4383
+ const { setGlobalMode: setGlobalMode2 } = await Promise.resolve().then(() => (init_config(), config_exports));
4384
+ setGlobalMode2(true);
4385
+ }
3263
4386
  const registrySkills = await listLockfileSkills();
3264
4387
  const githubSkills = await listLockfileGitHubPackages();
4388
+ const wellKnownSkills = await listLockfileWellKnownPackages();
3265
4389
  const manifest = await readManifest();
3266
4390
  const agentConfigs = manifest?.agents;
3267
4391
  const availableAgents = getAvailableAgents(agentConfigs);
3268
4392
  const projectRoot = process.cwd();
3269
4393
  const skills = [];
3270
4394
  for (const { name: fullName, entry } of registrySkills) {
3271
- const match = fullName.match(/^@user\/([^/]+)\/([^/]+)$/);
3272
- if (!match) continue;
3273
- const [, username, skillName] = match;
3274
- const sourcePath = getRegistrySkillPath(username, skillName);
4395
+ const parsed = parseRegistrySpecifier2(fullName);
4396
+ if (!parsed) continue;
4397
+ const skillName = parsed.subname ?? parsed.name;
4398
+ const pathName = parsed.namespace === "github" && parsed.subname ? `${parsed.name}/${parsed.subname}` : parsed.name;
4399
+ const sourcePath = getRegistrySkillPath(
4400
+ parsed.namespace,
4401
+ parsed.owner,
4402
+ pathName
4403
+ );
3275
4404
  const absolutePath = join(projectRoot, sourcePath);
3276
4405
  let status = "installed";
3277
4406
  try {
@@ -3296,10 +4425,10 @@ async function list(options) {
3296
4425
  });
3297
4426
  }
3298
4427
  for (const { specifier, entry } of githubSkills) {
3299
- const parsed = parseGitHubSpecifier(specifier);
4428
+ const parsed = parseGitHubSpecifier2(specifier);
3300
4429
  if (!parsed) continue;
3301
4430
  const ghEntry = entry;
3302
- const skillName = getGitHubSkillName(parsed);
4431
+ const skillName = getGitHubSkillName2(parsed);
3303
4432
  const sourcePath = getGitHubSkillPath(
3304
4433
  parsed.owner,
3305
4434
  parsed.repo,
@@ -3330,6 +4459,34 @@ async function list(options) {
3330
4459
  gitCommit: ghEntry.gitCommit
3331
4460
  });
3332
4461
  }
4462
+ for (const { specifier, entry } of wellKnownSkills) {
4463
+ const wkEntry = entry;
4464
+ const skillName = wkEntry.name;
4465
+ const sourcePath = getWellKnownSkillPath(wkEntry.hostname, skillName);
4466
+ const absolutePath = join(projectRoot, sourcePath);
4467
+ let status = "installed";
4468
+ try {
4469
+ await access$1(absolutePath);
4470
+ } catch {
4471
+ status = "missing";
4472
+ }
4473
+ const linkedAgents = await getLinkedAgents(
4474
+ skillName,
4475
+ availableAgents,
4476
+ projectRoot,
4477
+ agentConfigs
4478
+ );
4479
+ skills.push({
4480
+ name: skillName,
4481
+ fullName: specifier,
4482
+ version: "well-known",
4483
+ source: "well-known",
4484
+ sourcePath,
4485
+ status,
4486
+ linkedAgents,
4487
+ hostname: wkEntry.hostname
4488
+ });
4489
+ }
3333
4490
  if (skills.length === 0) {
3334
4491
  console.log("No skills installed.");
3335
4492
  return;
@@ -3342,6 +4499,8 @@ async function list(options) {
3342
4499
  for (const skill of skills) {
3343
4500
  if (skill.source === "registry") {
3344
4501
  console.log(` ${skill.fullName}@${skill.version} (registry)`);
4502
+ } else if (skill.source === "well-known") {
4503
+ console.log(` ${skill.name} (well-known: ${skill.hostname})`);
3345
4504
  } else {
3346
4505
  const refInfo = skill.gitRef ? `${skill.gitRef}@${skill.gitCommit?.slice(0, 7)}` : skill.version;
3347
4506
  console.log(` ${skill.fullName} (${refInfo})`);
@@ -3360,9 +4519,13 @@ async function list(options) {
3360
4519
  }
3361
4520
  const registryCount = skills.filter((s) => s.source === "registry").length;
3362
4521
  const githubCount = skills.filter((s) => s.source === "github").length;
4522
+ const wellKnownCount = skills.filter(
4523
+ (s) => s.source === "well-known"
4524
+ ).length;
3363
4525
  const parts = [];
3364
4526
  if (registryCount > 0) parts.push(`${registryCount} registry`);
3365
4527
  if (githubCount > 0) parts.push(`${githubCount} github`);
4528
+ if (wellKnownCount > 0) parts.push(`${wellKnownCount} well-known`);
3366
4529
  console.log(`
3367
4530
  Total: ${skills.length} skill(s) (${parts.join(", ")})`);
3368
4531
  } catch (error) {
@@ -3579,7 +4742,7 @@ async function logout() {
3579
4742
 
3580
4743
  // src/commands/migrate.ts
3581
4744
  init_config();
3582
- init_lockfile2();
4745
+ init_lockfile3();
3583
4746
  async function migrate(options) {
3584
4747
  try {
3585
4748
  const legacySkillsDir = getLegacySkillsDir();
@@ -3679,20 +4842,20 @@ async function migrate(options) {
3679
4842
  process.exit(1);
3680
4843
  }
3681
4844
  }
3682
- function resolveVersion2(range, availableVersions) {
3683
- const sorted = availableVersions.filter((v) => semver.valid(v)).sort((a, b) => semver.rcompare(a, b));
4845
+ function resolveVersion3(range, availableVersions) {
4846
+ const sorted = availableVersions.filter((v) => semver2.valid(v)).sort((a, b) => semver2.rcompare(a, b));
3684
4847
  if (range === "latest") {
3685
4848
  return sorted[0] ?? null;
3686
4849
  }
3687
- return semver.maxSatisfying(sorted, range);
4850
+ return semver2.maxSatisfying(sorted, range);
3688
4851
  }
3689
- function compareVersions2(a, b) {
3690
- return semver.compare(a, b);
4852
+ function compareVersions3(a, b) {
4853
+ return semver2.compare(a, b);
3691
4854
  }
3692
- function getLatestVersion2(versions) {
3693
- const valid3 = versions.filter((v) => semver.valid(v));
3694
- if (valid3.length === 0) return null;
3695
- return valid3.sort((a, b) => semver.rcompare(a, b))[0];
4855
+ function getLatestVersion3(versions) {
4856
+ const valid5 = versions.filter((v) => semver2.valid(v));
4857
+ if (valid5.length === 0) return null;
4858
+ return valid5.sort((a, b) => semver2.rcompare(a, b))[0];
3696
4859
  }
3697
4860
 
3698
4861
  // ../../packages/server/skill-registry/src/client/outdated.ts
@@ -3725,14 +4888,14 @@ function createOutdatedChecker(config2) {
3725
4888
  const versions = await fetchRegistryVersions(username, name);
3726
4889
  const versionStrings = versions.map((v) => v.version);
3727
4890
  const range = versionRange || "*";
3728
- const wanted = resolveVersion2(range, versionStrings);
3729
- const latest = getLatestVersion2(versionStrings);
4891
+ const wanted = resolveVersion3(range, versionStrings);
4892
+ const latest = getLatestVersion3(versionStrings);
3730
4893
  const currentVersionInfo = versions.find(
3731
4894
  (v) => v.version === entry.version
3732
4895
  );
3733
4896
  const deprecated = currentVersionInfo?.deprecationMessage ?? void 0;
3734
- const isOutdated = wanted !== null && compareVersions2(entry.version, wanted) < 0 || latest !== null && compareVersions2(entry.version, latest) < 0;
3735
- const wantedBehindLatest = wanted !== null && latest !== null && compareVersions2(wanted, latest) < 0;
4897
+ const isOutdated = wanted !== null && compareVersions3(entry.version, wanted) < 0 || latest !== null && compareVersions3(entry.version, latest) < 0;
4898
+ const wantedBehindLatest = wanted !== null && latest !== null && compareVersions3(wanted, latest) < 0;
3736
4899
  return {
3737
4900
  name: specifier,
3738
4901
  current: entry.version,
@@ -3865,8 +5028,8 @@ async function checkOutdated(config2, options) {
3865
5028
 
3866
5029
  // src/commands/outdated.ts
3867
5030
  init_config();
3868
- init_lockfile2();
3869
- init_manifest2();
5031
+ init_lockfile3();
5032
+ init_manifest3();
3870
5033
  async function outdated(packages, options) {
3871
5034
  try {
3872
5035
  const lockfile = await readLockfile();
@@ -4074,8 +5237,8 @@ async function publishCommand(options) {
4074
5237
  dependencies: manifest.dependencies
4075
5238
  };
4076
5239
  if (options.bump) {
4077
- const semver4 = await import('semver');
4078
- const newVersion = semver4.default.inc(packageJson2.version, options.bump);
5240
+ const semver6 = await import('semver');
5241
+ const newVersion = semver6.default.inc(packageJson2.version, options.bump);
4079
5242
  if (!newVersion) {
4080
5243
  console.error(
4081
5244
  `Error: Failed to bump version from ${packageJson2.version}`
@@ -4204,7 +5367,7 @@ async function publishCommand(options) {
4204
5367
  const visibility = result.skill.visibility;
4205
5368
  const visibilityIcon = visibility === "public" ? "\u{1F310}" : "\u{1F512}";
4206
5369
  console.log(
4207
- `+ @user/${result.skill.username}/${result.skill.name}@${result.version.version}`
5370
+ `+ @${result.skill.namespace ?? "user"}/${result.skill.username}/${result.skill.name}@${result.version.version}`
4208
5371
  );
4209
5372
  console.log(`Checksum: ${result.version.checksum}`);
4210
5373
  console.log(`Visibility: ${visibilityIcon} ${visibility}`);
@@ -4231,17 +5394,17 @@ async function publishCommand(options) {
4231
5394
  init_agents();
4232
5395
  init_config();
4233
5396
  init_lib();
4234
- init_lockfile2();
4235
- init_manifest2();
5397
+ init_lockfile3();
5398
+ init_manifest3();
4236
5399
  init_symlinks();
4237
5400
  async function remove(nameOrSpecifier) {
4238
5401
  try {
4239
5402
  const manifest = await readManifest();
4240
5403
  const agentConfigs = manifest?.agents;
4241
5404
  const agents = getAvailableAgents(agentConfigs);
4242
- if (isGitHubSpecifier(nameOrSpecifier)) {
5405
+ if (isGitHubSpecifier2(nameOrSpecifier)) {
4243
5406
  await removeGitHub(nameOrSpecifier, agents, agentConfigs);
4244
- } else if (nameOrSpecifier.startsWith("@user/")) {
5407
+ } else if (isRegistrySpecifier2(nameOrSpecifier)) {
4245
5408
  await removeRegistry(nameOrSpecifier, agents, agentConfigs);
4246
5409
  } else {
4247
5410
  await removeByShortName(nameOrSpecifier, agents, agentConfigs);
@@ -4253,14 +5416,13 @@ async function remove(nameOrSpecifier) {
4253
5416
  }
4254
5417
  }
4255
5418
  async function removeRegistry(specifier, agents, agentConfigs) {
4256
- const match = specifier.match(/^@user\/([^/]+)\/([^@/]+)/);
4257
- if (!match) {
5419
+ const parsed = parseRegistrySpecifier2(specifier);
5420
+ if (!parsed) {
4258
5421
  console.error(`Error: Invalid skill specifier: ${specifier}`);
4259
5422
  process.exit(1);
4260
5423
  }
4261
- const fullName = `@user/${match[1]}/${match[2]}`;
4262
- const username = match[1];
4263
- const name = match[2];
5424
+ const { namespace, owner, name } = parsed;
5425
+ const fullName = `@${namespace}/${owner}/${name}`;
4264
5426
  console.log(`Removing ${fullName}...`);
4265
5427
  const removedFromLockfile = await removeFromLockfile(fullName);
4266
5428
  const removedFromManifest = await removeDependency(fullName);
@@ -4274,7 +5436,7 @@ async function removeRegistry(specifier, agents, agentConfigs) {
4274
5436
  agentConfigs
4275
5437
  });
4276
5438
  const skillsDir = getSkillsDir();
4277
- const destDir = join(skillsDir, username, name);
5439
+ const destDir = namespace === "org" ? join(skillsDir, "_org", owner, name) : join(skillsDir, owner, name);
4278
5440
  try {
4279
5441
  await rm(destDir, { recursive: true, force: true });
4280
5442
  } catch {
@@ -4282,7 +5444,7 @@ async function removeRegistry(specifier, agents, agentConfigs) {
4282
5444
  console.log(`Removed ${fullName}`);
4283
5445
  }
4284
5446
  async function removeGitHub(specifier, agents, agentConfigs) {
4285
- const parsed = parseGitHubSpecifier(specifier);
5447
+ const parsed = parseGitHubSpecifier2(specifier);
4286
5448
  if (!parsed) {
4287
5449
  console.error(`Error: Invalid GitHub specifier: ${specifier}`);
4288
5450
  process.exit(1);
@@ -4295,7 +5457,7 @@ async function removeGitHub(specifier, agents, agentConfigs) {
4295
5457
  console.error(`Error: ${lockfileKey} not found in lockfile or pspm.json`);
4296
5458
  process.exit(1);
4297
5459
  }
4298
- const skillName = getGitHubSkillName(parsed);
5460
+ const skillName = getGitHubSkillName2(parsed);
4299
5461
  await removeAgentSymlinks(skillName, {
4300
5462
  agents,
4301
5463
  projectRoot: process.cwd(),
@@ -4313,8 +5475,8 @@ async function removeGitHub(specifier, agents, agentConfigs) {
4313
5475
  async function removeByShortName(shortName, agents, agentConfigs) {
4314
5476
  const registrySkills = await listLockfileSkills();
4315
5477
  const foundRegistry = registrySkills.find((s) => {
4316
- const match = s.name.match(/^@user\/([^/]+)\/([^/]+)$/);
4317
- return match && match[2] === shortName;
5478
+ const parsed = parseRegistrySpecifier2(s.name);
5479
+ return parsed && parsed.name === shortName;
4318
5480
  });
4319
5481
  if (foundRegistry) {
4320
5482
  await removeRegistry(foundRegistry.name, agents, agentConfigs);
@@ -4322,9 +5484,9 @@ async function removeByShortName(shortName, agents, agentConfigs) {
4322
5484
  }
4323
5485
  const githubSkills = await listLockfileGitHubPackages();
4324
5486
  const foundGitHub = githubSkills.find((s) => {
4325
- const parsed = parseGitHubSpecifier(s.specifier);
5487
+ const parsed = parseGitHubSpecifier2(s.specifier);
4326
5488
  if (!parsed) return false;
4327
- return getGitHubSkillName(parsed) === shortName;
5489
+ return getGitHubSkillName2(parsed) === shortName;
4328
5490
  });
4329
5491
  if (foundGitHub) {
4330
5492
  await removeGitHub(foundGitHub.specifier, agents, agentConfigs);
@@ -4334,6 +5496,88 @@ async function removeByShortName(shortName, agents, agentConfigs) {
4334
5496
  process.exit(1);
4335
5497
  }
4336
5498
 
5499
+ // src/commands/search.ts
5500
+ init_api_client();
5501
+ init_config();
5502
+ init_generated();
5503
+ async function search(query, options) {
5504
+ try {
5505
+ const config2 = await resolveConfig();
5506
+ const apiKey = getTokenForRegistry(config2, config2.registryUrl);
5507
+ configure2({ registryUrl: config2.registryUrl, apiKey });
5508
+ const limit = options.limit ?? 20;
5509
+ const sort = options.sort ?? "downloads";
5510
+ if (!options.json) {
5511
+ if (query) {
5512
+ console.log(`Searching for "${query}"...
5513
+ `);
5514
+ } else {
5515
+ console.log("Browsing skills...\n");
5516
+ }
5517
+ }
5518
+ const response = await explorePublicSkills({
5519
+ search: query,
5520
+ sort,
5521
+ limit,
5522
+ page: 1
5523
+ });
5524
+ if (response.status !== 200) {
5525
+ console.error("Error: Failed to search skills");
5526
+ process.exit(1);
5527
+ }
5528
+ const { skills, total } = response.data;
5529
+ if (skills.length === 0) {
5530
+ if (query) {
5531
+ console.log(`No skills found matching "${query}".`);
5532
+ } else {
5533
+ console.log("No skills published yet.");
5534
+ }
5535
+ return;
5536
+ }
5537
+ if (options.json) {
5538
+ console.log(JSON.stringify(skills, null, 2));
5539
+ return;
5540
+ }
5541
+ for (const skill of skills) {
5542
+ const name = `@${skill.namespace ?? "user"}/${skill.username}/${skill.name}`;
5543
+ const desc = skill.description ? ` - ${skill.description.slice(0, 80)}${skill.description.length > 80 ? "..." : ""}` : "";
5544
+ const downloads = skill.totalDownloads > 0 ? ` (${formatDownloads(skill.totalDownloads)} downloads)` : "";
5545
+ console.log(` ${name}${downloads}`);
5546
+ if (desc) {
5547
+ console.log(` ${desc.trim()}`);
5548
+ }
5549
+ }
5550
+ const showing = Math.min(skills.length, limit);
5551
+ if (total > showing) {
5552
+ console.log(`
5553
+ Showing ${showing} of ${total} results.`);
5554
+ } else {
5555
+ console.log(`
5556
+ ${total} skill(s) found.`);
5557
+ }
5558
+ if (skills.length > 0) {
5559
+ const first = skills[0];
5560
+ console.log(
5561
+ `
5562
+ Install with: pspm add @${first.namespace ?? "user"}/${first.username}/${first.name}`
5563
+ );
5564
+ }
5565
+ } catch (error) {
5566
+ const message = error instanceof Error ? error.message : "Unknown error";
5567
+ console.error(`Error: ${message}`);
5568
+ process.exit(1);
5569
+ }
5570
+ }
5571
+ function formatDownloads(count) {
5572
+ if (count >= 1e6) {
5573
+ return `${(count / 1e6).toFixed(1)}M`;
5574
+ }
5575
+ if (count >= 1e3) {
5576
+ return `${(count / 1e3).toFixed(1)}k`;
5577
+ }
5578
+ return String(count);
5579
+ }
5580
+
4337
5581
  // src/commands/unpublish.ts
4338
5582
  init_api_client();
4339
5583
  init_config();
@@ -4343,14 +5587,19 @@ async function unpublish(specifier, options) {
4343
5587
  try {
4344
5588
  const apiKey = await requireApiKey();
4345
5589
  const registryUrl = await getRegistryUrl();
4346
- const parsed = parseSkillSpecifier(specifier);
5590
+ const parsed = parseRegistrySpecifier2(specifier);
4347
5591
  if (!parsed) {
4348
5592
  console.error(
4349
- `Error: Invalid skill specifier "${specifier}". Use format: @user/{username}/{name}[@{version}]`
5593
+ `Error: Invalid skill specifier "${specifier}". Use format: @user/{username}/{name}[@{version}] or @org/{orgname}/{name}[@{version}]`
4350
5594
  );
4351
5595
  process.exit(1);
4352
5596
  }
4353
- const { username, name, versionRange } = parsed;
5597
+ const { owner, name, versionRange } = parsed;
5598
+ const fullName = generateRegistryIdentifier2({
5599
+ namespace: parsed.namespace,
5600
+ owner,
5601
+ name
5602
+ });
4354
5603
  configure2({ registryUrl, apiKey });
4355
5604
  if (versionRange) {
4356
5605
  console.log(`Unpublishing ${specifier}...`);
@@ -4360,7 +5609,7 @@ async function unpublish(specifier, options) {
4360
5609
  );
4361
5610
  process.exit(1);
4362
5611
  }
4363
- const response = await deleteSkillVersion(username, name, versionRange);
5612
+ const response = await deleteSkillVersion(owner, name, versionRange);
4364
5613
  if (response.status !== 200) {
4365
5614
  const errorMessage = extractApiErrorMessage(
4366
5615
  response,
@@ -4369,16 +5618,16 @@ async function unpublish(specifier, options) {
4369
5618
  console.error(`Error: ${errorMessage}`);
4370
5619
  process.exit(1);
4371
5620
  }
4372
- console.log(`Unpublished @user/${username}/${name}@${versionRange}`);
5621
+ console.log(`Unpublished ${fullName}@${versionRange}`);
4373
5622
  } else {
4374
- console.log(`Unpublishing all versions of @user/${username}/${name}...`);
5623
+ console.log(`Unpublishing all versions of ${fullName}...`);
4375
5624
  if (!options.force) {
4376
5625
  console.error(
4377
5626
  "Warning: This will delete ALL versions. Use --force to confirm."
4378
5627
  );
4379
5628
  process.exit(1);
4380
5629
  }
4381
- const response = await deleteSkill(username, name);
5630
+ const response = await deleteSkill(owner, name);
4382
5631
  if (response.status !== 200) {
4383
5632
  const errorMessage = extractApiErrorMessage(
4384
5633
  response,
@@ -4387,7 +5636,7 @@ async function unpublish(specifier, options) {
4387
5636
  console.error(`Error: ${errorMessage}`);
4388
5637
  process.exit(1);
4389
5638
  }
4390
- console.log(`Unpublished @user/${username}/${name} (all versions)`);
5639
+ console.log(`Unpublished ${fullName} (all versions)`);
4391
5640
  }
4392
5641
  } catch (error) {
4393
5642
  const message = error instanceof Error ? error.message : "Unknown error";
@@ -4401,7 +5650,7 @@ init_api_client();
4401
5650
  init_config();
4402
5651
  init_errors();
4403
5652
  init_lib();
4404
- init_lockfile2();
5653
+ init_lockfile3();
4405
5654
  init_add();
4406
5655
  async function update(options) {
4407
5656
  try {
@@ -4417,11 +5666,13 @@ async function update(options) {
4417
5666
  const updates = [];
4418
5667
  console.log("Checking for updates...\n");
4419
5668
  for (const { name, entry } of skills) {
4420
- const match = name.match(/^@user\/([^/]+)\/([^/]+)$/);
4421
- if (!match) continue;
4422
- const [, username, skillName] = match;
5669
+ const parsed = parseRegistrySpecifier2(name);
5670
+ if (!parsed) continue;
4423
5671
  try {
4424
- const versionsResponse = await listSkillVersions(username, skillName);
5672
+ const versionsResponse = await listSkillVersions(
5673
+ parsed.owner,
5674
+ parsed.name
5675
+ );
4425
5676
  if (versionsResponse.status !== 200) {
4426
5677
  const errorMessage = extractApiErrorMessage(
4427
5678
  versionsResponse,
@@ -4435,7 +5686,7 @@ async function update(options) {
4435
5686
  const versionStrings = versions.map(
4436
5687
  (v) => v.version
4437
5688
  );
4438
- const latest = resolveVersion("*", versionStrings);
5689
+ const latest = resolveVersion2("*", versionStrings);
4439
5690
  if (latest && latest !== entry.version) {
4440
5691
  updates.push({
4441
5692
  name,
@@ -4460,11 +5711,10 @@ async function update(options) {
4460
5711
  return;
4461
5712
  }
4462
5713
  console.log("\nUpdating...\n");
4463
- for (const { name, latest } of updates) {
4464
- const match = name.match(/^@user\/([^/]+)\/([^/]+)$/);
4465
- if (!match) continue;
4466
- const [, username, skillName] = match;
4467
- const specifier = `@user/${username}/${skillName}@${latest}`;
5714
+ for (const { name: pkgName, latest } of updates) {
5715
+ const parsed = parseRegistrySpecifier2(pkgName);
5716
+ if (!parsed) continue;
5717
+ const specifier = `${pkgName}@${latest}`;
4468
5718
  await add([specifier], {});
4469
5719
  }
4470
5720
  console.log("\nAll skills updated.");
@@ -4479,12 +5729,12 @@ async function upgrade() {
4479
5729
  try {
4480
5730
  const currentVersion = getCurrentVersion();
4481
5731
  console.log("Checking for updates...\n");
4482
- const latestVersion = getLatestVersion3(packageName);
5732
+ const latestVersion = getLatestVersion4(packageName);
4483
5733
  if (!latestVersion) {
4484
5734
  console.error("Error: Could not fetch latest version from registry.");
4485
5735
  process.exit(1);
4486
5736
  }
4487
- if (currentVersion === latestVersion) {
5737
+ if (semver2.valid(currentVersion) && semver2.valid(latestVersion) && !semver2.gt(latestVersion, currentVersion)) {
4488
5738
  console.log(`Already on the latest version: ${currentVersion}`);
4489
5739
  return;
4490
5740
  }
@@ -4517,7 +5767,7 @@ function getCurrentVersion() {
4517
5767
  return "unknown";
4518
5768
  }
4519
5769
  }
4520
- function getLatestVersion3(packageName) {
5770
+ function getLatestVersion4(packageName) {
4521
5771
  try {
4522
5772
  const output = execSync(`npm view ${packageName} version`, {
4523
5773
  encoding: "utf-8",
@@ -4569,7 +5819,7 @@ function getInstallCommand(pm, packageName, version3) {
4569
5819
  }
4570
5820
 
4571
5821
  // src/commands/version.ts
4572
- init_manifest2();
5822
+ init_manifest3();
4573
5823
  async function version(bump, options = {}) {
4574
5824
  try {
4575
5825
  const manifest = await readManifest();
@@ -4585,7 +5835,7 @@ async function version(bump, options = {}) {
4585
5835
  );
4586
5836
  process.exit(1);
4587
5837
  }
4588
- if (!semver__default.valid(manifest.version)) {
5838
+ if (!semver2__default.valid(manifest.version)) {
4589
5839
  console.error(
4590
5840
  `Error: Current version "${manifest.version}" is not valid semver.`
4591
5841
  );
@@ -4594,7 +5844,7 @@ async function version(bump, options = {}) {
4594
5844
  );
4595
5845
  process.exit(1);
4596
5846
  }
4597
- const newVersion = semver__default.inc(manifest.version, bump);
5847
+ const newVersion = semver2__default.inc(manifest.version, bump);
4598
5848
  if (!newVersion) {
4599
5849
  console.error(`Error: Failed to bump version from ${manifest.version}`);
4600
5850
  process.exit(1);
@@ -4640,6 +5890,9 @@ async function whoami() {
4640
5890
  process.exit(1);
4641
5891
  }
4642
5892
  }
5893
+
5894
+ // src/update-notifier.ts
5895
+ init_version2();
4643
5896
  var PACKAGE_NAME = "@anytio/pspm";
4644
5897
  var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
4645
5898
  var CACHE_DIR = join(homedir(), ".pspm");
@@ -4648,7 +5901,7 @@ async function checkForUpdates(currentVersion) {
4648
5901
  try {
4649
5902
  const cache = await readCache();
4650
5903
  if (cache && Date.now() - cache.lastCheck < CHECK_INTERVAL_MS) {
4651
- if (cache.latestVersion !== currentVersion) {
5904
+ if (isNewerVersion2(cache.latestVersion, currentVersion)) {
4652
5905
  printUpdateWarning(currentVersion, cache.latestVersion);
4653
5906
  }
4654
5907
  return;
@@ -4683,7 +5936,7 @@ function fetchAndCache(currentVersion) {
4683
5936
  };
4684
5937
  writeCache(cache).catch(() => {
4685
5938
  });
4686
- if (latestVersion !== currentVersion) {
5939
+ if (isNewerVersion2(latestVersion, currentVersion)) {
4687
5940
  printUpdateWarning(currentVersion, latestVersion);
4688
5941
  }
4689
5942
  } catch {
@@ -4705,7 +5958,7 @@ var packageJson = JSON.parse(
4705
5958
  );
4706
5959
  var version2 = packageJson.version;
4707
5960
  var program = new Command();
4708
- program.name("pspm").description("Prompt Skill Package Manager for AI coding agents").version(version2);
5961
+ program.name("pspm").description("Package manager for AI agent skills").version(version2);
4709
5962
  var configCmd = program.command("config").description("Manage PSPM configuration");
4710
5963
  configCmd.command("show").description("Show resolved configuration").action(async () => {
4711
5964
  await configShow();
@@ -4745,45 +5998,64 @@ program.command("migrate").description(
4745
5998
  await migrate({ dryRun: options.dryRun });
4746
5999
  });
4747
6000
  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)"
6001
+ "Add skills from registry, GitHub, local paths, or well-known URLs"
4749
6002
  ).option("--save", "Save to lockfile (default)").option(
4750
6003
  "--agent <agents>",
4751
6004
  '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) => {
6005
+ ).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
6006
  await add(specifiers, {
4754
6007
  save: options.save ?? true,
4755
6008
  agent: options.agent,
4756
- yes: options.yes
6009
+ yes: options.yes,
6010
+ global: options.global
4757
6011
  });
4758
6012
  });
4759
6013
  program.command("remove <name>").alias("rm").description("Remove an installed skill").action(async (name) => {
4760
6014
  await remove(name);
4761
6015
  });
4762
- program.command("list").alias("ls").description("List installed skills").option("--json", "Output as JSON").action(async (options) => {
4763
- await list({ json: options.json });
6016
+ program.command("list").alias("ls").description("List installed skills").option("--json", "Output as JSON").option("-g, --global", "List globally installed skills").action(async (options) => {
6017
+ await list({ json: options.json, global: options.global });
4764
6018
  });
4765
6019
  program.command("install [specifiers...]").alias("i").description(
4766
6020
  "Install skills from lockfile, or add and install specific packages"
4767
6021
  ).option("--frozen-lockfile", "Fail if lockfile is missing or outdated").option("--dir <path>", "Install skills to a specific directory").option(
4768
6022
  "--agent <agents>",
4769
6023
  '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) => {
6024
+ ).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
6025
  await install(specifiers, {
4772
6026
  frozenLockfile: options.frozenLockfile,
4773
6027
  dir: options.dir,
4774
6028
  agent: options.agent,
4775
- yes: options.yes
6029
+ yes: options.yes,
6030
+ global: options.global
4776
6031
  });
4777
6032
  });
4778
6033
  program.command("link").description("Recreate agent symlinks without reinstalling").option(
4779
6034
  "--agent <agents>",
4780
6035
  '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 });
6036
+ ).option("-g, --global", "Recreate global agent symlinks").option("-y, --yes", "Skip agent selection prompt and use defaults").action(async (options) => {
6037
+ await link({
6038
+ agent: options.agent,
6039
+ yes: options.yes,
6040
+ global: options.global
6041
+ });
4783
6042
  });
4784
6043
  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
6044
  await update({ dryRun: options.dryRun });
4786
6045
  });
6046
+ program.command("search [query]").alias("find").description("Search and discover skills from the registry").option(
6047
+ "-s, --sort <sort>",
6048
+ "Sort by: downloads, recent, name (default: downloads)"
6049
+ ).option("-l, --limit <n>", "Maximum results (default: 20)", Number.parseInt).option("--json", "Output as JSON").action(async (query, options) => {
6050
+ await search(query, {
6051
+ sort: options.sort,
6052
+ limit: options.limit,
6053
+ json: options.json
6054
+ });
6055
+ });
6056
+ program.command("audit").description("Verify integrity of installed skills and check for issues").option("--json", "Output as JSON").action(async (options) => {
6057
+ await audit({ json: options.json });
6058
+ });
4787
6059
  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
6060
  await outdated(packages, { json: options.json, all: options.all });
4789
6061
  });
@@ -4830,6 +6102,9 @@ program.command("deprecate <specifier> [message]").description(
4830
6102
  await deprecate(specifier, message, { undo: options.undo });
4831
6103
  });
4832
6104
  await program.parseAsync();
4833
- await checkForUpdates(version2);
6105
+ var executedCommand = program.args[0];
6106
+ if (executedCommand !== "upgrade") {
6107
+ await checkForUpdates(version2);
6108
+ }
4834
6109
  //# sourceMappingURL=index.js.map
4835
6110
  //# sourceMappingURL=index.js.map