@agentprojectcontext/apx 1.22.1 → 1.22.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentprojectcontext/apx",
3
- "version": "1.22.1",
3
+ "version": "1.22.2",
4
4
  "description": "APX — unified CLI + daemon for the Agent Project Context (APC) standard.",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -1,5 +1,6 @@
1
1
  import { spawnSync } from "node:child_process";
2
2
  import readline from "node:readline";
3
+ import { fileURLToPath } from "node:url";
3
4
  import { getLatestVersion } from "../../core/update-check.js";
4
5
 
5
6
  const PACKAGE_NAME = "@agentprojectcontext/apx";
@@ -25,6 +26,30 @@ function hasPnpmGlobal() {
25
26
  return check.status === 0 && !!check.stdout?.trim();
26
27
  }
27
28
 
29
+ // Detect which package manager actually owns this apx install, by checking
30
+ // where the running files live. Most installs are npm (it was the recommended
31
+ // installer before the project moved to pnpm), so npm is the safe default
32
+ // when detection is inconclusive.
33
+ function detectInstaller() {
34
+ let selfDir;
35
+ try {
36
+ selfDir = fileURLToPath(import.meta.url);
37
+ } catch {
38
+ selfDir = "";
39
+ }
40
+ const probe = (cmd) => {
41
+ const r = spawnSync(cmd, ["root", "-g"], { encoding: "utf8", stdio: "pipe" });
42
+ return r.status === 0 ? r.stdout?.trim() || "" : "";
43
+ };
44
+ const pnpmRoot = probe("pnpm");
45
+ const npmRoot = probe("npm");
46
+ if (pnpmRoot && selfDir.startsWith(pnpmRoot)) return "pnpm";
47
+ if (npmRoot && selfDir.startsWith(npmRoot)) return "npm";
48
+ // pnpm's global store path contains a "/pnpm/" segment.
49
+ if (/[\\/]pnpm[\\/]/.test(selfDir)) return "pnpm";
50
+ return "npm";
51
+ }
52
+
28
53
  function daemonRunning() {
29
54
  const r = spawnSync("apx", ["daemon", "status", "--json"], { encoding: "utf8", stdio: "pipe" });
30
55
  try { return JSON.parse(r.stdout)?.running === true; } catch { return false; }
@@ -65,13 +90,20 @@ export async function cmdUpdate(args, currentVersion) {
65
90
  console.log("stopped.");
66
91
  }
67
92
 
68
- // Pick a package manager that can actually install global binaries. Prefer
69
- // pnpm only when its global bin directory is configured; otherwise npm. If
70
- // the first attempt fails, fall back to the other so a misconfigured pnpm
71
- // never blocks the update.
93
+ // Install with whichever package manager owns this apx install. npm is the
94
+ // default (most installs predate the move to pnpm). pnpm is used first only
95
+ // when it owns the install AND its global bin directory is configured.
96
+ // The other package manager is always kept as a fallback so a misconfigured
97
+ // pnpm never blocks the update.
72
98
  const pnpmStep = ["pnpm", ["add", "-g", `${PACKAGE_NAME}@${latest}`]];
73
99
  const npmStep = ["npm", ["install", "-g", `${PACKAGE_NAME}@${latest}`]];
74
- const steps = hasPnpmGlobal() ? [pnpmStep, npmStep] : [npmStep];
100
+ const pnpmUsable = hasPnpmGlobal();
101
+ const steps =
102
+ detectInstaller() === "pnpm" && pnpmUsable
103
+ ? [pnpmStep, npmStep]
104
+ : pnpmUsable
105
+ ? [npmStep, pnpmStep]
106
+ : [npmStep];
75
107
 
76
108
  let result;
77
109
  for (let i = 0; i < steps.length; i++) {