@anytio/pspm 0.7.0 → 0.7.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/CHANGELOG.md CHANGED
@@ -5,6 +5,20 @@ 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.7.2] - 2026-03-02
9
+
10
+ ### Fixed
11
+
12
+ - **Fix npm install failure**: Moved `@repo/pspm-types` and `@repo/skill-registry` from `dependencies` to `devDependencies` to prevent npm from trying to install workspace-only packages from the public registry
13
+
14
+ ## [0.7.1] - 2026-03-02
15
+
16
+ ### Added
17
+
18
+ - **`outdated` command**: Check for outdated packages in your project
19
+ - Shows installed vs latest versions for registry, GitHub, and local dependencies
20
+ - Helps identify which packages need updating
21
+
8
22
  ## [0.7.0] - 2026-02-25
9
23
 
10
24
  ### Changed
package/README.md CHANGED
@@ -80,6 +80,7 @@ pspm list # List installed skills (alias: ls)
80
80
  pspm install [specifiers...] # Install from lockfile, or add specific packages (alias: i)
81
81
  pspm link # Recreate agent symlinks without reinstalling
82
82
  pspm update # Update skills to latest compatible versions
83
+ pspm outdated # Check for outdated packages
83
84
  ```
84
85
 
85
86
  **Multiple package support (like npm):**
package/dist/index.js CHANGED
@@ -1986,16 +1986,16 @@ async function installFromNode(node, options) {
1986
1986
  const skillsDir = getSkillsDir();
1987
1987
  const destDir = join(skillsDir, username, name);
1988
1988
  await mkdir(destDir, { recursive: true });
1989
- const { writeFile: writeFile8 } = await import('fs/promises');
1989
+ const { writeFile: writeFile9 } = await import('fs/promises');
1990
1990
  const tempFile = join(destDir, ".temp.tgz");
1991
- await writeFile8(tempFile, tarballBuffer);
1991
+ await writeFile9(tempFile, tarballBuffer);
1992
1992
  const { exec: exec2 } = await import('child_process');
1993
1993
  const { promisify: promisify2 } = await import('util');
1994
1994
  const execAsync = promisify2(exec2);
1995
1995
  try {
1996
1996
  await rm(destDir, { recursive: true, force: true });
1997
1997
  await mkdir(destDir, { recursive: true });
1998
- await writeFile8(tempFile, tarballBuffer);
1998
+ await writeFile9(tempFile, tarballBuffer);
1999
1999
  await execAsync(
2000
2000
  `tar -xzf "${tempFile}" -C "${destDir}" --strip-components=1`
2001
2001
  );
@@ -2331,19 +2331,19 @@ async function access(specifier, options) {
2331
2331
  packageName = parsed.name;
2332
2332
  packageUsername = parsed.username;
2333
2333
  } else {
2334
- const { readFile: readFile8 } = await import('fs/promises');
2335
- const { join: join14 } = await import('path');
2334
+ const { readFile: readFile9 } = await import('fs/promises');
2335
+ const { join: join15 } = await import('path');
2336
2336
  let manifest = null;
2337
2337
  try {
2338
- const content = await readFile8(
2339
- join14(process.cwd(), "pspm.json"),
2338
+ const content = await readFile9(
2339
+ join15(process.cwd(), "pspm.json"),
2340
2340
  "utf-8"
2341
2341
  );
2342
2342
  manifest = JSON.parse(content);
2343
2343
  } catch {
2344
2344
  try {
2345
- const content = await readFile8(
2346
- join14(process.cwd(), "package.json"),
2345
+ const content = await readFile9(
2346
+ join15(process.cwd(), "package.json"),
2347
2347
  "utf-8"
2348
2348
  );
2349
2349
  manifest = JSON.parse(content);
@@ -3679,6 +3679,267 @@ async function migrate(options) {
3679
3679
  process.exit(1);
3680
3680
  }
3681
3681
  }
3682
+ function resolveVersion2(range, availableVersions) {
3683
+ const sorted = availableVersions.filter((v) => semver.valid(v)).sort((a, b) => semver.rcompare(a, b));
3684
+ if (range === "latest") {
3685
+ return sorted[0] ?? null;
3686
+ }
3687
+ return semver.maxSatisfying(sorted, range);
3688
+ }
3689
+ function compareVersions2(a, b) {
3690
+ return semver.compare(a, b);
3691
+ }
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];
3696
+ }
3697
+
3698
+ // ../../packages/server/skill-registry/src/client/outdated.ts
3699
+ function createOutdatedChecker(config2) {
3700
+ const { registryUrl, apiKey, githubToken } = config2;
3701
+ async function fetchWithAuth(url, token) {
3702
+ const headers = {};
3703
+ if (token) {
3704
+ headers.Authorization = `Bearer ${token}`;
3705
+ }
3706
+ const response = await fetch(url, { headers });
3707
+ if (!response.ok) {
3708
+ const text = await response.text();
3709
+ throw new Error(`Request failed (${response.status}): ${text}`);
3710
+ }
3711
+ return response;
3712
+ }
3713
+ async function fetchRegistryVersions(username, name) {
3714
+ const url = `${registryUrl}/@user/${username}/${name}/versions`;
3715
+ const response = await fetchWithAuth(url, apiKey);
3716
+ return await response.json();
3717
+ }
3718
+ async function checkRegistryPackage(specifier, entry, versionRange) {
3719
+ const match = specifier.match(/^@user\/([^/]+)\/([^/]+)$/);
3720
+ if (!match) {
3721
+ throw new Error(`Invalid registry specifier: ${specifier}`);
3722
+ }
3723
+ const [, username, name] = match;
3724
+ try {
3725
+ const versions = await fetchRegistryVersions(username, name);
3726
+ const versionStrings = versions.map((v) => v.version);
3727
+ const range = versionRange || "*";
3728
+ const wanted = resolveVersion2(range, versionStrings);
3729
+ const latest = getLatestVersion2(versionStrings);
3730
+ const currentVersionInfo = versions.find(
3731
+ (v) => v.version === entry.version
3732
+ );
3733
+ 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;
3736
+ return {
3737
+ name: specifier,
3738
+ current: entry.version,
3739
+ wanted,
3740
+ latest,
3741
+ type: "registry",
3742
+ isOutdated,
3743
+ wantedBehindLatest,
3744
+ versionRange: range,
3745
+ deprecated
3746
+ };
3747
+ } catch {
3748
+ return {
3749
+ name: specifier,
3750
+ current: entry.version,
3751
+ wanted: null,
3752
+ latest: null,
3753
+ type: "registry",
3754
+ isOutdated: false,
3755
+ wantedBehindLatest: false,
3756
+ versionRange
3757
+ };
3758
+ }
3759
+ }
3760
+ async function fetchGitHubLatestCommit(owner, repo, ref) {
3761
+ try {
3762
+ const url = `https://api.github.com/repos/${owner}/${repo}/commits/${ref}`;
3763
+ const response = await fetchWithAuth(url, githubToken);
3764
+ const data = await response.json();
3765
+ return data.sha;
3766
+ } catch {
3767
+ return null;
3768
+ }
3769
+ }
3770
+ async function checkGitHubPackage(specifier, entry) {
3771
+ const match = specifier.match(
3772
+ /^github:([a-zA-Z0-9_-]+)\/([a-zA-Z0-9_.-]+)/
3773
+ );
3774
+ if (!match) {
3775
+ throw new Error(`Invalid GitHub specifier: ${specifier}`);
3776
+ }
3777
+ const [, owner, repo] = match;
3778
+ const ref = entry.gitRef || "HEAD";
3779
+ const latestCommit = await fetchGitHubLatestCommit(owner, repo, ref);
3780
+ const currentShort = entry.gitCommit.slice(0, 7);
3781
+ const latestShort = latestCommit?.slice(0, 7) ?? null;
3782
+ const isOutdated = latestCommit !== null && entry.gitCommit !== latestCommit;
3783
+ return {
3784
+ name: specifier,
3785
+ current: currentShort,
3786
+ wanted: latestShort,
3787
+ latest: latestShort,
3788
+ type: "github",
3789
+ isOutdated,
3790
+ wantedBehindLatest: false,
3791
+ versionRange: ref
3792
+ };
3793
+ }
3794
+ function checkLocalPackage(specifier, _entry) {
3795
+ return {
3796
+ name: specifier,
3797
+ current: "local",
3798
+ wanted: null,
3799
+ latest: null,
3800
+ type: "local",
3801
+ isOutdated: false,
3802
+ wantedBehindLatest: false
3803
+ };
3804
+ }
3805
+ async function checkOutdated2(options) {
3806
+ const {
3807
+ lockfile,
3808
+ manifest,
3809
+ includeUpToDate = false,
3810
+ includeLocal = false,
3811
+ packages: filterPackages
3812
+ } = options;
3813
+ const results = [];
3814
+ const registryPackages = lockfile.packages || lockfile.skills || {};
3815
+ const registryDeps = manifest?.dependencies || {};
3816
+ const registryEntries = Object.entries(registryPackages).filter(
3817
+ ([specifier]) => !filterPackages || filterPackages.includes(specifier)
3818
+ );
3819
+ const registryResults = await Promise.all(
3820
+ registryEntries.map(
3821
+ ([specifier, entry]) => checkRegistryPackage(
3822
+ specifier,
3823
+ entry,
3824
+ registryDeps[specifier]
3825
+ )
3826
+ )
3827
+ );
3828
+ results.push(...registryResults);
3829
+ const githubPackages = lockfile.githubPackages || {};
3830
+ const githubEntries = Object.entries(githubPackages).filter(
3831
+ ([specifier]) => !filterPackages || filterPackages.includes(specifier)
3832
+ );
3833
+ const githubResults = await Promise.all(
3834
+ githubEntries.map(
3835
+ ([specifier, entry]) => checkGitHubPackage(specifier, entry)
3836
+ )
3837
+ );
3838
+ results.push(...githubResults);
3839
+ if (includeLocal) {
3840
+ const localPackages = lockfile.localPackages || {};
3841
+ const localEntries = Object.entries(localPackages).filter(
3842
+ ([specifier]) => !filterPackages || filterPackages.includes(specifier)
3843
+ );
3844
+ for (const [specifier, entry] of localEntries) {
3845
+ results.push(checkLocalPackage(specifier));
3846
+ }
3847
+ }
3848
+ if (!includeUpToDate) {
3849
+ return results.filter((r) => r.isOutdated);
3850
+ }
3851
+ return results;
3852
+ }
3853
+ return {
3854
+ checkOutdated: checkOutdated2,
3855
+ checkRegistryPackage,
3856
+ checkGitHubPackage,
3857
+ checkLocalPackage,
3858
+ fetchRegistryVersions
3859
+ };
3860
+ }
3861
+ async function checkOutdated(config2, options) {
3862
+ const checker = createOutdatedChecker(config2);
3863
+ return checker.checkOutdated(options);
3864
+ }
3865
+
3866
+ // src/commands/outdated.ts
3867
+ init_config();
3868
+ init_lockfile2();
3869
+ init_manifest2();
3870
+ async function outdated(packages, options) {
3871
+ try {
3872
+ const lockfile = await readLockfile();
3873
+ if (!lockfile) {
3874
+ console.log("No skills installed.");
3875
+ return;
3876
+ }
3877
+ const hasPackages = Object.keys(lockfile.packages ?? lockfile.skills ?? {}).length > 0 || Object.keys(lockfile.githubPackages ?? {}).length > 0 || Object.keys(lockfile.localPackages ?? {}).length > 0;
3878
+ if (!hasPackages) {
3879
+ console.log("No skills installed.");
3880
+ return;
3881
+ }
3882
+ const config2 = await resolveConfig();
3883
+ const registryUrl = config2.registryUrl;
3884
+ const apiKey = getTokenForRegistry(config2, registryUrl);
3885
+ const githubToken = process.env.GITHUB_TOKEN;
3886
+ const manifest = await readManifest();
3887
+ console.log("Checking for outdated packages...\n");
3888
+ const results = await checkOutdated(
3889
+ { registryUrl, apiKey, githubToken },
3890
+ {
3891
+ lockfile,
3892
+ manifest: manifest ?? void 0,
3893
+ includeUpToDate: options.all,
3894
+ packages: packages.length > 0 ? packages : void 0
3895
+ }
3896
+ );
3897
+ if (results.length === 0) {
3898
+ console.log("All skills are up to date.");
3899
+ return;
3900
+ }
3901
+ if (options.json) {
3902
+ console.log(JSON.stringify(results, null, 2));
3903
+ } else {
3904
+ printTable(results);
3905
+ }
3906
+ const deprecated = results.filter((r) => r.deprecated);
3907
+ if (deprecated.length > 0) {
3908
+ console.log("");
3909
+ for (const r of deprecated) {
3910
+ console.log(`\x1B[33m\u26A0 ${r.name}: ${r.deprecated}\x1B[0m`);
3911
+ }
3912
+ }
3913
+ const hasOutdated = results.some((r) => r.isOutdated);
3914
+ if (hasOutdated) {
3915
+ process.exitCode = 1;
3916
+ }
3917
+ } catch (error) {
3918
+ const message = error instanceof Error ? error.message : "Unknown error";
3919
+ console.error(`Error: ${message}`);
3920
+ process.exit(1);
3921
+ }
3922
+ }
3923
+ function printTable(results) {
3924
+ const headers = ["Package", "Current", "Wanted", "Latest", "Type"];
3925
+ const rows = results.map((r) => [
3926
+ r.name,
3927
+ r.current,
3928
+ r.wanted ?? "\u2014",
3929
+ r.latest ?? "\u2014",
3930
+ r.type
3931
+ ]);
3932
+ const widths = headers.map(
3933
+ (h, i) => Math.max(h.length, ...rows.map((row) => row[i].length))
3934
+ );
3935
+ const headerLine = headers.map((h, i) => h.padEnd(widths[i])).join(" ");
3936
+ console.log(headerLine);
3937
+ console.log(widths.map((w) => "\u2500".repeat(w)).join("\u2500\u2500"));
3938
+ for (const row of rows) {
3939
+ const line = row.map((cell, i) => cell.padEnd(widths[i])).join(" ");
3940
+ console.log(line);
3941
+ }
3942
+ }
3682
3943
 
3683
3944
  // src/commands/publish.ts
3684
3945
  init_api_client();
@@ -3813,8 +4074,8 @@ async function publishCommand(options) {
3813
4074
  dependencies: manifest.dependencies
3814
4075
  };
3815
4076
  if (options.bump) {
3816
- const semver3 = await import('semver');
3817
- const newVersion = semver3.default.inc(packageJson2.version, options.bump);
4077
+ const semver4 = await import('semver');
4078
+ const newVersion = semver4.default.inc(packageJson2.version, options.bump);
3818
4079
  if (!newVersion) {
3819
4080
  console.error(
3820
4081
  `Error: Failed to bump version from ${packageJson2.version}`
@@ -4370,6 +4631,9 @@ program.command("link").description("Recreate agent symlinks without reinstallin
4370
4631
  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) => {
4371
4632
  await update({ dryRun: options.dryRun });
4372
4633
  });
4634
+ 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) => {
4635
+ await outdated(packages, { json: options.json, all: options.all });
4636
+ });
4373
4637
  program.command("version <bump>").description("Bump package version (major, minor, patch)").option("--dry-run", "Show what would be changed without writing").action(async (bump, options) => {
4374
4638
  const validBumps = ["major", "minor", "patch"];
4375
4639
  if (!validBumps.includes(bump)) {