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

The terminal's deploys screen lists an app's previews under production: one row per open pull with its state and address, Enter opening the pull #7485

Merged opened this

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

Merged

The terminal's deploys screen now shows a **Previews** group under production's deploys. It has one row per open pull that has a preview environment: `#N title · <state> · <address>`. The state uses the studio's own words and tone: `envPhrase` gives the word ("live", "not up", "starting", "serving · tests failed", …) and the new `envTone` in `runwords.ts` gives the tone. Pressing `j` past the last…

shipped production is serving it deploy 40e21c3

opened this

The terminal's deploys screen now shows a Previews group under production's deploys. It has one row per open pull that has a preview environment: #N title · <state> · <address>. The state uses the studio's own words and tone: envPhrase gives the word ("live", "not up", "starting", "serving · tests failed", …) and the new envTone in runwords.ts gives the tone. Pressing j past the last deploy moves the cursor into the previews, k from the first preview moves it back, and Enter or a click on a preview opens that pull's screen. An app with no previews draws No previews..

  • Data: the new appPreviews in src/actions/apps.ts reads the gated open pulls (openPulls, which applies the read and sealed-pull rules) and makes a single envsFor read, which is the same runtime status() the studio uses. It matches each pull to its pull-N environment and makes no read per row. It returns undefined when the viewer may not read the repository or the repository is not an app, so someone who can't see the app gets no group at all, not even No previews..
  • Screen: src/tui/screens/deploys.ts gives the previews their own list state and an inPreviews focus flag, so the deploy list's keys and the run-log Enter behave as before. The group shows up to 6 rows and scrolls past that. The existing "Open pulls" lines at the bottom are unchanged. The only key added is Enter on preview rows; the Enter hint reads "open the pull" while a preview is selected.
  • Not done: no redeploy or stop for a single preview, and no check word on these rows. The studio's writer actions belong to the separate key work in #7418 and #7465.
  • Test: test/tui-deploys-previews.test.ts stubs status() to give an app a running preview (#3), a failed one (#4) and an open pull with no preview (#5). It checks that each row reads live or not up with its address, that status() runs exactly once, and that j+Enter and j j+Enter open #4's and #3's pull screens. It also checks No previews. for an app without previews, and that a non-reader of a private repository sees no rows.

scripts/fast.ts named 1012 test files (about 88 minutes), so I ran the covering files instead: the new test plus tui-deploys, tui-deploy-act, tui-deploys-probe, tui-screens, tui-apps, tui-app-env and tui-runs-state. All 65 tests pass and tsc --noEmit is clean.

To try it: open an app repository in the terminal, go to Deploys, then press j past the deploys and Enter on a preview.

🤖 Generated with Claude Code

Closes #7475

commented

The terminal's deploys screen now shows a Previews group under production's deploys. It has one row per open pull that has a preview environment: #N title · <state> · <address>. The state uses the studio's own words and tone: envPhrase gives the word ("live", "not up", "starting", "serving · tests failed", …) and the new envTone in runwords.ts gives the tone. Pressing j past the last deploy moves the cursor into the previews, k from the first preview moves it back, and Enter or a click on a preview opens that pull's screen. An app with no previews draws No previews..

  • Data: the new appPreviews in src/actions/apps.ts reads the gated open pulls (openPulls, which applies the read and sealed-pull rules) and makes a single envsFor read, which is the same runtime status() the studio uses. It matches each pull to its pull-N environment and makes no read per row. It returns undefined when the viewer may not read the repository or the repository is not an app, so someone who can't see the app gets no group at all, not even No previews..
  • Screen: src/tui/screens/deploys.ts gives the previews their own list state and an inPreviews focus flag, so the deploy list's keys and the run-log Enter behave as before. The group shows up to 6 rows and scrolls past that. The existing "Open pulls" lines at the bottom are unchanged. The only key added is Enter on preview rows; the Enter hint reads "open the pull" while a preview is selected.
  • Not done: no redeploy or stop for a single preview, and no check word on these rows. The studio's writer actions belong to the separate key work in #7418 and #7465.
  • Test: test/tui-deploys-previews.test.ts stubs status() to give an app a running preview (#3), a failed one (#4) and an open pull with no preview (#5). It checks that each row reads live or not up with its address, that status() runs exactly once, and that j+Enter and j j+Enter open #4's and #3's pull screens. It also checks No previews. for an app without previews, and that a non-reader of a private repository sees no rows.

scripts/fast.ts named 1012 test files (about 88 minutes), so I ran the covering files instead: the new test plus tui-deploys, tui-deploy-act, tui-deploys-probe, tui-screens, tui-apps, tui-app-env and tui-runs-state. All 65 tests pass and tsc --noEmit is clean.

To try it: open an app repository in the terminal, go to Deploys, then press j past the deploys and Enter on a preview.

🤖 Generated with Claude Code

Changes requested — before the latest push

The Previews group is a sound design. It is gated by appPreviews and does one status() read. Its rows use the studio's words. The state-and-address row reads well. Changes needed, in one round:

  1. FIRST: the key logic in src/tui/screens/deploys.ts (key(), the j/k boundary between the deploy list and the previews) is new behaviour with no test that would fail without it. Every drive() in test/tui-deploys-previews.test.ts uses an app with zero runs, so j always lands in previews trivially. Add a test with at least two deploys that checks: (a) j on the last deploy moves into the previews and Enter then opens the pull, while Enter on a deploy still opens the run log; (b) k on the first preview returns to the last deploy; (c) the Enter hint reads "open the pull" only while a preview is selected.
  1. Add tests for more than PREVIEW_ROWS (6) previews: the group scrolls and the cursor stays in view. Also test the click path (hitList open on a preview row) and the tone of a failed row (envTone, which has no test).
  1. Direction: the repository's order is pipeline first (#6534, #6611, #5276, #3316, #6217, #6428, #1242, #1073), and this is a terminal feature. Name the issue it serves in the pull. It must not touch the pipeline-contended files; it does not.
  1. Terminal docs: say in the README or the terminal help text where the other deploys keys are described that the deploys screen has a Previews group and that Enter opens the pull. The only mention now is a code comment and the key hint.
  1. src/tui/screens/deploys.ts imports envPhrase from ../../web/ui.ts, so the terminal depends on a web module. Confirm that this is an existing pattern in src/tui. If it is not, move envPhrase to a shared module, or move it next to envTone in runwords.ts.

I did not find a security problem. Access is gated through requireReader and openPulls, the title is stripped of control characters, and the rows are terminal text.

commented

Closes #7475, under the P4 Forge in a link label. On the terminal's Deploys screen, a Previews group now sits under production's deploys. It has one row per open pull that has a preview environment: #N title · <state> · <address>. The state uses the studio's words and tone, from the single runtime status() read the studio's list makes (appPreviews in src/actions/apps.ts). The issue is a terminal feature, not one of the pipeline issues, and it touches none of the pipeline-contended files.

Moving around the screen (src/tui/screens/deploys.ts)

  • j on the last deploy moves the cursor into the previews, and k on the first preview moves it back to the last deploy.
  • Enter, or a second click, on a preview opens that pull's screen. Enter on a deploy still opens its run log.
  • One click on a preview selects it and moves the cursor into the previews; one click on a deploy moves it back.
  • The Enter hint reads "open the pull" only while a preview is selected.
  • The group shows 6 rows and scrolls so the selected row stays in view. An app with no previews draws No previews..
  • Someone who may not read the repository sees no Previews group at all, gated through requireReader and openPulls.
  • The only key added is Enter on the preview rows, so the keys #7418 and #7465 add to this screen are not affected.

envPhrase moved: it now lives in src/apps/env_phrase.ts as plain data, and src/web/ui.ts re-exports it, so web callers don't change. Terminal screens importing from src/web was already common (forges.ts imports timeAgo from web/ui.ts; dashboard.ts, workspace.ts and answers.ts import from web/studio). It moved anyway because web/ui.ts brings in HTML, icons and charts. envTone in runwords.ts takes the module's EnvPhraseTone and leaves the plain default tone neutral.

Tests (test/tui-deploys-previews.test.ts):

  • an app with two production deploys and one preview walks j/k across the boundary and checks the Enter hint at each step, then opens a run log from a deploy and the pull from the preview;
  • eight previews scroll, keeping the selected row on screen, and the last one opens;
  • a click selects a preview, a second click opens it;
  • previewRow and envTone give danger for a failed preview, success for a live one and no tone for a starting one.

A mutation check confirms the walk and click tests fail when the k boundary or the click focus is removed. The existing tests still cover the running and failed rows with their words, the single status() read, No previews. and the private repository.

Docs: docs/APPS.md, next to the other deploys keys (d, enter, r, p), now describes the Previews group, j/k into and out of it, and Enter opening the pull.

Checks run: bun x tsc --noEmit, bun scripts/design-lint.ts, and these test files, all passing: tui-deploys*, tui-deploy-act, web-ui, studio, studio-words, web-apps, apps. scripts/fast.ts named 1012 test files, so I ran the files that cover the change instead of the full suite.

🤖 Generated with Claude Code

Approved — before the latest push

Approved. I could not diff against f2b4cfeb69ee because the clone lacks that commit, so I read the whole change as it stands. I did not re-list my earlier asks. The tests now cover the things a reviewer would have asked for: keyboard entry and exit across the deploys/previews boundary, a click to select and a second click to open, scrolling past 6 rows, and tone mapping. The preview answers 200.

What I checked:

  • Access: appPreviews is gated by requireReader and openPulls, and returns undefined for a non-reader. The screen then draws no group at all, not even No previews.. A test covers the private-repo case.
  • Data: one status() read serves every row, and a test asserts it.
  • Names: envPhrase moved to plain data in src/apps/env_phrase.ts and is re-exported, so web callers do not change.
  • Terminal and docs: the keys work with no mouse, and docs/APPS.md describes them.
  • Design: no src/web markup changed, so the design system is not engaged.

Two things I would do next. Both are Non-blocking.

  1. Titles in previewRow are stripped of control characters. Move that strip into a shared helper, because pullLine does a similar thing.
  2. Add a per-preview redeploy or stop. This is already tracked in #7418 and #7465.

Declared and not an issue: scripts/fast.ts named 1012 files, so the covering files were run instead.

commented

Closes #7475. Under production's deploys, the terminal's Deploys screen now has a Previews group: one row per open pull that has a preview, as #N title · <state> · <address>. The state uses the studio's words and tone, and all rows come from the same single runtime status() read the studio's list makes (appPreviews in src/actions/apps.ts).

Using it (src/tui/screens/deploys.ts):

  • j on the last deploy moves the cursor into the previews, and k on the first preview moves it back.
  • Enter, or a second click, on a preview opens that pull's screen. Enter on a deploy still opens its run log.
  • A single click on either list moves the cursor into it.
  • The Enter hint reads "open the pull" only while a preview is selected.
  • The group shows 6 rows and scrolls to keep the selected row in view.
  • An app with no previews draws No previews.; someone who may not read the repository gets no group at all.

What to look at:

  • envPhrase moved. It now lives in src/apps/env_phrase.ts, and src/web/ui.ts re-exports it, so web callers are unchanged. envTone in src/tui/screens/runwords.ts maps its tone to the terminal's and leaves the plain default neutral.
  • Merge with main. The only conflict was the import block of deploys.ts, where #7434 added the members key m. Both sides are kept: the screen has the Previews group and m.
  • Docs. docs/APPS.md describes the group next to the screen's other keys.
  • Issue. This serves #7475 (P4 Forge in a link) and touches none of the files the pipeline issues contend for.

Tests: test/tui-deploys-previews.test.ts covers:

  • a running and a failed preview, read through exactly one status();
  • an app with no previews, and a non-reader of a private repository;
  • j/k across two deploys and a preview, with the Enter hint and both Enter outcomes checked;
  • eight previews that scroll, keeping the selected row on screen;
  • the click path, and the tone of a failed, a live and a starting preview.

The walk and click tests failed when the k boundary and the click focus were removed. After the merge, type-checking (tsc --noEmit) and design-lint pass, and the deploys, deploy-act, probe, previews and tui-appmembers tests pass (40 of 40). The full suite was not run here.

To try it: open an app repository in the terminal, press d, then j past the deploys and Enter on a preview.

🤖 Generated with Claude Code

Approved — before the latest push

Approved. The earlier head 214245ffbb54 is not in my clone and the API shows no prior review text, so I read the whole diff as it stands. I did not open the preview in a terminal; it answers 200 on /, and the Previews group is terminal-only.

  • Gate: appPreviews returns undefined unless the actor passes requireReader and the repo is an app. It lists through openPulls, so sealed pulls are filtered, and it makes one status() read for all rows. A non-reader sees no group, not even "No previews.". The tests cover this with a private repo and a second user.
  • Both doors: this is a read-only terminal view, so there is no write path to gate. docs/APPS.md documents j/k and Enter.
  • Design system: the only src/web change moves envPhrase into src/apps/env_phrase.ts and re-exports it from web/ui.ts, so there is no markup change.
  • Tests: they cover the rows, the single status() read, the empty state, the private repo, j/k across the boundary with the Enter hint, scrolling, click then click, and the tones. Each would fail without the change.

Next two things I would do:

  1. Non-blocking: add the preview check word and per-preview actions, already tracked in #7418 and #7465.
  2. Non-blocking: appPreviews caps open pulls at 50. Say so in the docs, or show a "+N more" row, so a 51st preview does not vanish silently.
commented

The terminal's Deploys screen now has a Previews group under production's deploys, with one row per open pull that has a preview: #N title · <state> · <address>. The state uses the studio's words and tone. All rows come from the one runtime status() read the studio's list already makes (appPreviews in src/actions/apps.ts), with no read per row.

How it works (src/tui/screens/deploys.ts):

  • j on the last deploy moves into the previews, and k on the first preview moves back.
  • Enter, or a second click, on a preview opens that pull's screen. Enter on a deploy still opens its run log.
  • A single click on either list moves the cursor into it, and the Enter hint reads "open the pull" only while a preview is selected.
  • The group shows 6 rows and scrolls to keep the selected row in view.
  • An app with no previews draws No previews., and someone who may not read the repository gets no group at all.

What to look at:

  • envPhrase moved to src/apps/env_phrase.ts, so the terminal no longer imports a web module. src/web/ui.ts re-exports it, so web callers are unchanged. envTone in src/tui/screens/runwords.ts maps it to the terminal's tones.
  • Merges with main. The screen keeps everything from both sides:

- the members key m from #7434; - the "Reached, not declared" egress lines from #7493, which sit in the head while previews have their own group below the deploys; - this Previews group.

  • Docs: docs/APPS.md describes the group next to the screen's other keys. This serves #7475 and touches none of the files the pipeline issues are working on.

Tests: test/tui-deploys-previews.test.ts covers:

  • a running and a failed preview, read through exactly one status();
  • an app with no previews, and a non-reader of a private repository;
  • j/k across two deploys and a preview, with the hint and both Enter outcomes;
  • eight previews scrolling;
  • the click path;
  • the tones of a failed, a live and a starting preview.

When the k boundary or the click focus was removed, the walk and click tests failed. After the latest merge, the type check (tsc --noEmit) and the design lint pass, and the deploys, deploy-act, probe, previews, egress and app-members terminal tests pass (43 of 43). I did not run the full suite here.

To try it: open an app repository in the terminal, press d, then j past the deploys and Enter on a preview.

🤖 Generated with Claude Code

Approved

Approved. The clone does not have 8f489085be06, so I could not diff against my last review. I read the whole change instead. I did not re-test the preview: it answers 200 on /, and I did not drive the terminal there.

  • Gating: appPreviews returns undefined unless the actor may read the repository, so a non-reader gets no group and no No previews. line. A test covers it.
  • Reads: one status() read serves every row, and a test asserts it.
  • Tests: each added behaviour has a test, covering the j/k boundary, scrolling, click select and open, tone, and the empty and private cases.
  • Web side: envPhrase moved to apps/env_phrase.ts and web/ui.ts re-exports it, so the web is unchanged and has no new markup or design-system exposure.
  • Docs: APPS.md describes the group and its keys.

Non-blocking: (1) the group takes only the 50 newest open pulls, and a dozen-plus previews past that would be silently missing. Say so in the docs or raise the cap. (2) The web studio and the terminal now share envPhrase, so a short test that web/ui.ts still re-exports the same function would guard that seam.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs