bellpull
Recipes

Subprocess results for --json and agents

Give a CLI's --json mode and an agent's event stream the same facts about a subprocess the terminal shows, from one bellpull Result.

A CLI that shells out usually prints something for a person and, under --json, builds a second report by hand — and the two drift. With bellpull the report is the result, rendered:

ship.mjs
import { format, run, toEvent, toJson } from 'bellpull';

import { install, runtimeWith } from './tools.mjs';

install();
const runtime = runtimeWith('bin');
const mode = process.argv[2] ?? 'human';

const result = await run('greet', ['1'], { runtime });
const steady = { ...result, duration: 0, executable: { path: 'bin/greet', from: 'bin' } }; // pinned for this page

if (mode === '--json') console.log(JSON.stringify(toJson(steady)));
else if (mode === '--events') console.log(JSON.stringify(toEvent(steady)));
else console.log(format(steady));
process.exitCode = result.ok ? 0 : 1;
node ship.mjs
failed  greet exited 1 after 0 ms
     bin/greet (from bin)
     hello from bin
node ship.mjs --events
{"type":"run","outcome":"failed","command":"greet","args":["1"],"code":1,"signal":null,"durationMs":0,"executable":"bin/greet","from":"bin"}

An agent branches on outcome — ok, failed, timedOut or signalled — rather than re-deriving it from code, signal and timedOut, and gets the binary that ran without asking a second question. The duration and paths are pinned above only so this page can be checked byte for byte; a real program passes result straight through.