@anytio/pspm 0.9.2 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,32 @@ All notable changes to the PSPM CLI will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.11.0] - 2026-03-17
9
+
10
+ ### Added
11
+
12
+ - **Skill list install**: Install all skills from a curated skill list with `pspm install --list @user/username/list-name`
13
+ - Supports both user and org lists: `@user/{username}/{list-name}` or `@org/{orgname}/{list-name}`
14
+ - Fetches list from the registry API and resolves items to registry specifiers
15
+ - Respects pinned versions when specified in the list
16
+ - Can be combined with explicit specifiers for additional packages
17
+
18
+ ### Changed
19
+
20
+ - Updated all dependencies to latest versions
21
+
22
+ ## [0.10.0] - 2026-03-14
23
+
24
+ ### Added
25
+
26
+ - **Organization publishing**: Publish skills under an org namespace with `pspm publish --org <orgname>`
27
+ - `pspm publish --access team --org myorg` — publish as team-visible under `@org/myorg/skill-name`
28
+ - `pspm publish --access public --org myorg` — publish as public under org namespace
29
+ - **Team visibility**: New `--access team` option restricts package access to org members only
30
+ - **Org namespace resolution**: `@org/` namespace fully supported in dependency resolution
31
+ - Install org-scoped packages: `pspm add @org/myorg/skill-name`
32
+ - Recursive dependency resolution for org packages
33
+
8
34
  ## [0.9.2] - 2026-03-10
9
35
 
10
36
  ### Changed
package/README.md CHANGED
@@ -9,7 +9,7 @@ Supports **Claude Code**, **Cursor**, **Codex**, **Gemini CLI**, **Windsurf**, a
9
9
  ## Install a Skill
10
10
 
11
11
  ```bash
12
- npx @anytio/pspm add vercel-labs/agent-skills
12
+ npx @anytio/pspm add @user/anyt/youtube-downloader
13
13
  ```
14
14
 
15
15
  ### Source Formats
@@ -146,6 +146,10 @@ pspm install --dir ./custom-path
146
146
 
147
147
  # Install specific packages
148
148
  pspm install @user/alice/skill1 github:org/repo
149
+
150
+ # Install all skills from a skill list
151
+ pspm install --list @user/alice/my-favorites
152
+ pspm install --list @org/myorg/team-skills
149
153
  ```
150
154
 
151
155
  ### `pspm search`
@@ -351,10 +355,11 @@ pspm version patch --dry-run # Preview without writing
351
355
  ```bash
352
356
  pspm publish --access public # Publish as public (irreversible)
353
357
  pspm publish --access private # Publish as private (requires Pro)
358
+ pspm publish --access team --org myorg # Publish under org (team-only)
354
359
  pspm publish --access private --bump patch # Bump and publish
355
360
  ```
356
361
 
357
- `--access` is required. Before uploading, `pspm publish` shows a preview of included files and package size. Max package size is **10MB**.
362
+ `--access` is required (`public`, `private`, or `team`). Use `--org <orgname>` to publish under an organization namespace. `--access team` requires `--org`. Before uploading, `pspm publish` shows a preview of included files and package size. Max package size is **10MB**.
358
363
 
359
364
  ### Managing Published Skills
360
365
 
package/dist/index.js CHANGED
@@ -37,6 +37,9 @@ function getConfig() {
37
37
  }
38
38
  return config;
39
39
  }
40
+ function isConfigured() {
41
+ return config !== null;
42
+ }
40
43
  async function customFetch(url, options) {
41
44
  const { baseUrl, apiKey } = getConfig();
42
45
  const fullUrl = `${baseUrl}${url}`;
@@ -66,18 +69,42 @@ async function customFetch(url, options) {
66
69
  headers: response.headers
67
70
  };
68
71
  }
69
- var config;
72
+ var config, SDKError;
70
73
  var init_fetcher = __esm({
71
74
  "src/sdk/fetcher.ts"() {
72
75
  config = null;
76
+ SDKError = class extends Error {
77
+ constructor(message, status, body) {
78
+ super(message);
79
+ this.status = status;
80
+ this.body = body;
81
+ this.name = "SDKError";
82
+ }
83
+ };
73
84
  }
74
85
  });
75
86
 
76
87
  // src/sdk/generated/index.ts
77
- var getMeUrl, me, getExplorePublicSkillsUrl, explorePublicSkills, getDeleteSkillUrl, deleteSkill, getListSkillVersionsUrl, listSkillVersions, getGetSkillVersionUrl, getSkillVersion, getDeleteSkillVersionUrl, deleteSkillVersion, getPublishSkillUrl, publishSkill;
88
+ var getExchangeCliTokenUrl, exchangeCliToken, getMeUrl, me, getExplorePublicSkillsUrl, explorePublicSkills, getListMySkillsUrl, listMySkills, getListUserSkillsUrl, listUserSkills, getGetSkillUrl, getSkill, getDeleteSkillUrl, deleteSkill, getListSkillVersionsUrl, listSkillVersions, getGetSkillVersionUrl, getSkillVersion, getDeleteSkillVersionUrl, deleteSkillVersion, getPublishSkillUrl, publishSkill, getListOrgSkillVersionsUrl, listOrgSkillVersions, getGetOrgSkillVersionUrl, getOrgSkillVersion, getPublishOrgSkillUrl, publishOrgSkill;
78
89
  var init_generated = __esm({
79
90
  "src/sdk/generated/index.ts"() {
80
91
  init_fetcher();
92
+ getExchangeCliTokenUrl = () => {
93
+ return `/api/api-keys/cli-token-exchange`;
94
+ };
95
+ exchangeCliToken = async (exchangeCliTokenInput, options) => {
96
+ return customFetch(
97
+ getExchangeCliTokenUrl(),
98
+ {
99
+ ...options,
100
+ method: "POST",
101
+ headers: { "Content-Type": "application/json", ...options?.headers },
102
+ body: JSON.stringify(
103
+ exchangeCliTokenInput
104
+ )
105
+ }
106
+ );
107
+ };
81
108
  getMeUrl = () => {
82
109
  return `/api/skills/-/me`;
83
110
  };
@@ -109,6 +136,42 @@ var init_generated = __esm({
109
136
  }
110
137
  );
111
138
  };
139
+ getListMySkillsUrl = () => {
140
+ return `/api/skills/-/mine`;
141
+ };
142
+ listMySkills = async (options) => {
143
+ return customFetch(
144
+ getListMySkillsUrl(),
145
+ {
146
+ ...options,
147
+ method: "GET"
148
+ }
149
+ );
150
+ };
151
+ getListUserSkillsUrl = (username) => {
152
+ return `/api/skills/@user/${username}`;
153
+ };
154
+ listUserSkills = async (username, options) => {
155
+ return customFetch(
156
+ getListUserSkillsUrl(username),
157
+ {
158
+ ...options,
159
+ method: "GET"
160
+ }
161
+ );
162
+ };
163
+ getGetSkillUrl = (username, name) => {
164
+ return `/api/skills/@user/${username}/${name}`;
165
+ };
166
+ getSkill = async (username, name, options) => {
167
+ return customFetch(
168
+ getGetSkillUrl(username, name),
169
+ {
170
+ ...options,
171
+ method: "GET"
172
+ }
173
+ );
174
+ };
112
175
  getDeleteSkillUrl = (username, name) => {
113
176
  return `/api/skills/@user/${username}/${name}`;
114
177
  };
@@ -173,10 +236,77 @@ var init_generated = __esm({
173
236
  }
174
237
  );
175
238
  };
239
+ getListOrgSkillVersionsUrl = (orgname, name) => {
240
+ return `/api/skills/@org/${orgname}/${name}/versions`;
241
+ };
242
+ listOrgSkillVersions = async (orgname, name, options) => {
243
+ return customFetch(
244
+ getListOrgSkillVersionsUrl(orgname, name),
245
+ {
246
+ ...options,
247
+ method: "GET"
248
+ }
249
+ );
250
+ };
251
+ getGetOrgSkillVersionUrl = (orgname, name, version3) => {
252
+ return `/api/skills/@org/${orgname}/${name}/versions/${version3}`;
253
+ };
254
+ getOrgSkillVersion = async (orgname, name, version3, options) => {
255
+ return customFetch(
256
+ getGetOrgSkillVersionUrl(orgname, name, version3),
257
+ {
258
+ ...options,
259
+ method: "GET"
260
+ }
261
+ );
262
+ };
263
+ getPublishOrgSkillUrl = (orgname) => {
264
+ return `/api/skills/@org/${orgname}/publish`;
265
+ };
266
+ publishOrgSkill = async (orgname, publishSkillInput, options) => {
267
+ return customFetch(
268
+ getPublishOrgSkillUrl(orgname),
269
+ {
270
+ ...options,
271
+ method: "POST",
272
+ headers: { "Content-Type": "application/json", ...options?.headers },
273
+ body: JSON.stringify(
274
+ publishSkillInput
275
+ )
276
+ }
277
+ );
278
+ };
176
279
  }
177
280
  });
178
281
 
179
282
  // src/api-client.ts
283
+ var api_client_exports = {};
284
+ __export(api_client_exports, {
285
+ SDKError: () => SDKError,
286
+ changeSkillAccess: () => changeSkillAccess,
287
+ configure: () => configure2,
288
+ deleteSkill: () => deleteSkill,
289
+ deleteSkillVersion: () => deleteSkillVersion,
290
+ deprecateSkillVersion: () => deprecateSkillVersion,
291
+ exchangeCliToken: () => exchangeCliToken,
292
+ fetchSkillList: () => fetchSkillList,
293
+ getConfig: () => getConfig,
294
+ getGithubSkillVersion: () => getGithubSkillVersion,
295
+ getOrgSkillVersion: () => getOrgSkillVersion,
296
+ getSkill: () => getSkill,
297
+ getSkillVersion: () => getSkillVersion,
298
+ isConfigured: () => isConfigured,
299
+ listGithubSkillVersions: () => listGithubSkillVersions,
300
+ listMySkills: () => listMySkills,
301
+ listOrgSkillVersions: () => listOrgSkillVersions,
302
+ listSkillVersions: () => listSkillVersions,
303
+ listUserSkills: () => listUserSkills,
304
+ me: () => me,
305
+ publishOrgSkill: () => publishOrgSkill,
306
+ publishSkill: () => publishSkill,
307
+ undeprecateSkillVersion: () => undeprecateSkillVersion,
308
+ whoamiRequest: () => whoamiRequest
309
+ });
180
310
  function registryUrlToBaseUrl(registryUrl) {
181
311
  return registryUrl.replace(/\/api\/skills\/?$/, "");
182
312
  }
@@ -258,6 +388,32 @@ async function undeprecateSkillVersion(username, skillName, version3) {
258
388
  };
259
389
  }
260
390
  }
391
+ async function fetchSkillList(ownerType, ownerName, listName) {
392
+ const config2 = getConfig();
393
+ try {
394
+ const response = await fetch(
395
+ `${config2.baseUrl}/api/skill-lists/lists/@${ownerType}/${ownerName}/${listName}`,
396
+ {
397
+ method: "GET",
398
+ headers: {
399
+ "Content-Type": "application/json",
400
+ ...config2.apiKey ? { Authorization: `Bearer ${config2.apiKey}` } : {}
401
+ }
402
+ }
403
+ );
404
+ if (!response.ok) {
405
+ const error = await response.text();
406
+ return { status: response.status, error };
407
+ }
408
+ const data = await response.json();
409
+ return { status: response.status, data };
410
+ } catch (error) {
411
+ return {
412
+ status: 500,
413
+ error: error instanceof Error ? error.message : "Unknown error"
414
+ };
415
+ }
416
+ }
261
417
  async function listGithubSkillVersions(owner, repo, name) {
262
418
  const config2 = getConfig();
263
419
  try {
@@ -1020,6 +1176,10 @@ async function resolveRecursive(rootDeps, config2) {
1020
1176
  );
1021
1177
  versionsStatus = resp.status;
1022
1178
  versionsData = resp.data;
1179
+ } else if (parsed.namespace === "org") {
1180
+ const resp = await listOrgSkillVersions(parsed.owner, parsed.name);
1181
+ versionsStatus = resp.status;
1182
+ versionsData = resp.status === 200 ? resp.data : void 0;
1023
1183
  } else {
1024
1184
  const resp = await listSkillVersions(parsed.owner, parsed.name);
1025
1185
  versionsStatus = resp.status;
@@ -1065,6 +1225,15 @@ async function resolveRecursive(rootDeps, config2) {
1065
1225
  if (resp.status === 200 && resp.data) {
1066
1226
  versionData = resp.data;
1067
1227
  }
1228
+ } else if (parsed.namespace === "org") {
1229
+ const resp = await getOrgSkillVersion(
1230
+ parsed.owner,
1231
+ parsed.name,
1232
+ resolvedVersion
1233
+ );
1234
+ if (resp.status === 200 && resp.data) {
1235
+ versionData = resp.data;
1236
+ }
1068
1237
  } else {
1069
1238
  const resp = await getSkillVersion(
1070
1239
  parsed.owner,
@@ -1133,6 +1302,9 @@ async function resolveRecursive(rootDeps, config2) {
1133
1302
  p2Parsed.subname
1134
1303
  );
1135
1304
  p2Versions = resp.status === 200 ? resp.data : void 0;
1305
+ } else if (p2Parsed.namespace === "org") {
1306
+ const resp = await listOrgSkillVersions(p2Parsed.owner, p2Parsed.name);
1307
+ p2Versions = resp.status === 200 ? resp.data : void 0;
1136
1308
  } else {
1137
1309
  const resp = await listSkillVersions(p2Parsed.owner, p2Parsed.name);
1138
1310
  p2Versions = resp.status === 200 ? resp.data : void 0;
@@ -1168,6 +1340,15 @@ async function resolveRecursive(rootDeps, config2) {
1168
1340
  if (resp.status === 200 && resp.data) {
1169
1341
  p2VersionData = resp.data;
1170
1342
  }
1343
+ } else if (p2Parsed.namespace === "org") {
1344
+ const resp = await getOrgSkillVersion(
1345
+ p2Parsed.owner,
1346
+ p2Parsed.name,
1347
+ finalVersion
1348
+ );
1349
+ if (resp.status === 200 && resp.data) {
1350
+ p2VersionData = resp.data;
1351
+ }
1171
1352
  } else {
1172
1353
  const resp = await getSkillVersion(
1173
1354
  p2Parsed.owner,
@@ -3886,6 +4067,22 @@ async function install(specifiers, options) {
3886
4067
  const { setGlobalMode: setGlobalMode2 } = await Promise.resolve().then(() => (init_config(), config_exports));
3887
4068
  setGlobalMode2(true);
3888
4069
  }
4070
+ if (options.list) {
4071
+ const listSpecifiers = await resolveListToSpecifiers(options.list);
4072
+ if (listSpecifiers.length === 0) {
4073
+ console.log("No skills in the list to install.");
4074
+ return;
4075
+ }
4076
+ const allSpecifiers = [...specifiers, ...listSpecifiers];
4077
+ const { add: add2 } = await Promise.resolve().then(() => (init_add(), add_exports));
4078
+ await add2(allSpecifiers, {
4079
+ save: true,
4080
+ agent: options.agent,
4081
+ yes: options.yes,
4082
+ global: options.global
4083
+ });
4084
+ return;
4085
+ }
3889
4086
  if (specifiers.length > 0) {
3890
4087
  const { add: add2 } = await Promise.resolve().then(() => (init_add(), add_exports));
3891
4088
  await add2(specifiers, {
@@ -3898,6 +4095,52 @@ async function install(specifiers, options) {
3898
4095
  }
3899
4096
  await installFromLockfile(options);
3900
4097
  }
4098
+ async function resolveListToSpecifiers(listSpec) {
4099
+ const match = listSpec.match(/^@(user|org)\/([^/]+)\/([^/]+)$/);
4100
+ if (!match) {
4101
+ console.error(
4102
+ `Error: Invalid list specifier "${listSpec}". Use format: @user/{username}/{list-name} or @org/{orgname}/{list-name}`
4103
+ );
4104
+ process.exit(1);
4105
+ }
4106
+ const [, ownerType, ownerName, listName] = match;
4107
+ const config2 = await resolveConfig();
4108
+ configure2({
4109
+ registryUrl: config2.registryUrl,
4110
+ apiKey: getTokenForRegistry(config2, config2.registryUrl)
4111
+ });
4112
+ console.log(
4113
+ `Fetching skill list @${ownerType}/${ownerName}/${listName}...
4114
+ `
4115
+ );
4116
+ const { fetchSkillList: fetchSkillList2 } = await Promise.resolve().then(() => (init_api_client(), api_client_exports));
4117
+ const response = await fetchSkillList2(
4118
+ ownerType,
4119
+ ownerName,
4120
+ listName
4121
+ );
4122
+ if (response.status !== 200 || !response.data) {
4123
+ const errorMsg = response.status === 404 ? `List "@${ownerType}/${ownerName}/${listName}" not found or is private.` : response.error || "Failed to fetch list";
4124
+ console.error(`Error: ${errorMsg}`);
4125
+ process.exit(1);
4126
+ }
4127
+ const list2 = response.data;
4128
+ console.log(
4129
+ `List: ${list2.name}${list2.description ? ` \u2014 ${list2.description}` : ""}`
4130
+ );
4131
+ console.log(`Skills: ${list2.items.length}
4132
+ `);
4133
+ const specifiers = [];
4134
+ for (const item of list2.items) {
4135
+ const ns = item.namespace === "org" ? "org" : "user";
4136
+ let spec = `@${ns}/${item.ownerName}/${item.skillName}`;
4137
+ if (item.pinnedVersion) {
4138
+ spec += `@${item.pinnedVersion}`;
4139
+ }
4140
+ specifiers.push(spec);
4141
+ }
4142
+ return specifiers;
4143
+ }
3901
4144
  async function installFromLockfile(options) {
3902
4145
  try {
3903
4146
  const config2 = await resolveConfig();
@@ -5348,13 +5591,25 @@ async function publishCommand(options) {
5348
5591
  console.log("");
5349
5592
  console.log(`pspm notice Publishing to ${registryUrl} with tag latest`);
5350
5593
  configure2({ registryUrl, apiKey });
5351
- const response = await publishSkill({
5352
- manifest: packageJson2,
5353
- tarballBase64,
5354
- visibility: options.access
5355
- });
5594
+ let response;
5595
+ if (options.org) {
5596
+ response = await publishOrgSkill(options.org, {
5597
+ manifest: packageJson2,
5598
+ tarballBase64,
5599
+ visibility: options.access
5600
+ });
5601
+ } else {
5602
+ response = await publishSkill({
5603
+ manifest: packageJson2,
5604
+ tarballBase64,
5605
+ visibility: options.access
5606
+ });
5607
+ }
5356
5608
  if (response.status !== 200) {
5357
- const errorMessage = extractApiErrorMessage(response, "Publish failed");
5609
+ const errorMessage = extractApiErrorMessage(
5610
+ { status: response.status, data: response.data },
5611
+ "Publish failed"
5612
+ );
5358
5613
  if (errorMessage.includes("must be greater than") || errorMessage.includes("already exists")) {
5359
5614
  console.error("pspm error code E403");
5360
5615
  console.error(
@@ -5365,9 +5620,11 @@ async function publishCommand(options) {
5365
5620
  }
5366
5621
  const result = response.data;
5367
5622
  const visibility = result.skill.visibility;
5368
- const visibilityIcon = visibility === "public" ? "\u{1F310}" : "\u{1F512}";
5623
+ const visibilityIcon = visibility === "public" ? "\u{1F310}" : visibility === "team" ? "\u{1F465}" : "\u{1F512}";
5624
+ const namespace = options.org ? "org" : result.skill.namespace ?? "user";
5625
+ const owner = options.org ?? result.skill.username;
5369
5626
  console.log(
5370
- `+ @${result.skill.namespace ?? "user"}/${result.skill.username}/${result.skill.name}@${result.version.version}`
5627
+ `+ @${namespace}/${owner}/${result.skill.name}@${result.version.version}`
5371
5628
  );
5372
5629
  console.log(`Checksum: ${result.version.checksum}`);
5373
5630
  console.log(`Visibility: ${visibilityIcon} ${visibility}`);
@@ -6021,11 +6278,15 @@ program.command("install [specifiers...]").alias("i").description(
6021
6278
  ).option("--frozen-lockfile", "Fail if lockfile is missing or outdated").option("--dir <path>", "Install skills to a specific directory").option(
6022
6279
  "--agent <agents>",
6023
6280
  'Comma-separated agents for symlinks (default: all agents, use "none" to skip)'
6281
+ ).option(
6282
+ "--list <specifier>",
6283
+ "Install all skills from a skill list (e.g. @user/username/list-name)"
6024
6284
  ).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) => {
6025
6285
  await install(specifiers, {
6026
6286
  frozenLockfile: options.frozenLockfile,
6027
6287
  dir: options.dir,
6028
6288
  agent: options.agent,
6289
+ list: options.list,
6029
6290
  yes: options.yes,
6030
6291
  global: options.global
6031
6292
  });
@@ -6070,19 +6331,24 @@ program.command("version <bump>").description("Bump package version (major, mino
6070
6331
  dryRun: options.dryRun
6071
6332
  });
6072
6333
  });
6073
- program.command("publish").description("Publish current directory as a skill").option("--bump <level>", "Bump version (major, minor, patch)").option("--tag <tag>", "Tag for the release").requiredOption(
6334
+ program.command("publish").description("Publish current directory as a skill").option("--bump <level>", "Bump version (major, minor, patch)").option("--tag <tag>", "Tag for the release").option("--org <orgname>", "Publish under an organization namespace").requiredOption(
6074
6335
  "--access <level>",
6075
- "Set package visibility (public or private)"
6336
+ "Set package visibility (public, private, or team)"
6076
6337
  ).action(async (options) => {
6077
6338
  const access3 = options.access;
6078
- if (access3 !== "public" && access3 !== "private") {
6079
- console.error('Error: --access must be "public" or "private"');
6339
+ if (access3 !== "public" && access3 !== "private" && access3 !== "team") {
6340
+ console.error('Error: --access must be "public", "private", or "team"');
6341
+ process.exit(1);
6342
+ }
6343
+ if (access3 === "team" && !options.org) {
6344
+ console.error("Error: --access team requires --org <orgname>");
6080
6345
  process.exit(1);
6081
6346
  }
6082
6347
  await publishCommand({
6083
6348
  bump: options.bump,
6084
6349
  tag: options.tag,
6085
- access: access3
6350
+ access: access3,
6351
+ org: options.org
6086
6352
  });
6087
6353
  });
6088
6354
  program.command("unpublish <specifier>").description(