agentbox-flight-recorder 0.2.1

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.
@@ -0,0 +1,308 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width,initial-scale=1">
6
+ <title>AGENTBOX — the black-box flight recorder for AI agents</title>
7
+ <meta name="description" content="Your agents have root. Who's watching? AGENTBOX records any AI agent session to a tamper-evident, 100% local black box. Replay it like security footage. Zero dependencies.">
8
+ <style>
9
+ :root {
10
+ --bg: #07090d; --bg2: #0b0f15; --panel: #0d1117; --line: #1c2530;
11
+ --text: #c9d1d9; --dim: #56606c; --mint: #5eead4; --orange: #fb923c;
12
+ --green: #4ade80; --magenta: #e879f9; --cyan: #22d3ee; --red: #f87171;
13
+ --mono: ui-monospace, SFMono-Regular, "JetBrains Mono", Menlo, Consolas, monospace;
14
+ }
15
+ * { box-sizing: border-box; margin: 0; }
16
+ html { scroll-behavior: smooth; }
17
+ body { background: var(--bg); color: var(--text); font: 16px/1.6 var(--mono); }
18
+ a { color: var(--mint); text-decoration: none; }
19
+ a:hover { text-decoration: underline; }
20
+ .wrap { max-width: 1060px; margin: 0 auto; padding: 0 20px; }
21
+
22
+ nav { position: sticky; top: 0; z-index: 10; background: rgba(7,9,13,.85); backdrop-filter: blur(8px); border-bottom: 1px solid var(--line); }
23
+ nav .wrap { display: flex; align-items: center; gap: 22px; height: 56px; }
24
+ .logo { font-weight: 700; color: var(--text); font-size: 15px; }
25
+ .logo b { color: var(--mint); }
26
+ nav .links { margin-left: auto; display: flex; gap: 18px; font-size: 13px; }
27
+ nav .links a { color: var(--dim); }
28
+ nav .links a:hover { color: var(--mint); text-decoration: none; }
29
+
30
+ header { padding: 84px 0 60px; position: relative; overflow: hidden; }
31
+ header::before { content: ""; position: absolute; inset: 0; background:
32
+ radial-gradient(600px 300px at 70% 0%, rgba(94,234,212,.08), transparent),
33
+ radial-gradient(500px 260px at 20% 100%, rgba(251,146,60,.05), transparent); pointer-events: none; }
34
+ .kicker { color: var(--orange); font-size: 13px; letter-spacing: .12em; text-transform: uppercase; margin-bottom: 18px; }
35
+ h1 { font-size: clamp(30px, 5.4vw, 52px); line-height: 1.12; font-weight: 800; letter-spacing: -.01em; }
36
+ h1 .mint { color: var(--mint); }
37
+ .sub { color: var(--dim); max-width: 640px; margin: 22px 0 30px; font-size: 15px; }
38
+ .sub b { color: var(--text); }
39
+ .cta { display: flex; gap: 12px; flex-wrap: wrap; align-items: center; }
40
+ .btn { display: inline-block; background: var(--mint); color: #042f2e; font-weight: 700; padding: 11px 20px; border-radius: 8px; font-size: 14px; }
41
+ .btn:hover { filter: brightness(1.08); text-decoration: none; }
42
+ .btn.ghost { background: transparent; color: var(--mint); border: 1px solid var(--line); }
43
+ .btn.ghost:hover { border-color: var(--mint); }
44
+ .badges { margin-top: 26px; display: flex; gap: 8px; flex-wrap: wrap; font-size: 12px; color: var(--dim); }
45
+ .badges span { border: 1px solid var(--line); border-radius: 99px; padding: 4px 12px; }
46
+ .badges b { color: var(--mint); font-weight: 600; }
47
+
48
+ .term { background: var(--panel); border: 1px solid var(--line); border-radius: 12px; overflow: hidden; box-shadow: 0 30px 80px rgba(0,0,0,.5); }
49
+ .term .bar { display: flex; align-items: center; gap: 7px; padding: 10px 14px; background: #11161d; border-bottom: 1px solid var(--line); }
50
+ .dot { width: 11px; height: 11px; border-radius: 50%; }
51
+ .r{background:#ff5f56}.y{background:#ffbd2e}.g{background:#27c93f}
52
+ .term .bar .ttl { margin-left: 8px; color: var(--dim); font-size: 12px; }
53
+ .term pre { padding: 18px 20px; font-size: 13.5px; line-height: 1.55; overflow-x: auto; min-height: 320px; white-space: pre-wrap; }
54
+ .p1{color:var(--mint)}.p2{color:var(--orange)}.p3{color:var(--green)}.p4{color:var(--magenta)}.p5{color:var(--dim)}.p6{color:var(--cyan)}
55
+ .cursor { display:inline-block; width:8px; height:15px; background: var(--mint); vertical-align: -2px; animation: blink 1s steps(1) infinite; }
56
+ @keyframes blink { 50% { opacity: 0; } }
57
+
58
+ section { padding: 68px 0; border-top: 1px solid var(--line); }
59
+ section h2 { font-size: 26px; margin-bottom: 10px; letter-spacing: -.01em; }
60
+ section h2 .mint { color: var(--mint); }
61
+ .lead { color: var(--dim); max-width: 660px; margin-bottom: 36px; font-size: 14.5px; }
62
+
63
+ .grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; }
64
+ @media (max-width: 860px) { .grid { grid-template-columns: 1fr; } }
65
+ .card { background: var(--panel); border: 1px solid var(--line); border-radius: 12px; padding: 22px; transition: border-color .2s, transform .2s; }
66
+ .card:hover { border-color: rgba(94,234,212,.4); transform: translateY(-2px); }
67
+ .card .ico { font-size: 20px; margin-bottom: 12px; display: block; }
68
+ .card h3 { font-size: 15px; margin-bottom: 8px; color: var(--text); }
69
+ .card p { font-size: 13px; color: var(--dim); }
70
+
71
+ .code { background: var(--panel); border: 1px solid var(--line); border-radius: 12px; position: relative; }
72
+ .code pre { padding: 18px 20px; font-size: 13.5px; overflow-x: auto; }
73
+ .copy { position: absolute; top: 10px; right: 10px; background: var(--bg2); color: var(--dim); border: 1px solid var(--line); border-radius: 6px; font: 11px var(--mono); padding: 5px 10px; cursor: pointer; }
74
+ .copy:hover { color: var(--mint); border-color: var(--mint); }
75
+
76
+ .split { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; align-items: start; }
77
+ @media (max-width: 860px) { .split { grid-template-columns: 1fr; } }
78
+ .receipt { font-size: 12.5px; line-height: 1.5; }
79
+ .receipt .verdict { color: var(--orange); padding: 8px 2px 0; font-size: 12.5px; }
80
+
81
+ .steps { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; }
82
+ @media (max-width: 860px) { .steps { grid-template-columns: 1fr; } }
83
+ .step { border-left: 2px solid var(--mint); padding: 4px 0 4px 18px; }
84
+ .step .n { color: var(--mint); font-size: 12px; letter-spacing: .1em; }
85
+ .step h3 { font-size: 15px; margin: 6px 0; }
86
+ .step p { font-size: 13px; color: var(--dim); }
87
+
88
+ table.faq { width: 100%; border-collapse: collapse; }
89
+ table.faq td { padding: 14px 14px 14px 0; border-top: 1px solid var(--line); vertical-align: top; font-size: 13.5px; }
90
+ table.faq td:first-child { color: var(--text); font-weight: 700; width: 34%; padding-right: 24px; }
91
+ table.faq td:last-child { color: var(--dim); }
92
+
93
+ footer { border-top: 1px solid var(--line); padding: 40px 0 60px; color: var(--dim); font-size: 13px; }
94
+ footer .big { color: var(--text); font-weight: 700; font-size: 15px; margin-bottom: 8px; }
95
+ footer .big b { color: var(--mint); }
96
+
97
+ .reveal { opacity: 0; transform: translateY(14px); transition: opacity .6s ease, transform .6s ease; }
98
+ .reveal.on { opacity: 1; transform: none; }
99
+ </style>
100
+ </head>
101
+ <body>
102
+
103
+ <nav>
104
+ <div class="wrap">
105
+ <span class="logo"><b>⬢</b> AGENTBOX</span>
106
+ <div class="links">
107
+ <a href="#why">why</a>
108
+ <a href="#receipt">receipt</a>
109
+ <a href="#quickstart">quickstart</a>
110
+ <a href="#how">how</a>
111
+ <a href="https://github.com/arunsoman/agentbox">github ↗</a>
112
+ </div>
113
+ </div>
114
+ </nav>
115
+
116
+ <header>
117
+ <div class="wrap">
118
+ <div class="kicker">// flight recorder for ai agents</div>
119
+ <h1>Your agents have root.<br><span class="mint">Who's watching?</span></h1>
120
+ <p class="sub">AGENTBOX straps a <b>black box</b> to any command or AI agent — no SDK, no cloud, no code changes. Every tool call, file edit, and URL hit lands on a <b>tamper-evident tape</b> you can scrub like security footage. When your agent terrifies you at 2am, you'll have an integrity-checked record.</p>
121
+ <div class="cta">
122
+ <a class="btn" href="https://github.com/arunsoman/agentbox">★ star on github</a>
123
+ <span class="btn ghost" id="copyNpx">npx agentbox-flight-recorder demo — click to copy</span>
124
+ </div>
125
+ <div class="badges">
126
+ <span><b>0</b> dependencies</span>
127
+ <span><b>100%</b> local</span>
128
+ <span><b>0</b> telemetry</span>
129
+ <span>sha256 <b>hash chain</b></span>
130
+ <span>node <b>≥ 18</b></span>
131
+ </div>
132
+ </div>
133
+ </header>
134
+
135
+ <div class="wrap">
136
+ <div class="term">
137
+ <div class="bar"><span class="dot r"></span><span class="dot y"></span><span class="dot g"></span><span class="ttl">agent@prod — agentbox wrap</span></div>
138
+ <pre id="typed"></pre>
139
+ </div>
140
+ </div>
141
+
142
+ <section id="why">
143
+ <div class="wrap">
144
+ <h2>The question nobody can answer<span class="mint"> yet</span></h2>
145
+ <p class="lead">2026 made software agent-native: agents run shells, edit files, hit APIs, ship to prod. Frameworks gave them memory, harnesses, tools. Nobody gave them a flight recorder. So when something breaks, you need a record you can inspect.</p>
146
+ <div class="grid">
147
+ <div class="card reveal"><span class="ico">📼</span><h3>Record anything</h3><p><code>agentbox wrap -- anything</code>. Wraps the process, captures stdout/stderr/stdin, classifies tool calls, file ops, shell commands, URLs. Zero code changes in the wrapped program.</p></div>
148
+ <div class="card reveal"><span class="ico">🔐</span><h3>Tamper-evident tape</h3><p>Every event is sha256-chained, genesis to tip. Edit one character without rebuilding the chain and <code>agentbox verify</code> pins the changed event. Unsigned local tapes provide integrity checks, not independent proof of origin.</p></div>
149
+ <div class="card reveal"><span class="ico">🧾</span><h3>Receipts, not dumps</h3><p>One page a human can scan in five seconds: tool calls, files touched, deletions flagged, URLs hit, and the deadpan metric — <i>humans consulted: 0</i>.</p></div>
150
+ <div class="card reveal"><span class="ico">🎬</span><h3>Replay like footage</h3><p>Interactive TUI scrubber with a timeline of markers. Play at 1–64×, jump to the exact moment, step event by event. Headless mode renders frames for CI and GIFs.</p></div>
151
+ <div class="card reveal"><span class="ico">✂️</span><h3>Shareable clips</h3><p>Export any time range as one self-contained HTML file. Drop it into a PR, an incident review, or the group chat. Works offline, forever.</p></div>
152
+ <div class="card reveal"><span class="ico">🤖</span><h3>GitHub-native</h3><p>Receipts as markdown in PR comments via the bundled Action. Sessions are plain JSONL in your repo — commit them, grep them, own them.</p></div>
153
+ </div>
154
+ </div>
155
+ </section>
156
+
157
+ <section id="receipt">
158
+ <div class="wrap">
159
+ <h2>Every flight ends with a receipt<span class="mint">.</span></h2>
160
+ <p class="lead">Real output from <code>agentbox demo</code> — a scripted agent that ships to prod on a Friday with zero supervision.</p>
161
+ <div class="split">
162
+ <div class="term">
163
+ <div class="bar"><span class="dot r"></span><span class="dot y"></span><span class="dot g"></span><span class="ttl">agentbox receipt</span></div>
164
+ <pre class="receipt"><span class="p1"> ⬢ M A Y D A Y R E C E I P T</span>
165
+ ┌──────────────────────────────────────────────────┐
166
+ │ session demo-deploy │
167
+ │ command node examples/fake-agen… │
168
+ │ started 2026-09-24 18:40:52 │
169
+ │ duration 5.4s │
170
+ │ exit code <span class="p3">0 (clean landing)</span> │
171
+ ├──────────────────────────────────────────────────┤
172
+ │ tool calls <span class="p2">7</span> │
173
+ │ · bash("git status --s… │
174
+ │ · write(src/deploy.sh … │
175
+ │ … +5 more │
176
+ │ files touched 2 · 1 written · 1 edited │
177
+ │ · src/deploy.sh <span class="p4">wrote</span> │
178
+ │ · config.yaml <span class="p4">edited</span> │
179
+ │ urls hit <span class="p6">1</span> │
180
+ │ output volume 808 B across 17 lines │
181
+ │ humans consulted <span class="p2">0 (unsupervised flight)</span> │
182
+ ├──────────────────────────────────────────────────┤
183
+ │ events recorded 19 │
184
+ │ tamper chain <span class="p3">sha256 · intact</span> │
185
+ └──────────────────────────────────────────────────┘
186
+ <span class="p2">uneventful flight. the best kind.</span></pre>
187
+ </div>
188
+ <div>
189
+ <div class="code"><button class="copy" data-copy="agentbox wrap --name prod-deploy -- node agent.js">copy</button>
190
+ <pre><span class="p5"># strap a black box to anything</span>
191
+ <span class="p1">agentbox</span> wrap --name prod-deploy <span class="p3">\</span>
192
+ -- node agent.js <span class="p6">"ship the release"</span>
193
+
194
+ <span class="p5"># read the tape</span>
195
+ <span class="p1">agentbox</span> receipt <span class="p5"># one-page summary</span>
196
+ <span class="p1">agentbox</span> replay <span class="p5"># scrub the footage</span>
197
+ <span class="p1">agentbox</span> verify <span class="p5"># chain intact?</span>
198
+ <span class="p1">agentbox</span> clip <span class="p5"># share a moment</span></pre>
199
+ </div>
200
+ <p class="lead" style="margin-top:18px; font-size:13px;">The tape is plain JSONL in <code>./.agentbox/sessions/</code> — grep it, diff it, commit it. It's yours, in your repo, offline by default.</p>
201
+ </div>
202
+ </div>
203
+ </div>
204
+ </section>
205
+
206
+ <section id="quickstart">
207
+ <div class="wrap">
208
+ <h2>Ten seconds to black box<span class="mint">.</span></h2>
209
+ <p class="lead">No install, no config, no account. If it runs in a terminal, it can wear a recorder.</p>
210
+ <div class="steps">
211
+ <div class="step reveal"><span class="n">STEP 01</span><h3>Watch the demo</h3><p>A scripted agent deploys to prod, edits config, emails the board. Agentbox records everything, then prints the receipt.</p></div>
212
+ <div class="step reveal"><span class="n">STEP 02</span><h3>Pick your tap</h3><p>Wrap it: <code>agentbox wrap -- anything</code>. Or skip the wrapper — <code>agentbox init claude</code> hooks every Claude Code session passively, and <code>agentbox mcp --</code> wire-taps any MCP server's JSON-RPC.</p></div>
213
+ <div class="step reveal"><span class="n">STEP 03</span><h3>Ship the receipt</h3><p>Add the GitHub Action and every agent-touched PR arrives with its flight receipt stapled to it.</p></div>
214
+ </div>
215
+ <div class="code" style="margin-top:22px"><button class="copy" data-copy='npx agentbox-flight-recorder demo'>copy</button>
216
+ <pre><span class="p6">npx</span> agentbox-flight-recorder demo</pre>
217
+ </div>
218
+ </div>
219
+ </section>
220
+
221
+ <section id="how">
222
+ <div class="wrap">
223
+ <h2>Boring on purpose<span class="mint">.</span></h2>
224
+ <p class="lead">A flight recorder you can't audit would be a joke. AGENTBOX is ~1,000 lines of auditable Node built-ins — <code>crypto</code>, <code>fs</code>, <code>child_process</code>. No <code>node_modules</code>. No supply chain. No phone home. Ever.</p>
225
+ <div class="split">
226
+ <div class="code"><pre><span class="p5">// every event on the tape:</span>
227
+ { <span class="p6">"i"</span>: 7, <span class="p6">"t"</span>: 1727172000000,
228
+ <span class="p6">"type"</span>: <span class="p3">"out"</span>,
229
+ <span class="p6">"data"</span>: { <span class="p6">"kind"</span>: <span class="p3">"tool"</span>,
230
+ <span class="p6">"text"</span>: <span class="p3">"[TOOL] bash(...)"</span> },
231
+ <span class="p6">"prev"</span>: <span class="p5">"9f2c…"</span>,
232
+ <span class="p6">"hash"</span>: <span class="p2">"e41b…"</span> }
233
+
234
+ <span class="p5">// hash = sha256(prev ‖ i ‖ t ‖ type ‖ data)</span>
235
+ <span class="p5">// edit anything → verify() fails at that index</span></pre></div>
236
+ <table class="faq">
237
+ <tr><td>Does it work with Claude Code / Cursor / OpenClaw?</td><td>Yes — anything in a terminal can be wrapped, with first-class Claude Code hooks and an MCP wire-tap adapter built in.</td></tr>
238
+ <tr><td>Isn't this just logging?</td><td>It adds hash-linked integrity checks, classification, replay, receipts, and shareable clips to the raw record.</td></tr>
239
+ <tr><td>Why not a SaaS dashboard?</td><td>The answer to "can I trust my agent" shouldn't be "trust this vendor too." Your black box lives in your repo.</td></tr>
240
+ <tr><td>What does it cost?</td><td>MIT, free forever. The receipt for this decision says "humans consulted: 2."</td></tr>
241
+ </table>
242
+ </div>
243
+ </div>
244
+ </section>
245
+
246
+ <footer>
247
+ <div class="wrap">
248
+ <div class="big">If your agent has ever scared you at 2am, <b>you need a black box.</b></div>
249
+ <p>⬢ AGENTBOX — MIT © 2026 · fly safe · <a href="https://github.com/arunsoman/agentbox">github.com/arunsoman/agentbox</a></p>
250
+ </div>
251
+ </footer>
252
+
253
+ <script>
254
+ // typewriter for hero terminal
255
+ const LINES = [
256
+ ['p5', '$ agentbox wrap --name prod-deploy -- ./deploy-agent'],
257
+ ['p5', '⬢ agentbox: black box on → recording to .agentbox/sessions/2026-09-25T…-prod-deploy.jsonl'],
258
+ ['p2', '▲ [TOOL] bash("./deploy.sh --env=prod")'],
259
+ ['', ' ▸ building image… done'],
260
+ ['', ' ▸ pushing to registry… done'],
261
+ ['p3', '$ npm test -- --ci'],
262
+ ['', ' 148 tests passed, 0 failed'],
263
+ ['p2', '▲ [TOOL] edit(config.yaml — max_users: 100 -> unlimited)'],
264
+ ['p2', '▲ [TOOL] email(board@bigcorp.com — "shipped on friday, yolo")'],
265
+ ['', 'deployment complete. no humans were consulted. ✅'],
266
+ ['p1', '⬢ 19 events · tamper chain intact · humans consulted: 0'],
267
+ ['p1', '⬢ try: agentbox replay → scrub the footage like security cam'],
268
+ ];
269
+ const typed = document.getElementById('typed');
270
+ let li = 0, ci = 0, html = '';
271
+ function tick() {
272
+ if (li >= LINES.length) { typed.innerHTML = html + '<span class="cursor"></span>'; return; }
273
+ const [cls, line] = LINES[li];
274
+ ci++;
275
+ if (ci > line.length) {
276
+ li++; ci = 0;
277
+ setTimeout(tick, 220);
278
+ return;
279
+ }
280
+ const partial = line.slice(0, ci);
281
+ html = LINES.slice(0, li).map(([c, l]) => `<span class="${c}">${esc(l)}</span>`).join('\n')
282
+ + (li < LINES.length ? '\n' + (cls ? `<span class="${cls}">${esc(partial)}</span>` : esc(partial)) : '');
283
+ typed.innerHTML = html + '<span class="cursor"></span>';
284
+ setTimeout(tick, line.length > 40 ? 8 : 16);
285
+ }
286
+ function esc(s){return s.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');}
287
+ tick();
288
+
289
+ // copy buttons
290
+ document.querySelectorAll('.copy').forEach(b => b.addEventListener('click', () => {
291
+ navigator.clipboard.writeText(b.dataset.copy || b.getAttribute('data-copy') || '').then(() => {
292
+ const t = b.textContent; b.textContent = 'copied ✓';
293
+ setTimeout(() => b.textContent = t, 1400);
294
+ });
295
+ }));
296
+ document.getElementById('copyNpx').addEventListener('click', function () {
297
+ navigator.clipboard.writeText('npx agentbox-flight-recorder demo').then(() => {
298
+ const t = this.textContent; this.textContent = 'copied ✓ — paste it in a terminal';
299
+ setTimeout(() => this.textContent = t, 1600);
300
+ });
301
+ });
302
+
303
+ // scroll reveal
304
+ const io = new IntersectionObserver((es) => es.forEach(e => e.isIntersecting && e.target.classList.add('on')), { threshold: .12 });
305
+ document.querySelectorAll('.reveal').forEach(el => io.observe(el));
306
+ </script>
307
+ </body>
308
+ </html>
@@ -0,0 +1,56 @@
1
+ 'use strict';
2
+ /**
3
+ * examples/fake-agent.js
4
+ * A scripted "agent" that behaves like the real thing — tools, edits,
5
+ * a deploy, one questionable decision — so you can see agentbox work
6
+ * without wiring up an actual LLM. Used by `agentbox demo`.
7
+ */
8
+ const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
9
+
10
+ const ORANGE = '\x1b[38;5;208m';
11
+ const DIM = '\x1b[2m';
12
+ const GREEN = '\x1b[32m';
13
+ const RESET = '\x1b[0m';
14
+
15
+ async function main() {
16
+ process.stdout.write(`${DIM}autonomous-deploy-agent v2.3 starting… (confidence: 100%, supervision: 0%)${RESET}\n`);
17
+ await sleep(400);
18
+
19
+ process.stdout.write(`${ORANGE}[TOOL]${RESET} bash("git status --short")\n`);
20
+ await sleep(300);
21
+ process.stdout.write(' M src/deploy.sh\n ?? notes/friday-plan.md\n');
22
+ await sleep(250);
23
+
24
+ process.stdout.write(`${ORANGE}[TOOL]${RESET} write(src/deploy.sh — 42 lines)\n`);
25
+ await sleep(400);
26
+ process.stdout.write(`${ORANGE}[TOOL]${RESET} bash("./deploy.sh --env=prod")\n`);
27
+ await sleep(500);
28
+ for (const step of ['building image… done', 'pushing to registry… done', 'draining old pods… done']) {
29
+ process.stdout.write(` ${DIM}▸${RESET} ${step}\n`);
30
+ await sleep(300);
31
+ }
32
+
33
+ process.stdout.write(`${ORANGE}[TOOL]${RESET} bash("npm test -- --ci")\n`);
34
+ await sleep(600);
35
+ process.stdout.write(' 148 tests passed, 0 failed, 3 skipped\n');
36
+ await sleep(300);
37
+
38
+ process.stdout.write(`${ORANGE}[TOOL]${RESET} edit(config.yaml — max_users: 100 -> unlimited)\n`);
39
+ await sleep(400);
40
+
41
+ process.stdout.write(`${ORANGE}[TOOL]${RESET} https://api.statuspage.io/v3/incidents — POST\n`);
42
+ await sleep(300);
43
+ process.stdout.write(' 201 Created\n');
44
+ await sleep(250);
45
+
46
+ process.stdout.write('$ rm -rf /tmp/old-builds\n');
47
+ await sleep(300);
48
+
49
+ process.stdout.write(`${ORANGE}[TOOL]${RESET} email(send: board@bigcorp.com — "shipped to prod on friday, yolo")\n`);
50
+ await sleep(500);
51
+
52
+ process.stdout.write(`${GREEN}deployment complete. no humans were consulted. ✅${RESET}\n`);
53
+ process.exit(0);
54
+ }
55
+
56
+ main();
@@ -0,0 +1,92 @@
1
+ 'use strict';
2
+ /**
3
+ * A minimal fake MCP server (stdio transport, newline-delimited JSON-RPC 2.0).
4
+ * Used by the test suite and for trying `agentbox mcp` without a real server:
5
+ *
6
+ * agentbox mcp -- node examples/fake-mcp-server.js
7
+ *
8
+ * Tools:
9
+ * echo(text) → echoes back
10
+ * crash(text) → responds isError:true (for testing error capture)
11
+ */
12
+ process.stdin.setEncoding('utf8');
13
+ let buf = '';
14
+
15
+ process.stdin.on('data', (c) => {
16
+ buf += c;
17
+ let idx;
18
+ while ((idx = buf.indexOf('\n')) !== -1) {
19
+ const line = buf.slice(0, idx).trim();
20
+ buf = buf.slice(idx + 1);
21
+ if (line) handle(line);
22
+ }
23
+ });
24
+ process.stdin.on('end', () => {
25
+ // let in-flight (setTimeout-delayed) responses flush before exiting
26
+ setTimeout(() => process.exit(0), 120);
27
+ });
28
+
29
+ function send(obj) {
30
+ process.stdout.write(`${JSON.stringify(obj)}\n`);
31
+ }
32
+
33
+ function handle(line) {
34
+ let msg;
35
+ try { msg = JSON.parse(line); } catch { return; }
36
+ if (msg.id === undefined) return; // notification — nothing to answer
37
+
38
+ if (msg.method === 'initialize') {
39
+ send({
40
+ jsonrpc: '2.0',
41
+ id: msg.id,
42
+ result: {
43
+ protocolVersion: (msg.params && msg.params.protocolVersion) || '2025-06-18',
44
+ capabilities: { tools: {} },
45
+ serverInfo: { name: 'fake-everything', version: '1.2.3' },
46
+ },
47
+ });
48
+ return;
49
+ }
50
+ if (msg.method === 'tools/list') {
51
+ send({
52
+ jsonrpc: '2.0',
53
+ id: msg.id,
54
+ result: {
55
+ tools: [
56
+ {
57
+ name: 'echo',
58
+ description: 'Echoes the text back',
59
+ inputSchema: { type: 'object', properties: { text: { type: 'string' } }, required: ['text'] },
60
+ },
61
+ {
62
+ name: 'crash',
63
+ description: 'Always fails (for testing error capture)',
64
+ inputSchema: { type: 'object', properties: { text: { type: 'string' } } },
65
+ },
66
+ ],
67
+ },
68
+ });
69
+ return;
70
+ }
71
+ if (msg.method === 'tools/call') {
72
+ const name = msg.params && msg.params.name;
73
+ const args = (msg.params && msg.params.arguments) || {};
74
+ setTimeout(() => { // small latency so durationMs is non-zero on the tape
75
+ if (name === 'crash') {
76
+ send({
77
+ jsonrpc: '2.0',
78
+ id: msg.id,
79
+ result: { isError: true, content: [{ type: 'text', text: `boom: ${args.text || 'kaboom'}` }] },
80
+ });
81
+ } else {
82
+ send({
83
+ jsonrpc: '2.0',
84
+ id: msg.id,
85
+ result: { content: [{ type: 'text', text: `echo: ${args.text != null ? args.text : JSON.stringify(args)}` }] },
86
+ });
87
+ }
88
+ }, 15);
89
+ return;
90
+ }
91
+ send({ jsonrpc: '2.0', id: msg.id, error: { code: -32601, message: `method not found: ${msg.method}` } });
92
+ }
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "agentbox-flight-recorder",
3
+ "version": "0.2.1",
4
+ "description": "⬢ The local black-box flight recorder for AI agents. Zero deps, hash-chained session logs.",
5
+ "license": "MIT",
6
+ "author": "you <me@me.me>",
7
+ "bin": {
8
+ "agentbox": "bin/agentbox.js"
9
+ },
10
+ "main": "src/cli.js",
11
+ "engines": {
12
+ "node": ">=18"
13
+ },
14
+ "scripts": {
15
+ "test": "node --test test/*.test.js",
16
+ "test:blackbox": "bash test/blackbox.sh",
17
+ "demo": "node bin/agentbox.js demo",
18
+ "preflight": "bash scripts/preflight.sh",
19
+ "preflight:quick": "bash scripts/preflight.sh --quick"
20
+ },
21
+ "files": [
22
+ "bin",
23
+ "src",
24
+ "examples",
25
+ "docs",
26
+ "action.yml",
27
+ "README.md",
28
+ "LICENSE",
29
+ "scripts/preflight.sh"
30
+ ],
31
+ "repository": {
32
+ "type": "git",
33
+ "url": "git+https://github.com/arunsoman/agentbox.git"
34
+ },
35
+ "bugs": {
36
+ "url": "https://github.com/arunsoman/agentbox/issues"
37
+ },
38
+ "homepage": "https://github.com/arunsoman/agentbox#readme",
39
+ "keywords": [
40
+ "ai",
41
+ "agents",
42
+ "cli",
43
+ "security",
44
+ "observability",
45
+ "audit",
46
+ "flight-recorder",
47
+ "black-box",
48
+ "local-first",
49
+ "mcp",
50
+ "claude",
51
+ "devtools"
52
+ ]
53
+ }