Skip to content

feat(cost): clickable PR link in the cost tables - #493

Merged
ralyodio merged 1 commit into
mainfrom
worktree-cost-pr-links
Sep 6, 2026
Merged

feat(cost): clickable PR link in the cost tables#493
ralyodio merged 1 commit into
mainfrom
worktree-cost-pr-links

Conversation

@ralyodio

@ralyodio ralyodio commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Adds a pr column to moshcode cost and moshcode cost --all. The cell reads view #128 and is an OSC 8 hyperlink — click it and the pull request opens in your browser.

The cost table is where you notice a session that cost $300, and the next thing you want is the thing it produced, which lives on GitHub rather than on this machine. Claude Code already writes a pr-link record when a session opens a PR; nothing was reading it.

  session  engine  model          in    out  cache   cost    age  pr
  api      claude  claude-opus-5  1.2k  27k  10.5M   $9.91~  42m  view #128
  audit    codex   gpt-5.6-sol    400   200  600     —       12m  —

Why a hyperlink rather than a URL column

The label is arbitrary text; only the target has to be a URL. So the column stays four characters wide while the click target is the full sixty-character GitHub URL.

OSC 8 is not universal and cannot be feature-detected, so there are two ways back to the plain form:

  • piped output prints the raw URL (nothing reading a pipe wants escapes)
  • MOSHCODE_HYPERLINKS=0 forces it in a terminal that would otherwise paint a view nobody can click

moshcode cost --json always carries pr and prs in full.

ui.mjs had to learn about hyperlinks

strip only matched SGR sequences, so a cell with a URL hidden inside it would have measured sixty columns wide and pushed the whole table apart. clip now copies an OSC 8 wrapper whole and closes one it cut into — the same care it already took with colour, and for the same reason: a terminal handed an opener with no closer keeps linking everything printed afterwards.

What is deliberately not here

ps does not get the column. It runs in 0.22s today; the transcript scan the PR comes from takes 1.75s. That is a 9x regression on the command people run constantly, for a column that is empty while the work is still in progress. The per-session moshcode cost table shows the same sessions and already pays for the scan.

Safety

Only https://host/path URLs are accepted. The string ends up in an escape sequence handed to the users browser, and a transcript is a file on disk that other tools write to — javascript:, file:// and plain http:// are dropped rather than shown as a dead link.

Tests

11 new tests, full suite green (2894 tests, 0 failures):

  • link wraps in OSC 8, measures as its label, and lines up in a table
  • clip closes a hyperlink it cut into
  • both fallbacks (piped, and MOSHCODE_HYPERLINKS=0)
  • a pr-link outside the cost window still belongs to the run — a session that ran overnight opened its PR yesterday
  • newest PR wins when a session opened two
  • unusable URLs are dropped, not rendered

🤖 Generated with Claude Code

https://claude.ai/code/session_01Cbtunz1LzTra3EEJNK1cHN

The cost table is where you notice a session that cost $300, and the next
thing you want is the thing it produced — which is on GitHub, not on this
machine. Claude Code already writes a `pr-link` record when a session opens
a pull request; nothing was reading it.

Adds a `pr` column to both `moshcode cost` and `moshcode cost --all`,
rendered as an OSC 8 hyperlink: the label reads "view #128" at four columns
wide while the click target is the full URL, so the column costs almost
nothing to carry. `--json` carries `pr` and `prs` in full.

OSC 8 is not universal and cannot be feature-detected, so piped output falls
back to the raw URL and `MOSHCODE_HYPERLINKS=0` forces that same plain form
in a terminal that would otherwise paint a "view" nobody can click.

ui.mjs had to learn about hyperlinks to make this line up: `strip` only
matched SGR, so a cell measured with a URL inside it would have sized its
column to sixty characters and pushed the table apart. `clip` now copies an
OSC 8 wrapper whole and closes one it cut into, the same care it already
took with colour.

`ps` deliberately does not get this column. It runs in 0.22s; the transcript
scan the PR comes from takes 1.75s, and that is a bad trade for a column
that is empty while the work is still in progress.

Only github.com-shaped https URLs are accepted — the string ends up in an
escape sequence handed to the user's browser, and a transcript is a file on
disk that other tools write to.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Cbtunz1LzTra3EEJNK1cHN
@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown

ThreatCrush Security Scan

0 finding(s) in the 6 file(s) this pull request changes.

Nothing in the files this pull request changes.

92 pre-existing finding(s) elsewhere in the repository — **HIGH/CRITICAL**: 8 | **MEDIUM**: 74 | **LOW**: 10

Not introduced by this pull request. The full set is in the Security tab.

Severity Rule Location
HIGH js-ssrf-outbound-request apps/pwa/public/sw.js:45
HIGH tls-verification-disabled apps/pwa/src/lib/moshpit-gateway.mjs:299
HIGH sh-remote-script-execution install.sh:86
HIGH sh-remote-script-execution install.sh:90
HIGH sh-remote-script-execution install.sh:202
HIGH sh-remote-script-execution install.sh:213
HIGH sh-remote-script-execution install.sh:219
HIGH tls-verification-disabled src/dns.mjs:766
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:139
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:153
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:179
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:373
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:377
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:422
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:671
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:867
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:869
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:928
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:974
MEDIUM sql-template-interpolation apps/pwa/src/moshpit.mjs:1044

…and 72 more. Full results in the Security tab.

Snippets are redacted; ThreatCrush never prints matched credential material.

@ralyodio
ralyodio merged commit 0ee02bf into main Sep 6, 2026
6 checks passed
@ralyodio
ralyodio deleted the worktree-cost-pr-links branch September 6, 2026 23:55
@ralyodio ralyodio mentioned this pull request Sep 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant