termcut 0.5.0 → 0.5.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "termcut",
3
- "version": "0.5.0",
3
+ "version": "0.5.1",
4
4
  "description": "Script terminal sessions in TypeScript, render them to reproducible MP4/GIF/WebM/SVG/HTML with Bun.",
5
5
  "license": "MIT",
6
6
  "author": "Aman Varshney",
@@ -56,7 +56,8 @@
56
56
  "dependencies": {
57
57
  "@wterm/core": "^0.3.4",
58
58
  "@wterm/dom": "^0.3.4",
59
- "@wterm/ghostty": "^0.3.4"
59
+ "@wterm/ghostty": "^0.3.4",
60
+ "@wterm/markdown": "^0.3.4"
60
61
  },
61
62
  "devDependencies": {
62
63
  "@types/bun": "latest"
package/src/live.ts CHANGED
@@ -98,7 +98,7 @@ export async function recordLive(config: ResolvedConfig, opts: LiveOptions = {})
98
98
  await Promise.race([exitedPromise, proc.exited]);
99
99
  push("m", MARKER.end);
100
100
  } finally {
101
- process.off("SIGWINCH", onResize);
101
+ (process as unknown as { off(event: string, fn: () => void): void }).off("SIGWINCH", onResize); // newer @types/bun drop the signal overload on off()
102
102
  if (stdin) {
103
103
  stdin.off("data", onData);
104
104
  if (isTTY) stdin.setRawMode(false);
package/src/recorder.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { MarkdownRenderer } from "@wterm/markdown";
1
2
  import { MARKER } from "./cast";
2
3
  import { WINDOW_BAR_HEIGHT, estimateCell } from "./config";
3
4
  import { formatMs, toMs } from "./duration";
@@ -269,6 +270,30 @@ export async function record(config: ResolvedConfig, script: Script, opts: Recor
269
270
  push("i", typeof data === "string" ? data : decoder.decode(data));
270
271
  };
271
272
 
273
+ /** Put text on screen as if the terminal had printed it: into the cast and the screen model, not the PTY. */
274
+ const inject = (data: string): void => {
275
+ push("o", data);
276
+ screen.write(data);
277
+ };
278
+
279
+ const renderMarkdown = (markdown: string): string => {
280
+ const renderer = new MarkdownRenderer({ width: Math.max(20, cols - 2) });
281
+ return renderer.push(markdown.endsWith("\n") ? markdown : markdown + "\n") + renderer.flush();
282
+ };
283
+
284
+ const print = async (markdown: string): Promise<void> => {
285
+ await screen.settle();
286
+ // Clear the prompt line, show the caption, then ask the shell for a fresh prompt on the next line.
287
+ inject(`\r\x1b[K${renderMarkdown(markdown)}`);
288
+ await raw("\r");
289
+ await waitFor(`prompt ${promptPattern} after print()`, promptVisible, config.waitTimeout);
290
+ };
291
+
292
+ const title = async (text: string, titleOpts: { pause?: Duration } = {}): Promise<void> => {
293
+ await print(`# ${text}\n\n---`);
294
+ await sleep(titleOpts.pause ?? "1.5s");
295
+ };
296
+
272
297
  const typingDelay = (base: number): number => {
273
298
  if (config.typingJitter === 0) return base;
274
299
  const factor = 1 + (rand() * 2 - 1) * config.typingJitter;
@@ -435,6 +460,8 @@ export async function record(config: ResolvedConfig, script: Script, opts: Recor
435
460
  await screen.settle();
436
461
  },
437
462
  clear: () => run("clear"),
463
+ print,
464
+ title,
438
465
  get browser(): BrowserSession {
439
466
  if (!browserSession) throw new Error("t.browser needs `browser: { url }` in the video config.");
440
467
  return browserSession;
package/src/types.ts CHANGED
@@ -278,6 +278,14 @@ export interface TerminalSession {
278
278
  resize(cols: number, rows: number): Promise<void>;
279
279
  /** Shorthand for `run("clear")`. */
280
280
  clear(): Promise<void>;
281
+ /**
282
+ * Show Markdown in the terminal as a caption (rendered to ANSI by @wterm/markdown). It is written into the
283
+ * recording and the screen model only, never sent to the shell; afterwards the shell is asked for a fresh prompt.
284
+ * Use at a shell prompt, not inside a full-screen program.
285
+ */
286
+ print(markdown: string): Promise<void>;
287
+ /** A title card: big heading + rule, then a pause (default "1.5s"). */
288
+ title(text: string, opts?: { pause?: Duration }): Promise<void>;
281
289
  /** The recorded browser window; throws if `browser` is not configured. */
282
290
  readonly browser: BrowserSession;
283
291
  /** Overlay layout: bring the terminal or the browser window to the front (recorded as a marker). */