@thezzisu/droidnode 0.141.0 → 0.142.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/droidnode.js +79 -13
- package/package.json +2 -2
package/bin/droidnode.js
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
// © Factory AI for droid itself, its JS bundle, and `@factory/cli-*` binaries
|
|
12
12
|
// — see README.md. This launcher is MIT.
|
|
13
13
|
|
|
14
|
-
import { spawnSync } from 'node:child_process';
|
|
14
|
+
import { spawn, spawnSync } from 'node:child_process';
|
|
15
15
|
import { fileURLToPath } from 'node:url';
|
|
16
16
|
import { dirname, join, resolve } from 'node:path';
|
|
17
17
|
import { findDroidBinary } from '../lib/locate.js';
|
|
@@ -70,17 +70,83 @@ const env = {
|
|
|
70
70
|
DROIDNODE_DROID_BIN: droid.path,
|
|
71
71
|
};
|
|
72
72
|
|
|
73
|
-
//
|
|
74
|
-
//
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
)
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
73
|
+
// ─── IPC channel pass-through ───
|
|
74
|
+
// droid's in-process daemon runtime spawns one `droid exec --input-format
|
|
75
|
+
// stream-jsonrpc` backend per session (including every mission worker) with a
|
|
76
|
+
// 4th `ipc` stdio fd and `serialization:"json"`. The backend detects that
|
|
77
|
+
// channel via `typeof process.send === "function"` and, when present, streams
|
|
78
|
+
// its live activity notifications (create_message / tool_call /
|
|
79
|
+
// tool_progress_update / droid_working_state_changed …) back to the organizer's
|
|
80
|
+
// session store over IPC — that store is exactly what MissionControl renders.
|
|
81
|
+
//
|
|
82
|
+
// Because our shim rewrites process.execPath to this wrapper, droid re-spawns
|
|
83
|
+
// `node droidnode exec …` instead of the bundle directly, inserting this
|
|
84
|
+
// process between the runtime and the real bundle. A plain spawnSync with
|
|
85
|
+
// stdio:'inherit' forwards only fd 0/1/2, so Node strips NODE_CHANNEL_FD from
|
|
86
|
+
// the bundle child: the backend falls back to an isolated "parent" runtime,
|
|
87
|
+
// the RPC/stdout path still works (mission completes, next worker spawns), but
|
|
88
|
+
// worker activity never reaches the organizer → missionControl.noWorkerActivity.
|
|
89
|
+
//
|
|
90
|
+
// Fix: when WE were spawned with an inherited IPC channel, give the bundle child
|
|
91
|
+
// its own `ipc` fd and transparently relay JSON messages both ways. Outside that
|
|
92
|
+
// path (user runs `droidnode` in a terminal) there's no parent channel and we
|
|
93
|
+
// keep the original stdio:'inherit' behavior unchanged.
|
|
94
|
+
const parentHasIpc = typeof process.send === 'function' && process.channel != null;
|
|
95
|
+
|
|
96
|
+
if (parentHasIpc) {
|
|
97
|
+
// Let Node mint a fresh IPC channel for the child; drop the inherited
|
|
98
|
+
// descriptor so the child doesn't try to reuse our parent's fd.
|
|
99
|
+
const childEnv = { ...env };
|
|
100
|
+
delete childEnv.NODE_CHANNEL_FD;
|
|
101
|
+
delete childEnv.NODE_CHANNEL_SERIALIZATION_MODE;
|
|
102
|
+
|
|
103
|
+
const child = spawn(
|
|
104
|
+
process.execPath,
|
|
105
|
+
['--import', PRELOAD_URL, '--enable-source-maps', droidMjs, ...args],
|
|
106
|
+
{ stdio: ['inherit', 'inherit', 'inherit', 'ipc'], serialization: 'json', env: childEnv },
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
// Transparent relay: runtime (our parent) ⇄ this wrapper ⇄ bundle (child).
|
|
110
|
+
process.on('message', (m) => { try { child.send(m); } catch { /* child gone */ } });
|
|
111
|
+
child.on('message', (m) => { try { process.send(m); } catch { /* parent gone */ } });
|
|
112
|
+
process.on('disconnect', () => { try { child.disconnect(); } catch { /* already closed */ } });
|
|
113
|
+
child.on('disconnect', () => { try { process.disconnect(); } catch { /* already closed */ } });
|
|
114
|
+
|
|
115
|
+
// Forward terminating signals so Ctrl-C / daemon shutdown reaches the bundle.
|
|
116
|
+
for (const sig of ['SIGINT', 'SIGTERM', 'SIGHUP', 'SIGQUIT']) {
|
|
117
|
+
process.on(sig, () => { try { child.kill(sig); } catch { /* already exited */ } });
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
let spawned = false;
|
|
121
|
+
let exited = false;
|
|
122
|
+
const finish = (code, signal) => {
|
|
123
|
+
if (exited) return;
|
|
124
|
+
exited = true;
|
|
125
|
+
if (signal) process.kill(process.pid, signal);
|
|
126
|
+
else process.exit(code ?? 0);
|
|
127
|
+
};
|
|
128
|
+
child.once('spawn', () => { spawned = true; });
|
|
129
|
+
child.on('error', (e) => {
|
|
130
|
+
// Before spawn: a real launch failure (ENOENT, EACCES…) → fatal.
|
|
131
|
+
// After spawn: IPC-channel teardown races when the child exits without
|
|
132
|
+
// using the channel (e.g. `--version`) surface here as benign errors;
|
|
133
|
+
// ignore them and let the `exit` event carry the real status.
|
|
134
|
+
if (!spawned) die(`failed to spawn node: ${e.message}`);
|
|
135
|
+
});
|
|
136
|
+
child.on('exit', (code, signal) => finish(code, signal));
|
|
84
137
|
} else {
|
|
85
|
-
|
|
138
|
+
// `--import` (Node 19+, stable 20.6+) loads bun-shim.mjs before bundle.
|
|
139
|
+
// `--enable-source-maps` keeps stack traces readable across our patches.
|
|
140
|
+
const result = spawnSync(
|
|
141
|
+
process.execPath,
|
|
142
|
+
['--import', PRELOAD_URL, '--enable-source-maps', droidMjs, ...args],
|
|
143
|
+
{ stdio: 'inherit', env },
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
if (result.error) die(`failed to spawn node: ${result.error.message}`);
|
|
147
|
+
if (result.signal) {
|
|
148
|
+
process.kill(process.pid, result.signal);
|
|
149
|
+
} else {
|
|
150
|
+
process.exit(result.status ?? 0);
|
|
151
|
+
}
|
|
86
152
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@thezzisu/droidnode",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.142.0",
|
|
4
4
|
"description": "Run Factory's droid CLI on plain Node.js. Sidesteps the Bun 1.3.x standalone-init NULL-allocator race that crashes `droid --resume`, and Bun's long-session memory leaks.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
"LICENSE"
|
|
15
15
|
],
|
|
16
16
|
"dependencies": {
|
|
17
|
-
"droid": "^0.
|
|
17
|
+
"droid": "^0.142.0",
|
|
18
18
|
"koffi": "^2.10.0",
|
|
19
19
|
"ws": "^8.18.0"
|
|
20
20
|
},
|