MCPcopy Create free account
hub / github.com/UsefulSoftwareCo/executor / ptyTheater

Function ptyTheater

e2e/src/clients/chat-theater.ts:117–170  ·  view source on GitHub ↗
(
  cli: CliSurface,
  options: TheaterOptions,
  body: (theater: ChatTheater) => Effect.Effect<A, E, R>,
)

Source from the content-addressed store, hash-verified

115// ---------------------------------------------------------------------------
116
117const ptyTheater = <A, E, R>(
118 cli: CliSurface,
119 options: TheaterOptions,
120 body: (theater: ChatTheater) => Effect.Effect<A, E, R>,
121): Effect.Effect<A, E, R> =>
122 Effect.gen(function* () {
123 const runDir = dirname(options.record);
124 const queue: TheaterEvent[] = [];
125 let closed = false;
126 const push = (event: TheaterEvent) =>
127 Effect.sync(() => {
128 if (!closed) {
129 // Chatting IS focusing the terminal window.
130 if (event.type !== "done") markFocus(runDir, "terminal");
131 queue.push(event);
132 }
133 });
134
135 const pump = cli.session(
136 ["bun", RENDERER, options.title],
137 async (term) => {
138 // Don't type until the renderer has painted its header — before that
139 // it hasn't set raw mode yet, and the PTY would echo the event line
140 // into the recording.
141 await term.screen.waitForText(options.title, { timeoutMs: 30_000 });
142 // The cast's clock started with the PTY moments ago; anchor it for
143 // the run's focus timeline (scripts/film.ts cuts on these).
144 markRecordingStart(runDir, "terminal");
145 const deadline = Date.now() + 30 * 60 * 1000;
146 for (;;) {
147 const event = queue.shift();
148 if (event) {
149 await term.keyboard.type(encode(event));
150 if (event.type === "done") break;
151 continue;
152 }
153 if (Date.now() > deadline) break;
154 await sleep(40);
155 }
156 await term.screen.waitForText("session complete", { timeoutMs: 60_000 });
157 },
158 {
159 record: options.record,
160 viewport: options.viewport ?? { cols: 100, rows: 32 },
161 },
162 );
163 const pumpFiber = yield* Effect.forkChild(Effect.exit(pump));
164
165 const result = yield* Effect.exit(body(makeTheater(push)));
166 yield* push({ type: "done" });
167 closed = true;
168 yield* Fiber.join(pumpFiber);
169 return yield* result;
170 });
171
172// ---------------------------------------------------------------------------
173// Desk mode: renderer in a visible xterm on the virtual desktop; events over

Callers 1

withChatTheaterFunction · 0.85

Calls 5

markRecordingStartFunction · 0.90
encodeFunction · 0.85
makeTheaterFunction · 0.85
pushFunction · 0.85
sleepFunction · 0.70

Tested by

no test coverage detected