/** * KHAELOR * File: prototypes/tui-spike/driver/debug-ink-input.tsx * Description: Diagnostic harness — traces stdin arrival vs Ink useInput delivery vs echo-frame * write time, to attribute candidate B's measured input latency (skew vs real stall). * * Author: Simon-Pierre Boucher * Contact: contact@spboucher.ai */ import fs from "node:fs"; import React, { useEffect, useReducer, useState } from "react"; import { Box, Static, Text, render, useApp, useInput } from "ink"; import { DemoModel } from "../shared/demo"; const log: string[] = []; const t0 = process.hrtime.bigint(); const ms = () => Number(process.hrtime.bigint() - t0) / 1e6; const model = new DemoModel(); process.stdin.on("data", (b: Buffer) => { log.push(`${ms().toFixed(1)} DATA ${JSON.stringify(b.toString("utf8"))}`); }); const origWrite = process.stdout.write.bind(process.stdout); let lastComposer = ""; (process.stdout as unknown as { write: unknown }).write = (chunk: unknown, ...rest: unknown[]) => { const s = typeof chunk === "string" ? chunk : Buffer.from(chunk as Uint8Array).toString("utf8"); if (lastComposer.length > 0 && s.includes("❯ " + lastComposer)) { log.push(`${ms().toFixed(1)} ECHO ${JSON.stringify(lastComposer.slice(-8))}`); lastComposer = ""; } return (origWrite as (c: unknown, ...r: unknown[]) => boolean)(chunk, ...rest); }; function App(): React.JSX.Element { const { exit } = useApp(); const [settled, setSettled] = useState<{ id: number; text: string }[]>([]); const [, force] = useReducer((x: number) => x + 1, 0); useEffect(() => { model.on("settled", (lines: string[]) => setSettled((s) => [...s, { id: s.length, text: lines.join("\n") }]), ); model.on("dirty", () => force()); const ticker = setInterval(() => { if (model.status !== null) force(); }, 100); model.start(); return () => clearInterval(ticker); }, []); useInput((input, key) => { log.push( `${ms().toFixed(1)} USEINPUT ${JSON.stringify(input)} esc=${key.escape} ret=${key.return}`, ); if (key.escape) { exit(); return; } if (key.return) { model.handleKey({ type: "enter" }); log.push(`${ms().toFixed(1)} ENTER composer_now=${JSON.stringify(model.composer)}`); return; } for (const ch of input) model.handleKey({ type: "char", ch }); lastComposer = model.composer; log.push(`${ms().toFixed(1)} COMPOSER ${JSON.stringify(model.composer.slice(-12))}`); }); const snap = model.snapshot(); const tail = snap.tail.length > 0 ? snap.tail.split("\n").slice(-12) : []; return ( <> {(i) => {i.text}} {tail.length > 0 && {tail.join("\n")}} {"❯ " + snap.composer} ); } const inst = render(, { exitOnCtrlC: true, patchConsole: false }); setTimeout(() => inst.unmount(), Number(process.env.DURATION_MS ?? 6000)).unref(); await inst.waitUntilExit(); model.stop(); fs.writeFileSync(process.env.DEBUG_OUT ?? "out/debug-ink.log", log.join("\n") + "\n"); process.exit(0);