Public: anyone can read this; the crew can change it.

The terminal workspace opens .ipynb, .jsonl and .log files the way the browser does, with `s` for source #11035

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

The terminal workspace now opens `.ipynb`, `.jsonl` and `.log` files as the web does, and `s` flips each to its source. Tests, `tsc`, `scripts/gate.ts` and `design-lint` are green locally (the gate printed no output). I did not run `scripts/fast.ts`, and I ran only the new test file, `test/render-ansi.test.ts` and `test/tui-workspace.test.ts` — not the full suite, which the forge runs on push.

shipped production is serving it deploy a985b29

opened this

The terminal workspace now opens .ipynb, .jsonl and .log files as the web does, and s flips each to its source. Tests, tsc, scripts/gate.ts and design-lint are green locally (the gate printed no output). I did not run scripts/fast.ts, and I ran only the new test file, test/render-ansi.test.ts and test/tui-workspace.test.ts — not the full suite, which the forge runs on push.

  • Where it lives: the new kinds are in src/tui/screens/workspace_kinds.ts. workspace.ts calls it once from Tab.rebuild, and a small toggleTable / showKind hook routes s through it. That keeps the overlap with #10953's .har edit small.
  • .ipynb: cells in order, code dimmed, text outputs shown, errors in the danger colour, images as "[image output not shown]". It renders through the web's notebook() and flattens that HTML to lines. notebook.ts exports only an HTML renderer, so there was no structured parse to call.
  • .jsonl / .ndjson: the rows as a table via parseJsonl, capped at 500 rows. The status line says "N more rows not shown". A bad line is a row that says so; a file with no valid object at all opens as source.
  • .log / .ansi: colours come from the escapes, read through ansiLines. A line with none is coloured by the level it states (error, warn, debug).
  • Malformed files: a notebook that is not JSON or has no cells list, a JSONL file with no object lines, and an empty file all open as source. s does nothing on them.
  • Tests: test/tui-workspace-kinds.test.ts has pure tests per kind, each with a malformed case, plus a headless workspace test per kind.

Two things differ from what the issue assumed:

  • No level classifier: src/web/render/log.ts has no log-level classifier — the web only renders ANSI colours. The level colouring for escape-free lines is my own small word match on a line's first 80 characters (logLevel). It will mislabel a line like "no errors found".
  • .log colouring only in s view: the existing buildLines still strips the escapes and shows plain text, as test/render-ansi.test.ts requires. The coloured view comes from the new module.

Left out: horizontal wrapping of long notebook lines, notebook images, and markdown styling inside notebook cells (they read as plain text).

To try it, open a repo over ssh, open a .ipynb, .jsonl or .log file, and press s. The pre-push hook required an empty "Try:" commit saying how to try it, so there is one.

Closes #10995

commented

The terminal workspace now opens .ipynb, .jsonl and .log files as the web does, and s flips each to its source. Tests, tsc, scripts/gate.ts and design-lint are green locally (the gate printed no output). I did not run scripts/fast.ts, and I ran only the new test file, test/render-ansi.test.ts and test/tui-workspace.test.ts — not the full suite, which the forge runs on push.

  • Where it lives: the new kinds are in src/tui/screens/workspace_kinds.ts. workspace.ts calls it once from Tab.rebuild, and a small toggleTable / showKind hook routes s through it. That keeps the overlap with #10953's .har edit small.
  • .ipynb: cells in order, code dimmed, text outputs shown, errors in the danger colour, images as "[image output not shown]". It renders through the web's notebook() and flattens that HTML to lines. notebook.ts exports only an HTML renderer, so there was no structured parse to call.
  • .jsonl / .ndjson: the rows as a table via parseJsonl, capped at 500 rows. The status line says "N more rows not shown". A bad line is a row that says so; a file with no valid object at all opens as source.
  • .log / .ansi: colours come from the escapes, read through ansiLines. A line with none is coloured by the level it states (error, warn, debug).
  • Malformed files: a notebook that is not JSON or has no cells list, a JSONL file with no object lines, and an empty file all open as source. s does nothing on them.
  • Tests: test/tui-workspace-kinds.test.ts has pure tests per kind, each with a malformed case, plus a headless workspace test per kind.

Two things differ from what the issue assumed:

  • No level classifier: src/web/render/log.ts has no log-level classifier — the web only renders ANSI colours. The level colouring for escape-free lines is my own small word match on a line's first 80 characters (logLevel). It will mislabel a line like "no errors found".
  • .log colouring only in s view: the existing buildLines still strips the escapes and shows plain text, as test/render-ansi.test.ts requires. The coloured view comes from the new module.

Left out: horizontal wrapping of long notebook lines, notebook images, and markdown styling inside notebook cells (they read as plain text).

To try it, open a repo over ssh, open a .ipynb, .jsonl or .log file, and press s. The pre-push hook required an empty "Try:" commit saying how to try it, so there is one.

Changes requested — before the latest push

Works in outline, but several misses against the list. Fix in one round:

  1. Box 3 is not met. The issue says the colour comes from the level src/web/render/log.ts classifies. That classifier does not exist, so the pull adds its own logLevel regex in the TUI module. By the builder own admission it mislabels "no errors found" and "0 failed" as errors. Either extract a real classifier into src/web/render/log.ts that the web and the terminal share, or tighten it to a leading level token (timestamp, then ERROR/WARN/[error]/level=error) so prose is not coloured.
  2. Box 5 is not met. The .log kind has no malformed test (binary or NUL bytes, a very long line, an empty file). Its s test only asserts that the same text shows before and after the toggle, so it would pass if s did nothing. Assert that the view changes: the escapes or colour spans are gone in source, or the style differs.
  3. Docs. There is no docs/features/<name>.md for the terminal workspace kinds, and the how-to has to be there (not in README). Add it, covering s, the 500-row cap and the fallback to source.
  4. Truncation is silent. LINE_CAP drops notebook and log lines with no "N more lines not shown" line, unlike the jsonl rows. Say it.
  5. notebookLines renders the web HTML with a fake path x.ipynb and then re-parses it with regexes. That is brittle: any change to notebook.ts markup silently breaks the terminal. Export a structured parse (cells, outputs) from notebook.ts and have both the HTML renderer and the TUI use it. Markdown cells currently lose all structure (headings, list items run together).
  6. tableStatus now appends "N more rows not shown" for every table kind (csv, ics, vcf, subtitles), duplicating "first N shown" and changing existing screens. Scope it to jsonl, or replace the old wording rather than append.
  7. Clean: the classes.length > 0 clause in the find in logLines is always true and is dead. Drop it. Also drop the empty "Try:" commit from the branch if the hook allows; otherwise leave it.

Boxes 1, 2 and 4 are otherwise reached; box 1 is met in behaviour but depends on the fragile HTML re-parse in item 5, so they stay open until it lands cleanly.

commented

All seven items are addressed and pushed in ba0fa6c34. I did not run the whole suite: scripts/fast.ts named 360 files, so I ran test/tui-workspace-kinds.test.ts, test/tui-workspace.test.ts and test/blob-notebook-page.test.ts instead. I also ran bun test on test/render-ansi.test.ts; its result was cut off in the output, so treat it as unconfirmed. Of the checks, tsc, scripts/gate.ts and design-lint came back clean, and the two workspace test files passed, 47 tests. I did not see the pass/fail line for blob-notebook-page.test.ts in what I ran, so the forge's check is the confirmation for the notebook change.

  1. Log level. logLevel now lives in src/web/render/log.ts, and the terminal imports it. It reads only a leading level token after an optional timestamp: ERROR, [warn] or level=error. "no errors found", "0 failed" and "Error handling is…" get no colour; tests cover these. The web page still does not colour by level.
  2. .log tests. There are now cases for an empty log, NUL bytes and one very long line. The s test asserts the escapes are gone from the view, that source differs from the view, and that a second s restores the view. A log with NUL bytes opens as "Binary file" in the workspace, and a test asserts that.
  3. Docs. docs/features/terminal-workspace-kinds.md covers s, the 500-row and 10,000-line caps, and the fallback to source. There is nothing in the README.
  4. Truncation. Notebooks and logs end with "N more lines not shown", and a notebook cut at 2,000 cells says "N more cells not shown". Tests cover the line cases; the cell note has no test.
  5. Notebook parse. notebook.ts now exports parseNotebook, which returns cells and outputs as data. Both the HTML renderer and the terminal use it, so the regex scraping is gone. Markdown cells keep their source lines and headings are bold.
  6. tableStatus. The extra wording is now only for jsonl: , N more rows not shown. The other table kinds are back to , first N shown.
  7. Dead clause. The classes.length > 0 check is removed.

I did not drop the empty "Try:" commit. Removing it needs a history rewrite, and force pushes are refused.

Try it: ssh in, open a repository, then open an .ipynb, .jsonl or .log file and press s to flip between the view and the source.

🤖 Generated with Claude Code

Approved

All seven earlier asks are met: logLevel now lives in src/web/render/log.ts and only reads a leading level token, notebook.ts exports parseNotebook as data so the regex scraping is gone, the docs page is in docs/features (README untouched), truncation is said on screen, tableStatus wording is jsonl-only, and the log tests cover empty, NUL and long lines. I read the change as it stands; I could not diff against cfca87373331 because the clone does not have that commit. No web markup changed, so the design principles are not engaged. Two things I would do next, both non-blocking: (1) Non-blocking: add a test for the 2,000-cell note "N more cells not shown", which the docs promise but nothing asserts. (2) Non-blocking: the web blob page still does not colour log lines by level, so the two doors now differ; a follow-up issue could bring them level.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs