rootrework 1.0.3 → 1.0.4
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/README.md +1 -1
- package/package.json +1 -1
- package/src/backend.mjs +18 -3
package/README.md
CHANGED
|
@@ -7,7 +7,7 @@ Run either command on your computer with Node.js 22.13 or later:
|
|
|
7
7
|
|
|
8
8
|
Both commands also start remote mode when `remote` is omitted. Complete the browser connection, then add rootRework in ChatGPT using `https://rootrework.com/mcp`, OAuth, and Dynamic Client Registration. Use the same browser for installation and ChatGPT authorization. No customer username, password, subscription activation, or device capability is required.
|
|
9
9
|
|
|
10
|
-
Check the live connection at `https://rootrework.com/verify`. Existing account credentials remain optional for recovering older installations. The `session` command opens the current installation's browser workspace when you change browsers or clear site data. Keep installation state private.
|
|
10
|
+
Check the live connection at `https://rootrework.com/verify`. In ChatGPT, select rootRework using its **Try in chat** control or the plugin picker for each chat where you want to use it. The host may require a plugin selection for a later request; this reuses the connected account without repeating authorization. Existing account credentials remain optional for recovering older installations. The `session` command opens the current installation's browser workspace when you change browsers or clear site data. Keep installation state private.
|
|
11
11
|
|
|
12
12
|
For a local MCP client, use command `npx` with arguments `-y`, `@rootenterprise/rootrework@latest`, `stdio`. Standard input and output carry MCP JSON messages; diagnostics use standard error. This local transport runs tools under the invoking operating-system user. OAuth DCR protects the public remote service.
|
|
13
13
|
|
package/package.json
CHANGED
package/src/backend.mjs
CHANGED
|
@@ -60,7 +60,7 @@ export function createBackend({ stateDir, packageRoot = moduleRoot, deviceId } =
|
|
|
60
60
|
stateDir = path.resolve(stateDir); packageRoot = path.resolve(packageRoot);
|
|
61
61
|
const tasksDir = path.join(stateDir, 'tasks'), requestsDir = path.join(stateDir, 'requests'), cursorsDir = path.join(stateDir, 'cursors');
|
|
62
62
|
const ready = Promise.all([privateDir(tasksDir), privateDir(requestsDir), privateDir(cursorsDir)]);
|
|
63
|
-
const locks = new Map();
|
|
63
|
+
const locks = new Map(), supervisors = new Map();
|
|
64
64
|
let closed = false, ptyAvailable = false;
|
|
65
65
|
try { createRequire(path.join(packageRoot, 'package.json'))('@lydell/node-pty'); ptyAvailable = true; } catch {}
|
|
66
66
|
const tools = schemas.filter(t => ptyAvailable || !t.name.startsWith('terminal_'));
|
|
@@ -154,7 +154,12 @@ export function createBackend({ stateDir, packageRoot = moduleRoot, deviceId } =
|
|
|
154
154
|
await atomic(launchFile, { launcher_pid: process.pid, launcher_identity: await processIdentity(process.pid), created_at: new Date().toISOString() });
|
|
155
155
|
const updateLaunch = values => withLock(launchFile, async () => atomic(launchFile, { ...await json(launchFile), ...values }));
|
|
156
156
|
child = spawn(process.execPath, [path.join(moduleRoot, 'src', 'supervisor.mjs'), dir], { detached: true, stdio: 'ignore', windowsHide: true, cwd: spec.cwd });
|
|
157
|
-
|
|
157
|
+
const exited = new Promise(resolve => {
|
|
158
|
+
child.once('exit', (code, signal) => { void updateLaunch({ exit_code: code, signal, exited_at: new Date().toISOString() }).catch(() => {}).finally(resolve); });
|
|
159
|
+
child.once('error', resolve);
|
|
160
|
+
});
|
|
161
|
+
supervisors.set(id, { child, exited });
|
|
162
|
+
void exited.then(() => supervisors.delete(id));
|
|
158
163
|
await new Promise((resolve, reject) => { child.once('spawn', resolve); child.once('error', reject); });
|
|
159
164
|
child.unref();
|
|
160
165
|
await updateLaunch({ supervisor_pid: child.pid, supervisor_identity: await processIdentity(child.pid), launched_at: new Date().toISOString() });
|
|
@@ -371,6 +376,16 @@ export function createBackend({ stateDir, packageRoot = moduleRoot, deviceId } =
|
|
|
371
376
|
if (name === 'terminal_resize') { const cols = integer(args.cols, undefined, 32767), rows = integer(args.rows, undefined, 32767); if (!cols || !rows) fail('INVALID_ARGUMENT', 'Terminal dimensions must be positive.'); return control(args, 'resize', { cols, rows }); }
|
|
372
377
|
if (name === 'terminal_interrupt') return control(args, 'interrupt');
|
|
373
378
|
},
|
|
374
|
-
async close() {
|
|
379
|
+
async close() {
|
|
380
|
+
closed = true; await ready;
|
|
381
|
+
await Promise.all([...supervisors].map(async ([id, { child, exited }]) => {
|
|
382
|
+
const state = await json(path.join(dirFor(id), 'state.json'));
|
|
383
|
+
if (finished.has(state.state)) {
|
|
384
|
+
child.ref();
|
|
385
|
+
try { await exited; } finally { child.unref(); }
|
|
386
|
+
}
|
|
387
|
+
}));
|
|
388
|
+
await Promise.allSettled(locks.values());
|
|
389
|
+
}
|
|
375
390
|
};
|
|
376
391
|
}
|