@luckydraw/cumulus 1.0.12 → 1.0.14

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.
@@ -5,6 +5,8 @@ import { spawn } from 'child_process';
5
5
  const DEFAULT_TIMEOUT = 120_000; // 2 minutes
6
6
  const MAX_TIMEOUT = 600_000; // 10 minutes
7
7
  const MAX_OUTPUT = 100_000; // 100KB output cap
8
+ /** Grace period after `exit` for buffered output to arrive when `close` cannot fire. */
9
+ const EXIT_DRAIN_MS = 500;
8
10
  export const bashTool = {
9
11
  definition: {
10
12
  name: 'Bash',
@@ -32,23 +34,81 @@ export const bashTool = {
32
34
  return new Promise(resolve => {
33
35
  let stdout = '';
34
36
  let stderr = '';
35
- let killed = false;
37
+ let timedOut = false;
38
+ let outputCapped = false;
39
+ let settled = false;
40
+ let exitCode = null;
41
+ let drainTimer;
42
+ // `detached` makes the child a process-group leader, so signalling `-pid`
43
+ // reaches everything it spawned. Without it a timeout kills only `bash`
44
+ // and leaves its children running, orphaned, holding our stdout pipe.
36
45
  const proc = spawn('bash', ['-c', command], {
37
46
  cwd,
38
47
  env: { ...process.env, TERM: 'dumb' },
39
48
  stdio: ['ignore', 'pipe', 'pipe'],
49
+ detached: true,
40
50
  });
51
+ /** Signal the whole process group; the process may already be gone. */
52
+ const killTree = (signal) => {
53
+ if (proc.pid === undefined)
54
+ return;
55
+ try {
56
+ process.kill(-proc.pid, signal);
57
+ }
58
+ catch {
59
+ // Already exited, or the group is gone — nothing to do.
60
+ }
61
+ };
41
62
  const timer = setTimeout(() => {
42
- killed = true;
43
- proc.kill('SIGTERM');
44
- setTimeout(() => proc.kill('SIGKILL'), 5000);
63
+ timedOut = true;
64
+ killTree('SIGTERM');
65
+ setTimeout(() => killTree('SIGKILL'), 5000).unref();
45
66
  }, timeout);
67
+ /**
68
+ * Finalize. `viaClose` is false when the process exited but a surviving
69
+ * child still holds our stdout pipe — the case that used to hang forever.
70
+ */
71
+ const finish = (viaClose) => {
72
+ if (settled)
73
+ return;
74
+ settled = true;
75
+ clearTimeout(timer);
76
+ if (drainTimer)
77
+ clearTimeout(drainTimer);
78
+ let result = '';
79
+ if (stdout)
80
+ result += stdout;
81
+ if (stderr) {
82
+ if (result)
83
+ result += '\n';
84
+ result += `STDERR:\n${stderr}`;
85
+ }
86
+ if (timedOut) {
87
+ result +=
88
+ `\n\n[Command timed out after ${timeout}ms; its process group was killed. ` +
89
+ `For work that outlives a turn, use run_job instead.]`;
90
+ }
91
+ else if (outputCapped) {
92
+ result += `\n\n[Command killed after exceeding the ${MAX_OUTPUT}-byte output cap]`;
93
+ }
94
+ else if (exitCode !== 0 && exitCode !== null) {
95
+ result += `\nExit code: ${exitCode}`;
96
+ }
97
+ if (!viaClose) {
98
+ result +=
99
+ `\n\n[The command exited but left a background process holding its output stream, ` +
100
+ `so output may be incomplete and that process is still running. ` +
101
+ `Use run_job for work that should outlive the command.]`;
102
+ }
103
+ resolve(result || `(no output, exit code ${exitCode})`);
104
+ };
46
105
  proc.stdout.on('data', (data) => {
47
106
  stdout += data.toString();
48
107
  if (stdout.length > MAX_OUTPUT) {
49
108
  stdout = stdout.slice(0, MAX_OUTPUT) + '\n\n[Output truncated at 100KB]';
50
- killed = true;
51
- proc.kill('SIGTERM');
109
+ outputCapped = true;
110
+ killTree('SIGTERM');
111
+ setTimeout(() => killTree('SIGKILL'), 5000).unref();
52
112
  }
53
113
  });
54
114
  proc.stderr.on('data', (data) => {
@@ -57,26 +117,27 @@ export const bashTool = {
57
117
  stderr = stderr.slice(0, MAX_OUTPUT);
58
118
  }
59
119
  });
120
+ // `close` fires only once every stdio stream is closed, which a surviving
121
+ // grandchild can defer indefinitely. `exit` fires when the process itself
122
+ // ends, so it is the signal we actually depend on; `close` is preferred
123
+ // when it arrives because it guarantees the output is complete.
124
+ proc.on('exit', code => {
125
+ exitCode = code;
126
+ drainTimer = setTimeout(() => finish(false), EXIT_DRAIN_MS);
127
+ drainTimer.unref();
128
+ });
60
129
  proc.on('close', code => {
61
- clearTimeout(timer);
62
- let result = '';
63
- if (stdout)
64
- result += stdout;
65
- if (stderr) {
66
- if (result)
67
- result += '\n';
68
- result += `STDERR:\n${stderr}`;
69
- }
70
- if (killed) {
71
- result += `\n\n[Command timed out after ${timeout}ms]`;
72
- }
73
- else if (code !== 0 && code !== null) {
74
- result += `\nExit code: ${code}`;
75
- }
76
- resolve(result || `(no output, exit code ${code})`);
130
+ if (exitCode === null)
131
+ exitCode = code;
132
+ finish(true);
77
133
  });
78
134
  proc.on('error', err => {
135
+ if (settled)
136
+ return;
137
+ settled = true;
79
138
  clearTimeout(timer);
139
+ if (drainTimer)
140
+ clearTimeout(drainTimer);
80
141
  resolve(`Error executing command: ${err.message}`);
81
142
  });
82
143
  });
@@ -1 +1 @@
1
- {"version":3,"file":"bash.js","sourceRoot":"","sources":["../../../src/lib/tools/bash.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"bash.js","sourceRoot":"","sources":["../../../src/lib/tools/bash.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@luckydraw/cumulus",
3
- "version": "1.0.12",
3
+ "version": "1.0.14",
4
4
  "description": "RLM-based CLI chat wrapper for Claude with external history context management",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",