@xulongzhe/clawbench 0.96.0 → 0.97.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/bin/clawbench.js +5 -5
- package/bin/platform.js +21 -0
- package/bin/platform.test.js +28 -0
- package/package.json +7 -7
package/bin/clawbench.js
CHANGED
|
@@ -4,7 +4,7 @@ import { resolve, dirname } from "path";
|
|
|
4
4
|
import { fileURLToPath } from "url";
|
|
5
5
|
import { createRequire } from "module";
|
|
6
6
|
import os from "os";
|
|
7
|
-
import { resolvePlatformPackage, resolveBinName } from "./platform.js";
|
|
7
|
+
import { resolvePlatformPackage, resolveBinName, resolveSpawnOptions } from "./platform.js";
|
|
8
8
|
|
|
9
9
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
10
10
|
const require = createRequire(import.meta.url);
|
|
@@ -35,10 +35,10 @@ if (process.env.CLAWBENCH_BINARY_PATH) {
|
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
});
|
|
38
|
+
// detached: true makes the server a session leader in its own process group,
|
|
39
|
+
// so a terminal hangup cannot reach it. See resolveSpawnOptions for the full
|
|
40
|
+
// rationale. Signals are forwarded explicitly below, so Ctrl+C still stops it.
|
|
41
|
+
const child = spawn(binPath, process.argv.slice(2), resolveSpawnOptions({ ...process.env }));
|
|
42
42
|
|
|
43
43
|
// 转发信号到子进程
|
|
44
44
|
process.on("SIGINT", () => child.kill("SIGINT"));
|
package/bin/platform.js
CHANGED
|
@@ -30,3 +30,24 @@ export function resolvePlatformPackage(platform, arch) {
|
|
|
30
30
|
export function resolveBinName(platform) {
|
|
31
31
|
return platform === "win32" ? "clawbench.exe" : "clawbench";
|
|
32
32
|
}
|
|
33
|
+
|
|
34
|
+
// Returns the spawn options used to launch the server binary.
|
|
35
|
+
//
|
|
36
|
+
// `detached: true` puts the server in its own session/process group. Without
|
|
37
|
+
// it the server inherits the launcher's group, so a terminal hangup (SSH
|
|
38
|
+
// disconnect, closing the shell) delivers SIGHUP to the whole group and the
|
|
39
|
+
// server dies. `nohup` cannot prevent this: it only sets SIG_IGN on the
|
|
40
|
+
// launcher, and Node resets that disposition to SIG_DFL for itself, so the
|
|
41
|
+
// signal reaches the binary regardless. The directly-installed binary has no
|
|
42
|
+
// launcher layer and survives a hangup, which is why only the npm install
|
|
43
|
+
// showed the problem.
|
|
44
|
+
//
|
|
45
|
+
// Signals are still forwarded explicitly by the launcher, so Ctrl+C and
|
|
46
|
+
// `kill <launcher-pid>` keep stopping the server.
|
|
47
|
+
export function resolveSpawnOptions(env) {
|
|
48
|
+
return {
|
|
49
|
+
stdio: "inherit",
|
|
50
|
+
env,
|
|
51
|
+
detached: true,
|
|
52
|
+
};
|
|
53
|
+
}
|
package/bin/platform.test.js
CHANGED
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
PLATFORM_MAP,
|
|
4
4
|
resolvePlatformPackage,
|
|
5
5
|
resolveBinName,
|
|
6
|
+
resolveSpawnOptions,
|
|
6
7
|
} from './platform.js'
|
|
7
8
|
|
|
8
9
|
describe('resolvePlatformPackage', () => {
|
|
@@ -53,3 +54,30 @@ describe('PLATFORM_MAP', () => {
|
|
|
53
54
|
expect(PLATFORM_MAP['android-arm64']).toBe('@xulongzhe/clawbench-android-arm64')
|
|
54
55
|
})
|
|
55
56
|
})
|
|
57
|
+
|
|
58
|
+
describe('resolveSpawnOptions', () => {
|
|
59
|
+
// Regression guard: without detached the server joins the launcher's process
|
|
60
|
+
// group and dies on terminal hangup (SSH disconnect), because `nohup` only
|
|
61
|
+
// shields the launcher — Node resets SIG_IGN to SIG_DFL for itself, so the
|
|
62
|
+
// SIGHUP still reaches the Go binary. The directly-installed binary has no
|
|
63
|
+
// launcher layer, which is why only the npm install was affected.
|
|
64
|
+
it('detaches the server so a terminal hangup cannot kill it', () => {
|
|
65
|
+
expect(resolveSpawnOptions({}).detached).toBe(true)
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
it('passes the environment through to the server', () => {
|
|
69
|
+
const env = { PATH: '/usr/bin', CLAWBENCH_CHILD: '1' }
|
|
70
|
+
expect(resolveSpawnOptions(env).env).toEqual(env)
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
it('keeps stdio inherited so the server logs stay visible', () => {
|
|
74
|
+
expect(resolveSpawnOptions({}).stdio).toBe('inherit')
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
it('returns a fresh object so callers cannot mutate shared state', () => {
|
|
78
|
+
const first = resolveSpawnOptions({ A: '1' })
|
|
79
|
+
const second = resolveSpawnOptions({ A: '2' })
|
|
80
|
+
expect(first).not.toBe(second)
|
|
81
|
+
expect(first.env).not.toBe(second.env)
|
|
82
|
+
})
|
|
83
|
+
})
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xulongzhe/clawbench",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.97.0",
|
|
4
4
|
"description": "ClawBench — AI Workbench, United Across Devices. Go backend + Vue3 frontend, runs on PC, Android, and Termux",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -14,12 +14,12 @@
|
|
|
14
14
|
"postinstall": "node install.js"
|
|
15
15
|
},
|
|
16
16
|
"optionalDependencies": {
|
|
17
|
-
"@xulongzhe/clawbench-linux-x64": "0.
|
|
18
|
-
"@xulongzhe/clawbench-linux-arm64": "0.
|
|
19
|
-
"@xulongzhe/clawbench-android-arm64": "0.
|
|
20
|
-
"@xulongzhe/clawbench-darwin-x64": "0.
|
|
21
|
-
"@xulongzhe/clawbench-darwin-arm64": "0.
|
|
22
|
-
"@xulongzhe/clawbench-win32-x64": "0.
|
|
17
|
+
"@xulongzhe/clawbench-linux-x64": "0.97.0",
|
|
18
|
+
"@xulongzhe/clawbench-linux-arm64": "0.97.0",
|
|
19
|
+
"@xulongzhe/clawbench-android-arm64": "0.97.0",
|
|
20
|
+
"@xulongzhe/clawbench-darwin-x64": "0.97.0",
|
|
21
|
+
"@xulongzhe/clawbench-darwin-arm64": "0.97.0",
|
|
22
|
+
"@xulongzhe/clawbench-win32-x64": "0.97.0"
|
|
23
23
|
},
|
|
24
24
|
"engines": {
|
|
25
25
|
"node": ">=14"
|