cwm-assistant 0.2.0 → 0.3.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/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-
|
|
10
|
+
const { cli } = await import("./cli-5CFP7QJS.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
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Local Git and workspace assistant for the CWM browser workbench",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cwm",
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
"files": [
|
|
31
31
|
"dist",
|
|
32
32
|
"scripts/postinstall.mjs",
|
|
33
|
+
"scripts/upgrade.mjs",
|
|
33
34
|
"README.md",
|
|
34
35
|
"LICENSE"
|
|
35
36
|
],
|
package/scripts/postinstall.mjs
CHANGED
|
@@ -58,11 +58,15 @@ async function main() {
|
|
|
58
58
|
quiet("安装包缺少构建产物,请运行 cwm-assistant start 手动启动。");
|
|
59
59
|
return;
|
|
60
60
|
}
|
|
61
|
-
const child = spawn(
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
61
|
+
const child = spawn(
|
|
62
|
+
process.execPath,
|
|
63
|
+
[entry, "install", "--prefix", process.env.npm_config_prefix],
|
|
64
|
+
{
|
|
65
|
+
detached: true,
|
|
66
|
+
windowsHide: true,
|
|
67
|
+
stdio: "ignore",
|
|
68
|
+
},
|
|
69
|
+
);
|
|
66
70
|
child.unref();
|
|
67
71
|
}
|
|
68
72
|
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Runs `/v1/upgrade`: waits for the daemon to exit, installs the requested version, restarts it.
|
|
3
|
+
//
|
|
4
|
+
// Spawned detached with only the state directory to go on, so it must not assume a terminal, a
|
|
5
|
+
// cwd under the package, or that the daemon is still alive when it starts.
|
|
6
|
+
|
|
7
|
+
import { spawn } from "node:child_process";
|
|
8
|
+
import fs from "node:fs";
|
|
9
|
+
import os from "node:os";
|
|
10
|
+
import path from "node:path";
|
|
11
|
+
import { fileURLToPath } from "node:url";
|
|
12
|
+
|
|
13
|
+
const packageRoot = path.dirname(path.dirname(fileURLToPath(import.meta.url)));
|
|
14
|
+
|
|
15
|
+
export function parseArgs(args) {
|
|
16
|
+
const versionIndex = args.indexOf("--version");
|
|
17
|
+
const stateIndex = args.indexOf("--state-dir");
|
|
18
|
+
return {
|
|
19
|
+
version: versionIndex >= 0 ? args[versionIndex + 1] : "",
|
|
20
|
+
stateDirectory: stateIndex >= 0 ? args[stateIndex + 1] : "",
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** The daemon writes its pid here; waiting for it to vanish avoids installing into a live tree. */
|
|
25
|
+
export async function waitForExit(lockFile, deadlineMs = 30_000) {
|
|
26
|
+
const deadline = Date.now() + deadlineMs;
|
|
27
|
+
while (Date.now() < deadline) {
|
|
28
|
+
if (!fs.existsSync(lockFile)) return true;
|
|
29
|
+
const pid = Number(fs.readFileSync(lockFile, "utf8"));
|
|
30
|
+
try {
|
|
31
|
+
process.kill(pid, 0);
|
|
32
|
+
} catch {
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
36
|
+
}
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function record(stateDirectory, value) {
|
|
41
|
+
if (!stateDirectory) return;
|
|
42
|
+
try {
|
|
43
|
+
fs.writeFileSync(path.join(stateDirectory, "upgrade.json"), JSON.stringify(value), {
|
|
44
|
+
mode: 0o600,
|
|
45
|
+
});
|
|
46
|
+
} catch {
|
|
47
|
+
/* The status file is advisory; a failed write must not block the upgrade. */
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async function main() {
|
|
52
|
+
const { version, stateDirectory } = parseArgs(process.argv.slice(2));
|
|
53
|
+
if (!version) throw new Error("缺少目标版本");
|
|
54
|
+
const directory = stateDirectory || path.join(os.homedir(), ".cwm-assistant");
|
|
55
|
+
const finished = await waitForExit(path.join(directory, "process.lock"));
|
|
56
|
+
if (!finished) throw new Error("助手未在预期时间内退出");
|
|
57
|
+
|
|
58
|
+
const npm = process.platform === "win32" ? "npm.cmd" : "npm";
|
|
59
|
+
const installed = await new Promise((resolve) => {
|
|
60
|
+
const child = spawn(npm, ["install", "-g", "cwm-assistant@" + version], {
|
|
61
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
62
|
+
shell: false,
|
|
63
|
+
windowsHide: true,
|
|
64
|
+
});
|
|
65
|
+
let output = "";
|
|
66
|
+
const collect = (chunk) => {
|
|
67
|
+
output += chunk;
|
|
68
|
+
if (output.length > 8000) output = output.slice(-8000);
|
|
69
|
+
};
|
|
70
|
+
child.stdout?.on("data", collect);
|
|
71
|
+
child.stderr?.on("data", collect);
|
|
72
|
+
child.once("error", (error) => resolve({ ok: false, output: error.message }));
|
|
73
|
+
child.once("close", (code) => resolve({ ok: code === 0, output: output.trim().slice(-2000) }));
|
|
74
|
+
});
|
|
75
|
+
if (!installed.ok) throw new Error(installed.output || "npm 安装失败");
|
|
76
|
+
|
|
77
|
+
// The reinstall ran postinstall, which starts the daemon again. Nothing else to do here.
|
|
78
|
+
record(stateDirectory, {
|
|
79
|
+
target: version,
|
|
80
|
+
state: "ok",
|
|
81
|
+
finishedAt: new Date().toISOString(),
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const invoked = process.argv[1];
|
|
86
|
+
if (invoked && path.resolve(invoked) === fileURLToPath(import.meta.url)) {
|
|
87
|
+
main()
|
|
88
|
+
.catch((error) => {
|
|
89
|
+
const { stateDirectory, version } = parseArgs(process.argv.slice(2));
|
|
90
|
+
record(stateDirectory, {
|
|
91
|
+
target: version,
|
|
92
|
+
state: "failed",
|
|
93
|
+
error: error instanceof Error ? error.message : String(error),
|
|
94
|
+
finishedAt: new Date().toISOString(),
|
|
95
|
+
});
|
|
96
|
+
process.exitCode = 1;
|
|
97
|
+
})
|
|
98
|
+
.finally(() => process.exit(process.exitCode ?? 0));
|
|
99
|
+
}
|