@xandout/libra-harness 0.1.12 → 0.1.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.
Files changed (53) hide show
  1. package/dist/agent.d.ts.map +1 -1
  2. package/dist/agent.js +48 -11
  3. package/dist/agent.js.map +1 -1
  4. package/dist/extras/extensions/code-tools/extension.d.ts +83 -0
  5. package/dist/extras/extensions/code-tools/extension.d.ts.map +1 -0
  6. package/dist/extras/extensions/code-tools/extension.js +93 -0
  7. package/dist/extras/extensions/code-tools/extension.js.map +1 -0
  8. package/dist/extras/extensions/code-tools/extension.json +7 -0
  9. package/dist/extras/extensions/code-tools/extension.test.d.ts +2 -0
  10. package/dist/extras/extensions/code-tools/extension.test.d.ts.map +1 -0
  11. package/dist/extras/extensions/code-tools/extension.test.js +656 -0
  12. package/dist/extras/extensions/code-tools/extension.test.js.map +1 -0
  13. package/dist/extras/extensions/code-tools/index.d.ts +3 -0
  14. package/dist/extras/extensions/code-tools/index.d.ts.map +1 -0
  15. package/dist/extras/extensions/code-tools/index.js +2 -0
  16. package/dist/extras/extensions/code-tools/index.js.map +1 -0
  17. package/dist/extras/extensions/code-tools/tools/code-search.d.ts +12 -0
  18. package/dist/extras/extensions/code-tools/tools/code-search.d.ts.map +1 -0
  19. package/dist/extras/extensions/code-tools/tools/code-search.js +86 -0
  20. package/dist/extras/extensions/code-tools/tools/code-search.js.map +1 -0
  21. package/dist/extras/extensions/code-tools/tools/find.d.ts +3 -0
  22. package/dist/extras/extensions/code-tools/tools/find.d.ts.map +1 -0
  23. package/dist/extras/extensions/code-tools/tools/find.js +160 -0
  24. package/dist/extras/extensions/code-tools/tools/find.js.map +1 -0
  25. package/dist/extras/extensions/code-tools/tools/grep.d.ts +3 -0
  26. package/dist/extras/extensions/code-tools/tools/grep.d.ts.map +1 -0
  27. package/dist/extras/extensions/code-tools/tools/grep.js +306 -0
  28. package/dist/extras/extensions/code-tools/tools/grep.js.map +1 -0
  29. package/dist/extras/extensions/code-tools/tools/read.d.ts +3 -0
  30. package/dist/extras/extensions/code-tools/tools/read.d.ts.map +1 -0
  31. package/dist/extras/extensions/code-tools/tools/read.js +97 -0
  32. package/dist/extras/extensions/code-tools/tools/read.js.map +1 -0
  33. package/dist/extras/extensions/code-tools/tools/shared.d.ts +14 -0
  34. package/dist/extras/extensions/code-tools/tools/shared.d.ts.map +1 -0
  35. package/dist/extras/extensions/code-tools/tools/shared.js +53 -0
  36. package/dist/extras/extensions/code-tools/tools/shared.js.map +1 -0
  37. package/dist/extras/extensions/code-tools/tools/shell.d.ts +49 -0
  38. package/dist/extras/extensions/code-tools/tools/shell.d.ts.map +1 -0
  39. package/dist/extras/extensions/code-tools/tools/shell.js +623 -0
  40. package/dist/extras/extensions/code-tools/tools/shell.js.map +1 -0
  41. package/dist/extras/extensions/code-tools/tools/todo.d.ts +24 -0
  42. package/dist/extras/extensions/code-tools/tools/todo.d.ts.map +1 -0
  43. package/dist/extras/extensions/code-tools/tools/todo.js +131 -0
  44. package/dist/extras/extensions/code-tools/tools/todo.js.map +1 -0
  45. package/dist/extras/extensions/code-tools/tools/write.d.ts +4 -0
  46. package/dist/extras/extensions/code-tools/tools/write.d.ts.map +1 -0
  47. package/dist/extras/extensions/code-tools/tools/write.js +179 -0
  48. package/dist/extras/extensions/code-tools/tools/write.js.map +1 -0
  49. package/dist/extras/extensions/disk-session/extension.d.ts +5 -0
  50. package/dist/extras/extensions/disk-session/extension.d.ts.map +1 -1
  51. package/dist/extras/extensions/disk-session/extension.js +148 -20
  52. package/dist/extras/extensions/disk-session/extension.js.map +1 -1
  53. package/package.json +5 -1
@@ -0,0 +1,623 @@
1
+ import { spawn, execFileSync } from 'node:child_process';
2
+ import { existsSync, mkdirSync, readFileSync, writeFileSync, unlinkSync, appendFileSync, openSync, closeSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ import { makeToolName } from './shared.js';
5
+ export class ShellRegistry {
6
+ shells = new Map();
7
+ counter = 0;
8
+ shellsDir;
9
+ constructor(shellsDir) {
10
+ this.shellsDir = shellsDir ?? join(process.cwd(), '.libra-shells');
11
+ }
12
+ nextId() {
13
+ return `shell_${++this.counter}`;
14
+ }
15
+ metaPath(id) {
16
+ return join(this.shellsDir, `${id}.json`);
17
+ }
18
+ /**
19
+ * Create a foreground shell (pipes connected, parent waits).
20
+ * If background is true, the process is detached and output goes
21
+ * to a file. Metadata is persisted to disk so a future process
22
+ * can reconnect.
23
+ */
24
+ async create(command, cwd, env, background) {
25
+ const id = this.nextId();
26
+ const shellsDir = this.shellsDir;
27
+ if (background) {
28
+ // ── Detached: output to file, stdin from FIFO, survives parent exit ──
29
+ // stdout/stderr → output file (regular file, readable by any process).
30
+ // stdin ← FIFO (named pipe, writable by any future process).
31
+ // The process is detached (unref'd) so it survives parent exit.
32
+ //
33
+ // A wrapper shell command records the exit code to a file after
34
+ // the command finishes, so a future process can see whether it
35
+ // succeeded — without relying on the parent's event handlers.
36
+ mkdirSync(shellsDir, { recursive: true });
37
+ const outputFile = join(shellsDir, `${id}.output`);
38
+ const exitFile = join(shellsDir, `${id}.exit`);
39
+ const inputFifo = join(shellsDir, `${id}.in`);
40
+ const metaFile = this.metaPath(id);
41
+ // Create the output file so it exists even if the command produces no output.
42
+ writeFileSync(outputFile, '');
43
+ // Create the FIFO for stdin reattachment.
44
+ // mkfifo is POSIX — works on macOS and Linux.
45
+ // Use execFileSync so it's synchronous — we need the FIFO to
46
+ // exist before we spawn the command that reads from it.
47
+ try {
48
+ if (existsSync(inputFifo))
49
+ unlinkSync(inputFifo);
50
+ execFileSync('mkfifo', [inputFifo], { stdio: 'ignore' });
51
+ }
52
+ catch {
53
+ // If mkfifo fails, fall back to /dev/null for stdin.
54
+ // The shell will still run, but write_to_process won't work
55
+ // across sessions.
56
+ }
57
+ // Open file descriptors for stdout/stderr redirection.
58
+ const outFd = openSync(outputFile, 'a');
59
+ const errFd = outFd;
60
+ // Stdin: if the FIFO exists, use the `exec 3<>"$fifo"` trick.
61
+ // Opening a FIFO read-write doesn't block (the opener is both
62
+ // reader and writer), unlike opening read-only which blocks
63
+ // until a writer is present. The command then reads stdin
64
+ // from fd 3. This means:
65
+ // - Commands that don't read stdin (echo, ls) work fine — fd 3
66
+ // is open but they never read from it.
67
+ // - Commands that read stdin (cat, repl) block on read, not
68
+ // open — they wait for data on fd 3.
69
+ // - Any future process can write to the FIFO and the data
70
+ // appears on fd 3, reaching the command's stdin.
71
+ // - In-memory writes (same session) also go through the FIFO
72
+ // via write_to_process's FIFO path.
73
+ const fifoReady = existsSync(inputFifo);
74
+ const nullFd = openSync('/dev/null', 'r');
75
+ // Build the wrapper command.
76
+ // If FIFO exists: exec 3<>"$fifo"; command <&3; echo $? > exit
77
+ // If not: command < /dev/null; echo $? > exit
78
+ const fullCommand = fifoReady
79
+ ? `exec 3<>"${inputFifo}"; ${command} <&3; echo $? > "${exitFile}" 2>/dev/null`
80
+ : `${command} < /dev/null; echo $? > "${exitFile}" 2>/dev/null`;
81
+ const child = spawn(fullCommand, {
82
+ shell: true,
83
+ cwd,
84
+ env: { ...process.env, ...env },
85
+ stdio: [nullFd, outFd, errFd],
86
+ detached: true,
87
+ });
88
+ closeSync(outFd);
89
+ try {
90
+ closeSync(nullFd);
91
+ }
92
+ catch { }
93
+ const entry = {
94
+ id,
95
+ process: child,
96
+ pid: child.pid ?? -1,
97
+ output: '',
98
+ done: false,
99
+ exitCode: null,
100
+ startedAt: Date.now(),
101
+ command,
102
+ cwd,
103
+ outputFile,
104
+ inputFifo: existsSync(inputFifo) ? inputFifo : undefined,
105
+ detached: true,
106
+ readOffset: 0,
107
+ };
108
+ // While the parent is alive, track exit for in-memory queries.
109
+ child.on('exit', (code) => {
110
+ entry.done = true;
111
+ entry.exitCode = code;
112
+ });
113
+ child.on('error', (err) => {
114
+ try {
115
+ appendFileSync(outputFile, `\nError: ${err.message}\n`);
116
+ }
117
+ catch { }
118
+ entry.done = true;
119
+ entry.exitCode = -1;
120
+ });
121
+ child.unref();
122
+ const meta = {
123
+ id,
124
+ pid: child.pid ?? -1,
125
+ command,
126
+ cwd,
127
+ startedAt: entry.startedAt,
128
+ outputFile,
129
+ inputFifo: inputFifo,
130
+ };
131
+ try {
132
+ writeFileSync(metaFile, JSON.stringify(meta, null, 2));
133
+ }
134
+ catch { }
135
+ this.shells.set(id, entry);
136
+ return entry;
137
+ }
138
+ // ── Foreground: pipes connected, parent owns the process ──
139
+ const child = spawn(command, {
140
+ shell: true,
141
+ cwd,
142
+ env: { ...process.env, ...env },
143
+ stdio: ['pipe', 'pipe', 'pipe'],
144
+ });
145
+ const entry = {
146
+ id,
147
+ process: child,
148
+ pid: child.pid ?? -1,
149
+ output: '',
150
+ done: false,
151
+ exitCode: null,
152
+ startedAt: Date.now(),
153
+ command,
154
+ cwd,
155
+ detached: false,
156
+ };
157
+ child.stdout?.on('data', (data) => {
158
+ entry.output += data.toString();
159
+ });
160
+ child.stderr?.on('data', (data) => {
161
+ entry.output += data.toString();
162
+ });
163
+ child.on('exit', (code) => {
164
+ entry.done = true;
165
+ entry.exitCode = code;
166
+ });
167
+ child.on('error', (err) => {
168
+ entry.output += `\nError: ${err.message}\n`;
169
+ entry.done = true;
170
+ entry.exitCode = -1;
171
+ });
172
+ this.shells.set(id, entry);
173
+ return entry;
174
+ }
175
+ /**
176
+ * Get a shell by ID. If it's not in the in-memory map, try to
177
+ * reconnect from persisted metadata on disk.
178
+ */
179
+ get(id) {
180
+ const cached = this.shells.get(id);
181
+ if (cached)
182
+ return cached;
183
+ // Try to reconnect from disk.
184
+ const metaFile = this.metaPath(id);
185
+ if (!existsSync(metaFile))
186
+ return undefined;
187
+ try {
188
+ const meta = JSON.parse(readFileSync(metaFile, 'utf-8'));
189
+ const outputFile = meta.outputFile;
190
+ const exitFile = join(this.shellsDir, `${id}.exit`);
191
+ // Check if the process is still alive (signal 0 = probe).
192
+ let alive = false;
193
+ try {
194
+ process.kill(meta.pid, 0);
195
+ alive = true;
196
+ }
197
+ catch {
198
+ alive = false;
199
+ }
200
+ // Read accumulated output from file.
201
+ let output = '';
202
+ if (existsSync(outputFile)) {
203
+ output = readFileSync(outputFile, 'utf-8');
204
+ }
205
+ // Check if exit code was recorded.
206
+ let exitCode = null;
207
+ let done = false;
208
+ if (existsSync(exitFile)) {
209
+ exitCode = Number(readFileSync(exitFile, 'utf-8').trim());
210
+ done = true;
211
+ }
212
+ else if (!alive) {
213
+ // Process died without recording exit code.
214
+ done = true;
215
+ exitCode = -1;
216
+ }
217
+ const entry = {
218
+ id,
219
+ pid: meta.pid,
220
+ output,
221
+ done,
222
+ exitCode,
223
+ startedAt: meta.startedAt,
224
+ command: meta.command,
225
+ cwd: meta.cwd,
226
+ outputFile,
227
+ inputFifo: meta.inputFifo,
228
+ detached: true,
229
+ readOffset: output.length,
230
+ // No process handle — but we can write to the FIFO and kill by PID.
231
+ };
232
+ this.shells.set(id, entry);
233
+ return entry;
234
+ }
235
+ catch {
236
+ return undefined;
237
+ }
238
+ }
239
+ delete(id) {
240
+ const removed = this.shells.delete(id);
241
+ // Clean up disk artifacts for detached shells.
242
+ const metaFile = this.metaPath(id);
243
+ const outputFile = join(this.shellsDir, `${id}.output`);
244
+ const exitFile = join(this.shellsDir, `${id}.exit`);
245
+ const inputFifo = join(this.shellsDir, `${id}.in`);
246
+ for (const f of [metaFile, outputFile, exitFile, inputFifo]) {
247
+ try {
248
+ unlinkSync(f);
249
+ }
250
+ catch { }
251
+ }
252
+ return removed;
253
+ }
254
+ /** Kill all in-memory backgrounded shells. Called on extension close. */
255
+ close() {
256
+ for (const [id, entry] of this.shells) {
257
+ if (!entry.done && entry.process) {
258
+ try {
259
+ entry.process.kill('SIGKILL');
260
+ }
261
+ catch {
262
+ // already dead
263
+ }
264
+ }
265
+ // Detached shells survive — that's the point.
266
+ // Only clean up disk artifacts for non-detached shells.
267
+ if (!entry.detached) {
268
+ this.delete(id);
269
+ }
270
+ this.shells.delete(id);
271
+ }
272
+ }
273
+ }
274
+ // ── exec ─────────────────────────────────────────────────────────────
275
+ export const execTool = (cfg) => ({
276
+ name: makeToolName(cfg.toolPrefix, 'exec'),
277
+ description: 'Execute a shell command. By default, runs the command and waits for it to complete, ' +
278
+ 'returning stdout and stderr. Set timeout (ms) to limit execution time — if the command ' +
279
+ 'is still running when the timeout elapses, it is detached and backgrounded with a shell_id ' +
280
+ 'so you can retrieve output later with get_output. ' +
281
+ 'Set timeout to 0 to background immediately. ' +
282
+ 'Backgrounded shells are detached from the agent process and survive process exit — ' +
283
+ 'any future agent turn can observe output (get_output), send input (write_to_process), ' +
284
+ 'or kill (kill_shell) by shell_id. All backgrounded shells use a named pipe (FIFO) for ' +
285
+ 'stdin, so write_to_process works across sessions and process restarts. ' +
286
+ 'Prefer backgrounding (timeout=0) for any command that might run long, block on input, ' +
287
+ 'or need to survive across agent turns — this avoids blocking the agent and ensures ' +
288
+ 'the process can be adopted by any future turn. ' +
289
+ 'Commands run in the current working directory. Do not use this for file operations — ' +
290
+ 'use the dedicated file tools instead.',
291
+ parameters: {
292
+ type: 'object',
293
+ properties: {
294
+ command: {
295
+ type: 'string',
296
+ description: 'The shell command to execute.',
297
+ },
298
+ timeout: {
299
+ type: 'integer',
300
+ description: 'Timeout in milliseconds. Default: 30000 (30s). Set to 0 to background immediately.',
301
+ },
302
+ cwd: {
303
+ type: 'string',
304
+ description: 'Working directory for the command. Default: current working directory.',
305
+ },
306
+ env: {
307
+ type: 'object',
308
+ description: 'Additional environment variables (merged with process.env).',
309
+ },
310
+ },
311
+ required: ['command'],
312
+ },
313
+ async execute(args) {
314
+ const command = String(args.command ?? '');
315
+ if (!command) {
316
+ return { toolCallId: '', content: 'Error: command is required' };
317
+ }
318
+ const timeout = Number(args.timeout ?? 30000);
319
+ const cwd = String(args.cwd ?? process.cwd());
320
+ const extraEnv = (args.env ?? {});
321
+ // Background immediately — detach the process.
322
+ if (timeout === 0) {
323
+ const entry = await cfg.registry.create(command, cwd, extraEnv, true);
324
+ return {
325
+ toolCallId: '',
326
+ content: `Backgrounded: ${entry.id} (pid ${entry.pid})\nUse get_output with shell_id "${entry.id}" to read output, or kill_shell to terminate.`,
327
+ };
328
+ }
329
+ // Foreground — wait for completion or timeout.
330
+ const entry = await cfg.registry.create(command, cwd, extraEnv, false);
331
+ const elapsed = await new Promise((resolve) => {
332
+ const start = Date.now();
333
+ const check = setInterval(() => {
334
+ if (entry.done) {
335
+ clearInterval(check);
336
+ resolve(Date.now() - start);
337
+ }
338
+ else if (Date.now() - start >= timeout) {
339
+ clearInterval(check);
340
+ resolve(Date.now() - start);
341
+ }
342
+ }, 50);
343
+ });
344
+ if (entry.done) {
345
+ const output = entry.output || '(no output)';
346
+ const truncated = output.length > 50000
347
+ ? output.slice(0, 50000) + '\n[output truncated]'
348
+ : output;
349
+ cfg.registry.delete(entry.id);
350
+ return {
351
+ toolCallId: '',
352
+ content: `Exit code: ${entry.exitCode}\n${truncated}`,
353
+ };
354
+ }
355
+ // Timed out — re-spawn as detached so it survives.
356
+ // Kill the foreground process first.
357
+ try {
358
+ entry.process?.kill('SIGKILL');
359
+ }
360
+ catch { }
361
+ cfg.registry.delete(entry.id);
362
+ // Re-create as detached, capturing output from the start.
363
+ const bgEntry = await cfg.registry.create(command, cwd, extraEnv, true);
364
+ return {
365
+ toolCallId: '',
366
+ content: `Timed out after ${elapsed}ms. Detached and backgrounded as ${bgEntry.id} (pid ${bgEntry.pid}).\nUse get_output with shell_id "${bgEntry.id}" to read output, or kill_shell to terminate.`,
367
+ };
368
+ },
369
+ });
370
+ // ── get_output ───────────────────────────────────────────────────────
371
+ export const getOutputTool = (cfg) => ({
372
+ name: makeToolName(cfg.toolPrefix, 'get_output'),
373
+ description: 'Read output from a backgrounded shell process. Returns accumulated stdout and stderr. ' +
374
+ 'If the process has exited, includes the exit code and the shell is cleaned up. ' +
375
+ 'Works across sessions — if the shell was started in a previous invocation, it is ' +
376
+ 'reconnected from persisted metadata. Use the shell_id returned by exec. ' +
377
+ 'On first call, returns all output so far. On subsequent calls, returns only new output ' +
378
+ 'since the last read (incremental tailing).',
379
+ parameters: {
380
+ type: 'object',
381
+ properties: {
382
+ shell_id: {
383
+ type: 'string',
384
+ description: 'The shell ID returned by exec when the command was backgrounded.',
385
+ },
386
+ },
387
+ required: ['shell_id'],
388
+ },
389
+ async execute(args) {
390
+ const shellId = String(args.shell_id ?? '');
391
+ if (!shellId) {
392
+ return { toolCallId: '', content: 'Error: shell_id is required' };
393
+ }
394
+ // get() auto-reconnects from disk if the shell isn't in memory.
395
+ const entry = cfg.registry.get(shellId);
396
+ if (!entry) {
397
+ return { toolCallId: '', content: `Error: no shell with id "${shellId}"` };
398
+ }
399
+ // For detached shells, read from the output file.
400
+ // Use readOffset for incremental reads — first call returns all
401
+ // output so far, subsequent calls return only new bytes.
402
+ // When the process is done, always return all unread output.
403
+ let output = entry.output;
404
+ let isNew = false;
405
+ if (entry.detached && entry.outputFile && existsSync(entry.outputFile)) {
406
+ try {
407
+ const fullOutput = readFileSync(entry.outputFile, 'utf-8');
408
+ const offset = entry.readOffset ?? 0;
409
+ if (fullOutput.length > offset) {
410
+ // New output available — return only the new portion.
411
+ output = fullOutput.slice(offset);
412
+ entry.readOffset = fullOutput.length;
413
+ entry.output = fullOutput;
414
+ isNew = true;
415
+ }
416
+ else if (entry.done) {
417
+ // Process is done but no new output — return empty string
418
+ // (the exit message will be appended below).
419
+ output = '';
420
+ isNew = true;
421
+ }
422
+ else if (offset > 0) {
423
+ // No new output since last read.
424
+ output = '';
425
+ isNew = true;
426
+ }
427
+ else {
428
+ // First read — return everything.
429
+ output = fullOutput;
430
+ entry.readOffset = fullOutput.length;
431
+ entry.output = fullOutput;
432
+ isNew = true;
433
+ }
434
+ }
435
+ catch { }
436
+ }
437
+ const truncated = output.length > 50000
438
+ ? output.slice(0, 50000) + '\n[output truncated]'
439
+ : output;
440
+ if (entry.done) {
441
+ cfg.registry.delete(shellId);
442
+ return {
443
+ toolCallId: '',
444
+ content: `Process exited (code: ${entry.exitCode}).\n${truncated}`,
445
+ };
446
+ }
447
+ if (isNew && output === '') {
448
+ return {
449
+ toolCallId: '',
450
+ content: `Still running (pid ${entry.pid}). No new output since last read.`,
451
+ };
452
+ }
453
+ return {
454
+ toolCallId: '',
455
+ content: `Still running (pid ${entry.pid}).\n${truncated}`,
456
+ };
457
+ },
458
+ });
459
+ // ── kill_shell ───────────────────────────────────────────────────────
460
+ export const killShellTool = (cfg) => ({
461
+ name: makeToolName(cfg.toolPrefix, 'kill_shell'),
462
+ description: 'Kill a backgrounded shell process by its shell_id. Sends SIGKILL. ' +
463
+ 'Returns the final accumulated output. Works across sessions.',
464
+ parameters: {
465
+ type: 'object',
466
+ properties: {
467
+ shell_id: {
468
+ type: 'string',
469
+ description: 'The shell ID returned by exec.',
470
+ },
471
+ },
472
+ required: ['shell_id'],
473
+ },
474
+ async execute(args) {
475
+ const shellId = String(args.shell_id ?? '');
476
+ if (!shellId) {
477
+ return { toolCallId: '', content: 'Error: shell_id is required' };
478
+ }
479
+ const entry = cfg.registry.get(shellId);
480
+ if (!entry) {
481
+ return { toolCallId: '', content: `Error: no shell with id "${shellId}"` };
482
+ }
483
+ // Kill via PID (works for both in-memory and reconnected shells).
484
+ try {
485
+ process.kill(entry.pid, 'SIGKILL');
486
+ }
487
+ catch {
488
+ // already dead
489
+ }
490
+ // Give it a moment to flush output.
491
+ await new Promise((r) => setTimeout(r, 100));
492
+ // Re-read output file for detached shells.
493
+ let output = entry.output;
494
+ if (entry.detached && entry.outputFile && existsSync(entry.outputFile)) {
495
+ try {
496
+ output = readFileSync(entry.outputFile, 'utf-8');
497
+ }
498
+ catch { }
499
+ }
500
+ const truncated = output.length > 50000
501
+ ? output.slice(0, 50000) + '\n[output truncated]'
502
+ : output;
503
+ cfg.registry.delete(shellId);
504
+ return {
505
+ toolCallId: '',
506
+ content: `Killed ${shellId} (pid ${entry.pid}).\n${truncated}`,
507
+ };
508
+ },
509
+ });
510
+ // ── write_to_process ─────────────────────────────────────────────────
511
+ export const writeToProcessTool = (cfg) => ({
512
+ name: makeToolName(cfg.toolPrefix, 'write_to_process'),
513
+ description: 'Write input to the stdin of a backgrounded interactive shell process. ' +
514
+ 'Use this for shells running TUI programs, REPLs, or commands that wait for input. ' +
515
+ 'For a simple Enter keypress, send "\\n". ' +
516
+ 'Works across sessions — reconnected shells write to a named pipe (FIFO) ' +
517
+ 'that the detached process reads from.',
518
+ parameters: {
519
+ type: 'object',
520
+ properties: {
521
+ shell_id: {
522
+ type: 'string',
523
+ description: 'The shell ID returned by exec.',
524
+ },
525
+ input: {
526
+ type: 'string',
527
+ description: 'The text to write to the process stdin.',
528
+ },
529
+ },
530
+ required: ['shell_id', 'input'],
531
+ },
532
+ async execute(args) {
533
+ const shellId = String(args.shell_id ?? '');
534
+ const input = String(args.input ?? '');
535
+ if (!shellId) {
536
+ return { toolCallId: '', content: 'Error: shell_id is required' };
537
+ }
538
+ if (!input) {
539
+ return { toolCallId: '', content: 'Error: input is required' };
540
+ }
541
+ const entry = cfg.registry.get(shellId);
542
+ if (!entry) {
543
+ return { toolCallId: '', content: `Error: no shell with id "${shellId}"` };
544
+ }
545
+ if (entry.done) {
546
+ return { toolCallId: '', content: `Error: process ${shellId} has already exited` };
547
+ }
548
+ // For reconnected shells, check if the PID is still alive.
549
+ if (!entry.process) {
550
+ try {
551
+ process.kill(entry.pid, 0);
552
+ }
553
+ catch {
554
+ entry.done = true;
555
+ entry.exitCode = -1;
556
+ return { toolCallId: '', content: `Error: process ${shellId} has already exited` };
557
+ }
558
+ }
559
+ // Write to the FIFO. Both in-memory and reconnected shells read
560
+ // stdin from the FIFO (via the `exec 3<>"$fifo"` trick in the
561
+ // wrapper command). We use a subprocess to write so we don't
562
+ // block the event loop — opening a FIFO for writing blocks until
563
+ // a reader is present, and the detached shell is the reader.
564
+ if (entry.inputFifo && existsSync(entry.inputFifo)) {
565
+ const { spawn } = await import('node:child_process');
566
+ return new Promise((resolve) => {
567
+ // Use a heredoc to safely pass the input to printf, which
568
+ // writes to the FIFO. This handles special characters.
569
+ const writer = spawn('sh', ['-c', `printf %s "$1" >> "${entry.inputFifo}"`, 'write_to_process', input], { stdio: 'ignore' });
570
+ writer.on('exit', (code) => {
571
+ if (code === 0) {
572
+ resolve({
573
+ toolCallId: '',
574
+ content: `Wrote ${input.length} bytes to ${shellId}`,
575
+ });
576
+ }
577
+ else {
578
+ resolve({
579
+ toolCallId: '',
580
+ content: `Error writing to ${shellId}: exit code ${code}`,
581
+ isError: true,
582
+ });
583
+ }
584
+ });
585
+ writer.on('error', (err) => {
586
+ resolve({
587
+ toolCallId: '',
588
+ content: `Error writing to ${shellId}: ${err.message}`,
589
+ isError: true,
590
+ });
591
+ });
592
+ });
593
+ }
594
+ // No FIFO — fall back to in-memory pipe if available (legacy path
595
+ // for shells backgrounded before FIFO support, or if mkfifo failed).
596
+ if (entry.process && entry.process.stdin && !entry.process.stdin.destroyed) {
597
+ const stdin = entry.process.stdin;
598
+ return new Promise((resolve) => {
599
+ stdin.write(input, (err) => {
600
+ if (err) {
601
+ resolve({
602
+ toolCallId: '',
603
+ content: `Error writing to ${shellId}: ${err.message}`,
604
+ isError: true,
605
+ });
606
+ }
607
+ else {
608
+ resolve({
609
+ toolCallId: '',
610
+ content: `Wrote ${input.length} bytes to ${shellId}`,
611
+ });
612
+ }
613
+ });
614
+ });
615
+ }
616
+ return {
617
+ toolCallId: '',
618
+ content: `Error: shell ${shellId} has no writable stdin (no FIFO and no process handle)`,
619
+ isError: true,
620
+ };
621
+ },
622
+ });
623
+ //# sourceMappingURL=shell.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shell.js","sourceRoot":"","sources":["../../../../../src/extras/extensions/code-tools/tools/shell.ts"],"names":[],"mappings":"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"}