cwm-assistant 0.3.3 → 0.3.5

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/main.js CHANGED
@@ -7,7 +7,7 @@ if (major < 22 || major === 22 && minor < 13) {
7
7
  console.error("Workspace \u52A9\u624B\u9700\u8981 Node.js 22.13 \u6216\u66F4\u9AD8\u7248\u672C\uFF08\u63A8\u8350 24 LTS\uFF09\u3002");
8
8
  process.exitCode = 1;
9
9
  } else {
10
- const { cli } = await import("./cli-ZVCMSNB3.js");
10
+ const { cli } = await import("./cli-VXWMAG3L.js");
11
11
  cli(process.argv.slice(2), fileURLToPath(import.meta.url)).catch((error) => {
12
12
  console.error(error instanceof Error ? error.message : String(error));
13
13
  process.exitCode = 1;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cwm-assistant",
3
- "version": "0.3.3",
3
+ "version": "0.3.5",
4
4
  "description": "Local Git and workspace assistant for the CWM browser workbench",
5
5
  "keywords": [
6
6
  "cwm",
@@ -49,26 +49,36 @@ function record(stateDirectory, value) {
49
49
  }
50
50
 
51
51
  /**
52
- * Find npm without relying on PATH.
52
+ * Find npm without relying on PATH, preferring npm's own JS entry point.
53
53
  *
54
- * A login item starts with a minimal environment — no Homebrew, no nvm — so a bare `npm` spawn
55
- * fails with ENOENT even though the shell that installed the package finds it. Every candidate is
56
- * checked for existence; the bare name is the last resort for setups that do export PATH.
54
+ * Two platform traps make the shim a poor first choice:
55
+ * - Windows: Node refuses to spawn a `.cmd` without a shell since the 2024 command-injection fix,
56
+ * so `spawn("npm.cmd")` throws EINVAL outright.
57
+ * - macOS: a login item runs with a bare PATH, so the shim beside node may not resolve at all.
58
+ * Running `node npm-cli.js` sidesteps both.
57
59
  */
58
60
  export function npmCandidates(platform = process.platform, execPath = process.execPath) {
59
- const names = platform === "win32" ? ["npm.cmd"] : ["npm"];
60
61
  const beside = path.dirname(execPath);
61
- const candidates = names.map((name) => path.join(beside, name));
62
- // npm's own entry point, present in every Node distribution regardless of the shim.
63
- candidates.push(path.join(beside, "..", "lib", "node_modules", "npm", "bin", "npm-cli.js"));
64
- if (platform !== "win32") candidates.push("/opt/homebrew/bin/npm", "/usr/local/bin/npm");
65
- candidates.push(...names);
62
+ const candidates = [
63
+ // Windows ships npm under <node>/node_modules; Homebrew and Linux use <node>/../lib/node_modules.
64
+ path.join(beside, "node_modules", "npm", "bin", "npm-cli.js"),
65
+ path.join(beside, "..", "lib", "node_modules", "npm", "bin", "npm-cli.js"),
66
+ ];
67
+ if (platform === "win32") candidates.push(path.join(beside, "npm.cmd"));
68
+ else
69
+ candidates.push(
70
+ path.join(beside, "npm"),
71
+ "/opt/homebrew/bin/npm",
72
+ "/usr/local/bin/npm",
73
+ "/usr/bin/npm",
74
+ );
75
+ candidates.push(platform === "win32" ? "npm.cmd" : "npm");
66
76
  return candidates;
67
77
  }
68
78
 
69
79
  export function resolveNpm(platform = process.platform, execPath = process.execPath) {
70
80
  for (const candidate of npmCandidates(platform, execPath)) {
71
- if (!candidate.includes(path.sep) && !path.isAbsolute(candidate)) return candidate;
81
+ if (!path.isAbsolute(candidate)) return candidate;
72
82
  try {
73
83
  if (fs.statSync(candidate).isFile()) return candidate;
74
84
  } catch {
@@ -78,6 +88,22 @@ export function resolveNpm(platform = process.platform, execPath = process.execP
78
88
  return platform === "win32" ? "npm.cmd" : "npm";
79
89
  }
80
90
 
91
+ /** Restart the daemon we stopped, so a failed upgrade does not leave the machine with none. */
92
+ function restartInstalled(stateDirectory) {
93
+ const entry = path.join(packageRoot, "dist", "main.js");
94
+ if (!fs.existsSync(entry)) return;
95
+ try {
96
+ const child = spawn(process.execPath, [entry, "start", "--state-dir", stateDirectory], {
97
+ detached: true,
98
+ stdio: "ignore",
99
+ windowsHide: true,
100
+ });
101
+ child.unref();
102
+ } catch {
103
+ /* Nothing more to do; the user can run cwm-assistant start. */
104
+ }
105
+ }
106
+
81
107
  async function main() {
82
108
  const { version, stateDirectory } = parseArgs(process.argv.slice(2));
83
109
  if (!version) throw new Error("缺少目标版本");
@@ -113,7 +139,12 @@ async function main() {
113
139
  child.once("error", (error) => resolve({ ok: false, output: error.message }));
114
140
  child.once("close", (code) => resolve({ ok: code === 0, output: output.trim().slice(-2000) }));
115
141
  });
116
- if (!installed.ok) throw new Error(installed.output || "npm 安装失败");
142
+ if (!installed.ok) {
143
+ // The daemon was stopped to make room for the install; put the old build back on its feet
144
+ // rather than leaving the machine with no assistant at all.
145
+ restartInstalled(directory);
146
+ throw new Error(installed.output || "npm 安装失败");
147
+ }
117
148
 
118
149
  // The reinstall ran postinstall, which starts the daemon again. Nothing else to do here.
119
150
  record(stateDirectory, {