@xulongzhe/clawbench 0.99.1 → 0.100.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 CHANGED
@@ -35,9 +35,11 @@ if (process.env.CLAWBENCH_BINARY_PATH) {
35
35
  }
36
36
  }
37
37
 
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.
38
+ // detached: true (POSIX only — see resolveSpawnOptions) makes the server a
39
+ // session leader in its own process group, so a terminal hangup cannot reach
40
+ // it. Windows deliberately opts out: there detached means DETACHED_PROCESS,
41
+ // which strips the console and silently swallowed all server output. Signals
42
+ // are forwarded explicitly below, so Ctrl+C still stops it.
41
43
  const child = spawn(binPath, process.argv.slice(2), resolveSpawnOptions({ ...process.env }));
42
44
 
43
45
  // 转发信号到子进程
package/bin/platform.js CHANGED
@@ -44,10 +44,21 @@ export function resolveBinName(platform) {
44
44
  //
45
45
  // Signals are still forwarded explicitly by the launcher, so Ctrl+C and
46
46
  // `kill <launcher-pid>` keep stopping the server.
47
- export function resolveSpawnOptions(env) {
47
+ //
48
+ // Windows is excluded: there `detached` means DETACHED_PROCESS (libuv
49
+ // src/win/process.c), i.e. the child inherits no console, while `stdio:
50
+ // "inherit"` still hands it the launcher's console handles. The server writes
51
+ // everything through them (slog -> stderr, startup banner -> stdout), so its
52
+ // entire console output — including the auto-generated password banner — was
53
+ // silently discarded. Nothing about the SIGHUP rationale applies there, so
54
+ // Windows keeps the default non-detached spawn and the output stays visible.
55
+ // The cost is that libuv assigns the child to a job object
56
+ // (JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE), so closing the terminal window also
57
+ // stops the server; use the Windows service path for unattended runs.
58
+ export function resolveSpawnOptions(env, platform = process.platform) {
48
59
  return {
49
60
  stdio: "inherit",
50
61
  env,
51
- detached: true,
62
+ detached: platform !== "win32",
52
63
  };
53
64
  }
@@ -61,22 +61,39 @@ describe('resolveSpawnOptions', () => {
61
61
  // shields the launcher — Node resets SIG_IGN to SIG_DFL for itself, so the
62
62
  // SIGHUP still reaches the Go binary. The directly-installed binary has no
63
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)
64
+ it('detaches the server on POSIX so a terminal hangup cannot kill it', () => {
65
+ expect(resolveSpawnOptions({}, 'linux').detached).toBe(true)
66
+ expect(resolveSpawnOptions({}, 'darwin').detached).toBe(true)
67
+ expect(resolveSpawnOptions({}, 'android').detached).toBe(true)
68
+ })
69
+
70
+ // Regression guard: on Windows detached maps to DETACHED_PROCESS, which
71
+ // strips the child's console while `stdio: "inherit"` still passes the
72
+ // launcher's console handles. The server writes all of its console output
73
+ // (slog -> stderr, startup banner -> stdout) through those handles, so the
74
+ // combination silently discarded every line — including the first-run
75
+ // password banner. Windows must spawn without detached.
76
+ it('does not detach on Windows, where it would silently discard all output', () => {
77
+ expect(resolveSpawnOptions({}, 'win32').detached).toBe(false)
78
+ })
79
+
80
+ it('defaults to the running platform', () => {
81
+ expect(resolveSpawnOptions({}).detached).toBe(process.platform !== 'win32')
66
82
  })
67
83
 
68
84
  it('passes the environment through to the server', () => {
69
85
  const env = { PATH: '/usr/bin', CLAWBENCH_CHILD: '1' }
70
- expect(resolveSpawnOptions(env).env).toEqual(env)
86
+ expect(resolveSpawnOptions(env, 'linux').env).toEqual(env)
71
87
  })
72
88
 
73
89
  it('keeps stdio inherited so the server logs stay visible', () => {
74
- expect(resolveSpawnOptions({}).stdio).toBe('inherit')
90
+ expect(resolveSpawnOptions({}, 'linux').stdio).toBe('inherit')
91
+ expect(resolveSpawnOptions({}, 'win32').stdio).toBe('inherit')
75
92
  })
76
93
 
77
94
  it('returns a fresh object so callers cannot mutate shared state', () => {
78
- const first = resolveSpawnOptions({ A: '1' })
79
- const second = resolveSpawnOptions({ A: '2' })
95
+ const first = resolveSpawnOptions({ A: '1' }, 'linux')
96
+ const second = resolveSpawnOptions({ A: '2' }, 'linux')
80
97
  expect(first).not.toBe(second)
81
98
  expect(first.env).not.toBe(second.env)
82
99
  })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xulongzhe/clawbench",
3
- "version": "0.99.1",
3
+ "version": "0.100.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.99.1",
18
- "@xulongzhe/clawbench-linux-arm64": "0.99.1",
19
- "@xulongzhe/clawbench-android-arm64": "0.99.1",
20
- "@xulongzhe/clawbench-darwin-x64": "0.99.1",
21
- "@xulongzhe/clawbench-darwin-arm64": "0.99.1",
22
- "@xulongzhe/clawbench-win32-x64": "0.99.1"
17
+ "@xulongzhe/clawbench-linux-x64": "0.100.0",
18
+ "@xulongzhe/clawbench-linux-arm64": "0.100.0",
19
+ "@xulongzhe/clawbench-android-arm64": "0.100.0",
20
+ "@xulongzhe/clawbench-darwin-x64": "0.100.0",
21
+ "@xulongzhe/clawbench-darwin-arm64": "0.100.0",
22
+ "@xulongzhe/clawbench-win32-x64": "0.100.0"
23
23
  },
24
24
  "engines": {
25
25
  "node": ">=14"