@bigking67/pi-67 0.10.0 → 0.10.1

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
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.10.1]
4
+
5
+ - Falls back from `npm` to `npm.cmd` on Windows when checking npm registry state
6
+ or running `pi-67 self-update`, avoiding `spawnSync npm ENOENT` in PowerShell
7
+ environments where only the command shim is directly spawnable.
8
+ - Clarifies that global install is the normal daily path and `npx @latest` is
9
+ the always-fresh one-shot validation or recovery path.
10
+
3
11
  ## [0.10.0]
4
12
 
5
13
  - Initial npm manager CLI for pi-67.
package/README.md CHANGED
@@ -55,6 +55,10 @@ If the local manager may be stale, run the latest npm package for one repair:
55
55
  npx -y @bigking67/pi-67@latest update --repair
56
56
  ```
57
57
 
58
+ Use `npm install -g @bigking67/pi-67` for normal daily operation. Use `npx -y
59
+ @bigking67/pi-67@latest ...` when you want a zero-install, always-fresh one-shot
60
+ check or repair before trusting the globally installed manager.
61
+
58
62
  ## Safety defaults
59
63
 
60
64
  `pi-67 update` preserves local runtime choices:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bigking67/pi-67",
3
- "version": "0.10.0",
3
+ "version": "0.10.1",
4
4
  "description": "Cross-platform manager CLI for the pi-67 Pi Coding Agent distribution.",
5
5
  "type": "module",
6
6
  "bin": {
package/scripts/check.mjs CHANGED
@@ -4,6 +4,7 @@ import path from "node:path";
4
4
  import { spawnSync } from "node:child_process";
5
5
  import { fileURLToPath } from "node:url";
6
6
  import { npmPublishTargetStatus } from "../src/lib/npm-registry.mjs";
7
+ import { commandCandidatesForPlatform } from "../src/lib/shell-runner.mjs";
7
8
  import { readExtensionRegistry, validateExtensionRegistry } from "../src/lib/extension-registry.mjs";
8
9
  import { buildPlanDecisions, classifyGitShort } from "../src/lib/update-plan.mjs";
9
10
  import {
@@ -26,6 +27,7 @@ for (const file of files.filter((item) => item.endsWith(".json"))) {
26
27
  JSON.parse(fs.readFileSync(file, "utf8"));
27
28
  }
28
29
  runPublishTargetSelfTests();
30
+ runShellRunnerSelfTests();
29
31
  runExtensionRegistrySelfTests();
30
32
  runUpdatePlanSelfTests();
31
33
  runUpdateSafetySelfTests();
@@ -92,6 +94,21 @@ function runPublishTargetSelfTests() {
92
94
  );
93
95
  }
94
96
 
97
+ function runShellRunnerSelfTests() {
98
+ assert(
99
+ JSON.stringify(commandCandidatesForPlatform("npm", "win32")) === JSON.stringify(["npm", "npm.cmd"]),
100
+ "Windows npm execution must fall back to npm.cmd",
101
+ );
102
+ assert(
103
+ JSON.stringify(commandCandidatesForPlatform("git", "win32")) === JSON.stringify(["git"]),
104
+ "Windows non-npm execution should keep the requested command",
105
+ );
106
+ assert(
107
+ JSON.stringify(commandCandidatesForPlatform("npm", "darwin")) === JSON.stringify(["npm"]),
108
+ "POSIX npm execution should keep the requested command",
109
+ );
110
+ }
111
+
95
112
  function runExtensionRegistrySelfTests() {
96
113
  const registry = readExtensionRegistry(path.join(root, "src", "data", "extension-registry.json"));
97
114
  const manifest = extensionRegistryTestManifest();
@@ -7,7 +7,7 @@ export function runCommand(command, args = [], options = {}) {
7
7
  info(`DRY-RUN (${cwd}) ${[command, ...args].join(" ")}`);
8
8
  return { status: 0, stdout: "", stderr: "" };
9
9
  }
10
- const result = spawnSync(command, args, {
10
+ const { result } = spawnWithFallback(command, args, {
11
11
  cwd,
12
12
  stdio: options.stdio || "inherit",
13
13
  env: { ...process.env, ...(options.env || {}) },
@@ -24,7 +24,7 @@ export function runCommand(command, args = [], options = {}) {
24
24
  }
25
25
 
26
26
  export function captureCommand(command, args = [], options = {}) {
27
- const result = spawnSync(command, args, {
27
+ const { result } = spawnWithFallback(command, args, {
28
28
  cwd: options.cwd || process.cwd(),
29
29
  env: { ...process.env, ...(options.env || {}) },
30
30
  encoding: "utf8",
@@ -38,3 +38,24 @@ export function captureCommand(command, args = [], options = {}) {
38
38
  error: result.error ? result.error.message : "",
39
39
  };
40
40
  }
41
+
42
+ export function commandCandidatesForPlatform(command, platform = process.platform) {
43
+ if (platform === "win32" && command === "npm") {
44
+ return ["npm", "npm.cmd"];
45
+ }
46
+ return [command];
47
+ }
48
+
49
+ function spawnWithFallback(command, args, options) {
50
+ let lastResult;
51
+ for (const candidate of commandCandidatesForPlatform(command)) {
52
+ const result = spawnSync(candidate, args, options);
53
+ lastResult = result;
54
+ if (!isCommandNotFound(result)) return { command: candidate, result };
55
+ }
56
+ return { command, result: lastResult };
57
+ }
58
+
59
+ function isCommandNotFound(result) {
60
+ return result?.error?.code === "ENOENT";
61
+ }