fix(web): open GitHub pull requests in browser when loading fails - #134

Merged
rynfar merged 2 commits into
pylonfrom
upstream/2026-08-28-pr-open-on-github
Aug 29, 2026
Merged

fix(web): open GitHub pull requests in browser when loading fails#134
rynfar merged 2 commits into
pylonfrom
upstream/2026-08-28-pr-open-on-github

Conversation

@rynfar

@rynfarrynfar commented Aug 28, 2026

Copy link
Copy Markdown
Collaborator

A GitHub API error left the pull request view with only Retry, even though
the pull request was still perfectly reachable on GitHub. Rate limiting is the
common case, and retrying is exactly what does not help.

The error view now offers Open on GitHub, built from the saved project host
and pull request reference with no extra API call — so it works precisely when
the API does not. Error states for GitLab, Bitbucket, Azure DevOps, and unknown
providers are unchanged.

Adopted from T3 Code 7068e86f76e908c77ff04d1a684840257eab3a8a
(pingdotgg/t3code#8507).

Adaptation

One conflict, in docs/user/source-control.md: upstream's new bullet named
"T3 Code" twice. Resolved Pylon-first, keeping Pylon's product name and its
existing command-click bullet. Confirmed no T3 branding leaked into any adopted
file.

Verification

  • vp test run openPullRequestLink.test.ts PullRequestsUnavailableState.test.tsx — 33 passed

  • vp run -F @t3tools/web typecheck — clean

  • gitHubPullRequestBrowserUrl builds a URL that gets opened in a browser, so I
    mutation-probed its two guards rather than trusting the tests existed:

    • dropping the ./.. path-segment check produces
      https://github.com/repository/pull/1 where null is expected — caught;
    • dropping the http:/https: protocol allowlist breaks the SCP-style remote
      path — caught.

    Both guards are therefore genuinely covered, in both directions.

Before/after image pending the consolidated real-client pass for this batch.
Upstream's own before/after screenshots are on pingdotgg/t3code#8507.

Claude Opus 5 via Claude Code.


View with [code]smithAutofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:M labels Aug 28, 2026
@github-actions

github-actionsBot commented Aug 28, 2026

Copy link
Copy Markdown

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ProviderMetricMain baselineThis PRImpactPR ceiling
CodexTotal thread wire13.3 KiB13.3 KiB−6 B (−0.0%)15.1 KiB
CodexThread snapshot wire6.9 KiB6.9 KiB−7 B (−0.1%)7.3 KiB
CodexLive turn WebSocket wire6.4 KiB6.4 KiB+1 B (+0.0%)7.8 KiB
CodexLive turn WebSocket decoded55.5 KiB55.5 KiB0 B (0.0%)66.4 KiB
CodexLive turn messages990 (0.0%)21
ClaudeTotal thread wire13.3 KiB13.3 KiB−63 B (−0.5%)15.1 KiB
ClaudeThread snapshot wire6.9 KiB6.9 KiB+6 B (+0.1%)7.3 KiB
ClaudeLive turn WebSocket wire6.5 KiB6.4 KiB−69 B (−1.0%)7.8 KiB
ClaudeLive turn WebSocket decoded56.4 KiB56.3 KiB−88 B (−0.2%)66.4 KiB
ClaudeLive turn messages119−2 (−18.2%)21

Baseline: 3d6035f · PR result: 42a669e · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 109.4 KiB
  • Claude decoded thread snapshot: 110.1 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

@rynfar

Copy link
Copy Markdown
CollaboratorAuthor

Independent review pass. Two findings — one fixed, one documented.

Fixed in d7109b3ec — the other pull request error surface was a dead end.
The thread right panel shows a second PullRequestsUnavailableState when the
environment's server is too old to browse pull requests, with no retry and no
GitHub link. That contradicted the docs sentence this branch adds, which promises
the button whenever Pylon cannot load a GitHub pull request. The surface already
carries projectId, repository, and number, and ChatView already reads every
project, so it now builds the link with the same helper and the same
conditional-spread pattern the detail panel uses.

Documented — self-hosted GitHub installs still get no button. The helper gates
on identity.provider === "github". A self-hosted GitHub Enterprise host without
a github DNS label carries provider: "unknown", yet the server serves its pull
requests as GitHub after refineUnknownProjectKinds
(PullRequestService.ts:493-588). So the panel works normally and only the error
view comes up empty. Upstream's gating; widening it means deciding what
provider: "unknown" should imply for URL construction, which is a bigger call
than this PR.

The review cleared the parts that mattered: SCP and git:// remotes fall back to
the canonical host, malformed hosts and repository paths return null, credentials
are stripped via URL.origin, non-GitHub providers are correctly excluded,
url.pathname assignment percent-encodes stray characters, and Electron's
setWindowOpenHandler means target="_blank" really does reach the system
browser on desktop.

t3dotggand others added 2 commits August 28, 2026 20:55
A GitHub API error left the pull request view with only Retry, even though the
pull request was still perfectly reachable on GitHub. Rate limiting is the
common case.
The error view now offers Open on GitHub, built from the saved project host and
pull request reference with no extra API call, so it works precisely when the
API does not. Error states for GitLab, Bitbucket, Azure DevOps, and unknown
providers are unchanged.
Adopted from T3 Code 7068e86f76e908c77ff04d1a684840257eab3a8a
(pingdotgg/t3code#8507).
Adaptation: one conflict in docs/user/source-control.md, where upstream's new
bullet named T3 Code twice. Resolved Pylon-first, keeping Pylon's product name
and its existing command-click bullet.
…e too
Review follow-up. The thread right panel has a second pull request error state,
shown when the environment's server is too old to browse pull requests, and it
rendered with no retry and no GitHub link. That made it a dead end, and it
contradicted the docs sentence this branch added, which promises the button
whenever Pylon cannot load a GitHub pull request.
The surface already carries projectId, repository, and number, and ChatView
already reads every project, so the link is built with the same helper and the
same conditional-spread pattern the detail panel uses. A pull request stays
readable on GitHub whether the failure was an API error or an old server.
@rynfar
rynfarforce-pushed the upstream/2026-08-28-pr-open-on-github branch from d7109b3 to 42a669eCompareAugust 29, 2026 02:55
@rynfar
rynfar merged commit 92dce5a into pylonAug 29, 2026
15 checks passed
@rynfar
rynfar deleted the upstream/2026-08-28-pr-open-on-github branch August 29, 2026 03:04
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:Mvouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@rynfar@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

fix(web): open GitHub pull requests in browser when loading fails - #134

Merged
rynfar merged 2 commits into
pylonfrom
upstream/2026-08-28-pr-open-on-github
Aug 29, 2026
Merged

fix(web): open GitHub pull requests in browser when loading fails#134
rynfar merged 2 commits into
pylonfrom
upstream/2026-08-28-pr-open-on-github

Conversation

@rynfar

@rynfarrynfar commented Aug 28, 2026

Copy link
Copy Markdown
Collaborator

A GitHub API error left the pull request view with only Retry, even though
the pull request was still perfectly reachable on GitHub. Rate limiting is the
common case, and retrying is exactly what does not help.

The error view now offers Open on GitHub, built from the saved project host
and pull request reference with no extra API call — so it works precisely when
the API does not. Error states for GitLab, Bitbucket, Azure DevOps, and unknown
providers are unchanged.

Adopted from T3 Code 7068e86f76e908c77ff04d1a684840257eab3a8a
(pingdotgg/t3code#8507).

Adaptation

One conflict, in docs/user/source-control.md: upstream's new bullet named
"T3 Code" twice. Resolved Pylon-first, keeping Pylon's product name and its
existing command-click bullet. Confirmed no T3 branding leaked into any adopted
file.

Verification

  • vp test run openPullRequestLink.test.ts PullRequestsUnavailableState.test.tsx — 33 passed

  • vp run -F @t3tools/web typecheck — clean

  • gitHubPullRequestBrowserUrl builds a URL that gets opened in a browser, so I
    mutation-probed its two guards rather than trusting the tests existed:

    • dropping the ./.. path-segment check produces
      https://github.com/repository/pull/1 where null is expected — caught;
    • dropping the http:/https: protocol allowlist breaks the SCP-style remote
      path — caught.

    Both guards are therefore genuinely covered, in both directions.

Before/after image pending the consolidated real-client pass for this batch.
Upstream's own before/after screenshots are on pingdotgg/t3code#8507.

Claude Opus 5 via Claude Code.


View with [code]smithAutofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:M labels Aug 28, 2026
@github-actions

github-actionsBot commented Aug 28, 2026

Copy link
Copy Markdown

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ProviderMetricMain baselineThis PRImpactPR ceiling
CodexTotal thread wire13.3 KiB13.3 KiB−6 B (−0.0%)15.1 KiB
CodexThread snapshot wire6.9 KiB6.9 KiB−7 B (−0.1%)7.3 KiB
CodexLive turn WebSocket wire6.4 KiB6.4 KiB+1 B (+0.0%)7.8 KiB
CodexLive turn WebSocket decoded55.5 KiB55.5 KiB0 B (0.0%)66.4 KiB
CodexLive turn messages990 (0.0%)21
ClaudeTotal thread wire13.3 KiB13.3 KiB−63 B (−0.5%)15.1 KiB
ClaudeThread snapshot wire6.9 KiB6.9 KiB+6 B (+0.1%)7.3 KiB
ClaudeLive turn WebSocket wire6.5 KiB6.4 KiB−69 B (−1.0%)7.8 KiB
ClaudeLive turn WebSocket decoded56.4 KiB56.3 KiB−88 B (−0.2%)66.4 KiB
ClaudeLive turn messages119−2 (−18.2%)21

Baseline: 3d6035f · PR result: 42a669e · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 109.4 KiB
  • Claude decoded thread snapshot: 110.1 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

@rynfar

Copy link
Copy Markdown
CollaboratorAuthor

Independent review pass. Two findings — one fixed, one documented.

Fixed in d7109b3ec — the other pull request error surface was a dead end.
The thread right panel shows a second PullRequestsUnavailableState when the
environment's server is too old to browse pull requests, with no retry and no
GitHub link. That contradicted the docs sentence this branch adds, which promises
the button whenever Pylon cannot load a GitHub pull request. The surface already
carries projectId, repository, and number, and ChatView already reads every
project, so it now builds the link with the same helper and the same
conditional-spread pattern the detail panel uses.

Documented — self-hosted GitHub installs still get no button. The helper gates
on identity.provider === "github". A self-hosted GitHub Enterprise host without
a github DNS label carries provider: "unknown", yet the server serves its pull
requests as GitHub after refineUnknownProjectKinds
(PullRequestService.ts:493-588). So the panel works normally and only the error
view comes up empty. Upstream's gating; widening it means deciding what
provider: "unknown" should imply for URL construction, which is a bigger call
than this PR.

The review cleared the parts that mattered: SCP and git:// remotes fall back to
the canonical host, malformed hosts and repository paths return null, credentials
are stripped via URL.origin, non-GitHub providers are correctly excluded,
url.pathname assignment percent-encodes stray characters, and Electron's
setWindowOpenHandler means target="_blank" really does reach the system
browser on desktop.

t3dotggand others added 2 commits August 28, 2026 20:55
A GitHub API error left the pull request view with only Retry, even though the
pull request was still perfectly reachable on GitHub. Rate limiting is the
common case.
The error view now offers Open on GitHub, built from the saved project host and
pull request reference with no extra API call, so it works precisely when the
API does not. Error states for GitLab, Bitbucket, Azure DevOps, and unknown
providers are unchanged.
Adopted from T3 Code 7068e86f76e908c77ff04d1a684840257eab3a8a
(pingdotgg/t3code#8507).
Adaptation: one conflict in docs/user/source-control.md, where upstream's new
bullet named T3 Code twice. Resolved Pylon-first, keeping Pylon's product name
and its existing command-click bullet.
…e too
Review follow-up. The thread right panel has a second pull request error state,
shown when the environment's server is too old to browse pull requests, and it
rendered with no retry and no GitHub link. That made it a dead end, and it
contradicted the docs sentence this branch added, which promises the button
whenever Pylon cannot load a GitHub pull request.
The surface already carries projectId, repository, and number, and ChatView
already reads every project, so the link is built with the same helper and the
same conditional-spread pattern the detail panel uses. A pull request stays
readable on GitHub whether the failure was an API error or an old server.
@rynfar
rynfarforce-pushed the upstream/2026-08-28-pr-open-on-github branch from d7109b3 to 42a669eCompareAugust 29, 2026 02:55
@rynfar
rynfar merged commit 92dce5a into pylonAug 29, 2026
15 checks passed
@rynfar
rynfar deleted the upstream/2026-08-28-pr-open-on-github branch August 29, 2026 03:04
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:Mvouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@rynfar@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(web): open GitHub pull requests in browser when loading fails - #134

Merged
rynfar merged 2 commits into
pylonfrom
upstream/2026-08-28-pr-open-on-github
Aug 29, 2026
Merged

fix(web): open GitHub pull requests in browser when loading fails#134
rynfar merged 2 commits into
pylonfrom
upstream/2026-08-28-pr-open-on-github

Conversation

@rynfar

@rynfarrynfar commented Aug 28, 2026

Copy link
Copy Markdown
Collaborator

A GitHub API error left the pull request view with only Retry, even though
the pull request was still perfectly reachable on GitHub. Rate limiting is the
common case, and retrying is exactly what does not help.

The error view now offers Open on GitHub, built from the saved project host
and pull request reference with no extra API call — so it works precisely when
the API does not. Error states for GitLab, Bitbucket, Azure DevOps, and unknown
providers are unchanged.

Adopted from T3 Code 7068e86f76e908c77ff04d1a684840257eab3a8a
(pingdotgg/t3code#8507).

Adaptation

One conflict, in docs/user/source-control.md: upstream's new bullet named
"T3 Code" twice. Resolved Pylon-first, keeping Pylon's product name and its
existing command-click bullet. Confirmed no T3 branding leaked into any adopted
file.

Verification

  • vp test run openPullRequestLink.test.ts PullRequestsUnavailableState.test.tsx — 33 passed

  • vp run -F @t3tools/web typecheck — clean

  • gitHubPullRequestBrowserUrl builds a URL that gets opened in a browser, so I
    mutation-probed its two guards rather than trusting the tests existed:

    • dropping the ./.. path-segment check produces
      https://github.com/repository/pull/1 where null is expected — caught;
    • dropping the http:/https: protocol allowlist breaks the SCP-style remote
      path — caught.

    Both guards are therefore genuinely covered, in both directions.

Before/after image pending the consolidated real-client pass for this batch.
Upstream's own before/after screenshots are on pingdotgg/t3code#8507.

Claude Opus 5 via Claude Code.


View with [code]smithAutofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:M labels Aug 28, 2026
@github-actions

github-actionsBot commented Aug 28, 2026

Copy link
Copy Markdown

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ProviderMetricMain baselineThis PRImpactPR ceiling
CodexTotal thread wire13.3 KiB13.3 KiB−6 B (−0.0%)15.1 KiB
CodexThread snapshot wire6.9 KiB6.9 KiB−7 B (−0.1%)7.3 KiB
CodexLive turn WebSocket wire6.4 KiB6.4 KiB+1 B (+0.0%)7.8 KiB
CodexLive turn WebSocket decoded55.5 KiB55.5 KiB0 B (0.0%)66.4 KiB
CodexLive turn messages990 (0.0%)21
ClaudeTotal thread wire13.3 KiB13.3 KiB−63 B (−0.5%)15.1 KiB
ClaudeThread snapshot wire6.9 KiB6.9 KiB+6 B (+0.1%)7.3 KiB
ClaudeLive turn WebSocket wire6.5 KiB6.4 KiB−69 B (−1.0%)7.8 KiB
ClaudeLive turn WebSocket decoded56.4 KiB56.3 KiB−88 B (−0.2%)66.4 KiB
ClaudeLive turn messages119−2 (−18.2%)21

Baseline: 3d6035f · PR result: 42a669e · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 109.4 KiB
  • Claude decoded thread snapshot: 110.1 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

@rynfar

Copy link
Copy Markdown
CollaboratorAuthor

Independent review pass. Two findings — one fixed, one documented.

Fixed in d7109b3ec — the other pull request error surface was a dead end.
The thread right panel shows a second PullRequestsUnavailableState when the
environment's server is too old to browse pull requests, with no retry and no
GitHub link. That contradicted the docs sentence this branch adds, which promises
the button whenever Pylon cannot load a GitHub pull request. The surface already
carries projectId, repository, and number, and ChatView already reads every
project, so it now builds the link with the same helper and the same
conditional-spread pattern the detail panel uses.

Documented — self-hosted GitHub installs still get no button. The helper gates
on identity.provider === "github". A self-hosted GitHub Enterprise host without
a github DNS label carries provider: "unknown", yet the server serves its pull
requests as GitHub after refineUnknownProjectKinds
(PullRequestService.ts:493-588). So the panel works normally and only the error
view comes up empty. Upstream's gating; widening it means deciding what
provider: "unknown" should imply for URL construction, which is a bigger call
than this PR.

The review cleared the parts that mattered: SCP and git:// remotes fall back to
the canonical host, malformed hosts and repository paths return null, credentials
are stripped via URL.origin, non-GitHub providers are correctly excluded,
url.pathname assignment percent-encodes stray characters, and Electron's
setWindowOpenHandler means target="_blank" really does reach the system
browser on desktop.

t3dotggand others added 2 commits August 28, 2026 20:55
A GitHub API error left the pull request view with only Retry, even though the
pull request was still perfectly reachable on GitHub. Rate limiting is the
common case.
The error view now offers Open on GitHub, built from the saved project host and
pull request reference with no extra API call, so it works precisely when the
API does not. Error states for GitLab, Bitbucket, Azure DevOps, and unknown
providers are unchanged.
Adopted from T3 Code 7068e86f76e908c77ff04d1a684840257eab3a8a
(pingdotgg/t3code#8507).
Adaptation: one conflict in docs/user/source-control.md, where upstream's new
bullet named T3 Code twice. Resolved Pylon-first, keeping Pylon's product name
and its existing command-click bullet.
…e too
Review follow-up. The thread right panel has a second pull request error state,
shown when the environment's server is too old to browse pull requests, and it
rendered with no retry and no GitHub link. That made it a dead end, and it
contradicted the docs sentence this branch added, which promises the button
whenever Pylon cannot load a GitHub pull request.
The surface already carries projectId, repository, and number, and ChatView
already reads every project, so the link is built with the same helper and the
same conditional-spread pattern the detail panel uses. A pull request stays
readable on GitHub whether the failure was an API error or an old server.
@rynfar
rynfarforce-pushed the upstream/2026-08-28-pr-open-on-github branch from d7109b3 to 42a669eCompareAugust 29, 2026 02:55
@rynfar
rynfar merged commit 92dce5a into pylonAug 29, 2026
15 checks passed
@rynfar
rynfar deleted the upstream/2026-08-28-pr-open-on-github branch August 29, 2026 03:04
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:Mvouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@rynfar@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(web): open GitHub pull requests in browser when loading fails - #134

Merged
rynfar merged 2 commits into
pylonfrom
upstream/2026-08-28-pr-open-on-github
Aug 29, 2026
Merged

fix(web): open GitHub pull requests in browser when loading fails#134
rynfar merged 2 commits into
pylonfrom
upstream/2026-08-28-pr-open-on-github

Conversation

@rynfar

@rynfarrynfar commented Aug 28, 2026

Copy link
Copy Markdown
Collaborator

A GitHub API error left the pull request view with only Retry, even though
the pull request was still perfectly reachable on GitHub. Rate limiting is the
common case, and retrying is exactly what does not help.

The error view now offers Open on GitHub, built from the saved project host
and pull request reference with no extra API call — so it works precisely when
the API does not. Error states for GitLab, Bitbucket, Azure DevOps, and unknown
providers are unchanged.

Adopted from T3 Code 7068e86f76e908c77ff04d1a684840257eab3a8a
(pingdotgg/t3code#8507).

Adaptation

One conflict, in docs/user/source-control.md: upstream's new bullet named
"T3 Code" twice. Resolved Pylon-first, keeping Pylon's product name and its
existing command-click bullet. Confirmed no T3 branding leaked into any adopted
file.

Verification

  • vp test run openPullRequestLink.test.ts PullRequestsUnavailableState.test.tsx — 33 passed

  • vp run -F @t3tools/web typecheck — clean

  • gitHubPullRequestBrowserUrl builds a URL that gets opened in a browser, so I
    mutation-probed its two guards rather than trusting the tests existed:

    • dropping the ./.. path-segment check produces
      https://github.com/repository/pull/1 where null is expected — caught;
    • dropping the http:/https: protocol allowlist breaks the SCP-style remote
      path — caught.

    Both guards are therefore genuinely covered, in both directions.

Before/after image pending the consolidated real-client pass for this batch.
Upstream's own before/after screenshots are on pingdotgg/t3code#8507.

Claude Opus 5 via Claude Code.


View with [code]smithAutofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:M labels Aug 28, 2026
@github-actions

github-actionsBot commented Aug 28, 2026

Copy link
Copy Markdown

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ProviderMetricMain baselineThis PRImpactPR ceiling
CodexTotal thread wire13.3 KiB13.3 KiB−6 B (−0.0%)15.1 KiB
CodexThread snapshot wire6.9 KiB6.9 KiB−7 B (−0.1%)7.3 KiB
CodexLive turn WebSocket wire6.4 KiB6.4 KiB+1 B (+0.0%)7.8 KiB
CodexLive turn WebSocket decoded55.5 KiB55.5 KiB0 B (0.0%)66.4 KiB
CodexLive turn messages990 (0.0%)21
ClaudeTotal thread wire13.3 KiB13.3 KiB−63 B (−0.5%)15.1 KiB
ClaudeThread snapshot wire6.9 KiB6.9 KiB+6 B (+0.1%)7.3 KiB
ClaudeLive turn WebSocket wire6.5 KiB6.4 KiB−69 B (−1.0%)7.8 KiB
ClaudeLive turn WebSocket decoded56.4 KiB56.3 KiB−88 B (−0.2%)66.4 KiB
ClaudeLive turn messages119−2 (−18.2%)21

Baseline: 3d6035f · PR result: 42a669e · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 109.4 KiB
  • Claude decoded thread snapshot: 110.1 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

@rynfar

Copy link
Copy Markdown
CollaboratorAuthor

Independent review pass. Two findings — one fixed, one documented.

Fixed in d7109b3ec — the other pull request error surface was a dead end.
The thread right panel shows a second PullRequestsUnavailableState when the
environment's server is too old to browse pull requests, with no retry and no
GitHub link. That contradicted the docs sentence this branch adds, which promises
the button whenever Pylon cannot load a GitHub pull request. The surface already
carries projectId, repository, and number, and ChatView already reads every
project, so it now builds the link with the same helper and the same
conditional-spread pattern the detail panel uses.

Documented — self-hosted GitHub installs still get no button. The helper gates
on identity.provider === "github". A self-hosted GitHub Enterprise host without
a github DNS label carries provider: "unknown", yet the server serves its pull
requests as GitHub after refineUnknownProjectKinds
(PullRequestService.ts:493-588). So the panel works normally and only the error
view comes up empty. Upstream's gating; widening it means deciding what
provider: "unknown" should imply for URL construction, which is a bigger call
than this PR.

The review cleared the parts that mattered: SCP and git:// remotes fall back to
the canonical host, malformed hosts and repository paths return null, credentials
are stripped via URL.origin, non-GitHub providers are correctly excluded,
url.pathname assignment percent-encodes stray characters, and Electron's
setWindowOpenHandler means target="_blank" really does reach the system
browser on desktop.

t3dotggand others added 2 commits August 28, 2026 20:55
A GitHub API error left the pull request view with only Retry, even though the
pull request was still perfectly reachable on GitHub. Rate limiting is the
common case.
The error view now offers Open on GitHub, built from the saved project host and
pull request reference with no extra API call, so it works precisely when the
API does not. Error states for GitLab, Bitbucket, Azure DevOps, and unknown
providers are unchanged.
Adopted from T3 Code 7068e86f76e908c77ff04d1a684840257eab3a8a
(pingdotgg/t3code#8507).
Adaptation: one conflict in docs/user/source-control.md, where upstream's new
bullet named T3 Code twice. Resolved Pylon-first, keeping Pylon's product name
and its existing command-click bullet.
…e too
Review follow-up. The thread right panel has a second pull request error state,
shown when the environment's server is too old to browse pull requests, and it
rendered with no retry and no GitHub link. That made it a dead end, and it
contradicted the docs sentence this branch added, which promises the button
whenever Pylon cannot load a GitHub pull request.
The surface already carries projectId, repository, and number, and ChatView
already reads every project, so the link is built with the same helper and the
same conditional-spread pattern the detail panel uses. A pull request stays
readable on GitHub whether the failure was an API error or an old server.
@rynfar
rynfarforce-pushed the upstream/2026-08-28-pr-open-on-github branch from d7109b3 to 42a669eCompareAugust 29, 2026 02:55
@rynfar
rynfar merged commit 92dce5a into pylonAug 29, 2026
15 checks passed
@rynfar
rynfar deleted the upstream/2026-08-28-pr-open-on-github branch August 29, 2026 03:04
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:Mvouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@rynfar@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

fix(web): open GitHub pull requests in browser when loading fails - #134

Merged
rynfar merged 2 commits into
pylonfrom
upstream/2026-08-28-pr-open-on-github
Aug 29, 2026
Merged

fix(web): open GitHub pull requests in browser when loading fails#134
rynfar merged 2 commits into
pylonfrom
upstream/2026-08-28-pr-open-on-github

Conversation

@rynfar

@rynfarrynfar commented Aug 28, 2026

Copy link
Copy Markdown
Collaborator

A GitHub API error left the pull request view with only Retry, even though
the pull request was still perfectly reachable on GitHub. Rate limiting is the
common case, and retrying is exactly what does not help.

The error view now offers Open on GitHub, built from the saved project host
and pull request reference with no extra API call — so it works precisely when
the API does not. Error states for GitLab, Bitbucket, Azure DevOps, and unknown
providers are unchanged.

Adopted from T3 Code 7068e86f76e908c77ff04d1a684840257eab3a8a
(pingdotgg/t3code#8507).

Adaptation

One conflict, in docs/user/source-control.md: upstream's new bullet named
"T3 Code" twice. Resolved Pylon-first, keeping Pylon's product name and its
existing command-click bullet. Confirmed no T3 branding leaked into any adopted
file.

Verification

  • vp test run openPullRequestLink.test.ts PullRequestsUnavailableState.test.tsx — 33 passed

  • vp run -F @t3tools/web typecheck — clean

  • gitHubPullRequestBrowserUrl builds a URL that gets opened in a browser, so I
    mutation-probed its two guards rather than trusting the tests existed:

    • dropping the ./.. path-segment check produces
      https://github.com/repository/pull/1 where null is expected — caught;
    • dropping the http:/https: protocol allowlist breaks the SCP-style remote
      path — caught.

    Both guards are therefore genuinely covered, in both directions.

Before/after image pending the consolidated real-client pass for this batch.
Upstream's own before/after screenshots are on pingdotgg/t3code#8507.

Claude Opus 5 via Claude Code.


View with [code]smithAutofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:M labels Aug 28, 2026
@github-actions

github-actionsBot commented Aug 28, 2026

Copy link
Copy Markdown

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ProviderMetricMain baselineThis PRImpactPR ceiling
CodexTotal thread wire13.3 KiB13.3 KiB−6 B (−0.0%)15.1 KiB
CodexThread snapshot wire6.9 KiB6.9 KiB−7 B (−0.1%)7.3 KiB
CodexLive turn WebSocket wire6.4 KiB6.4 KiB+1 B (+0.0%)7.8 KiB
CodexLive turn WebSocket decoded55.5 KiB55.5 KiB0 B (0.0%)66.4 KiB
CodexLive turn messages990 (0.0%)21
ClaudeTotal thread wire13.3 KiB13.3 KiB−63 B (−0.5%)15.1 KiB
ClaudeThread snapshot wire6.9 KiB6.9 KiB+6 B (+0.1%)7.3 KiB
ClaudeLive turn WebSocket wire6.5 KiB6.4 KiB−69 B (−1.0%)7.8 KiB
ClaudeLive turn WebSocket decoded56.4 KiB56.3 KiB−88 B (−0.2%)66.4 KiB
ClaudeLive turn messages119−2 (−18.2%)21

Baseline: 3d6035f · PR result: 42a669e · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 109.4 KiB
  • Claude decoded thread snapshot: 110.1 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

@rynfar

Copy link
Copy Markdown
CollaboratorAuthor

Independent review pass. Two findings — one fixed, one documented.

Fixed in d7109b3ec — the other pull request error surface was a dead end.
The thread right panel shows a second PullRequestsUnavailableState when the
environment's server is too old to browse pull requests, with no retry and no
GitHub link. That contradicted the docs sentence this branch adds, which promises
the button whenever Pylon cannot load a GitHub pull request. The surface already
carries projectId, repository, and number, and ChatView already reads every
project, so it now builds the link with the same helper and the same
conditional-spread pattern the detail panel uses.

Documented — self-hosted GitHub installs still get no button. The helper gates
on identity.provider === "github". A self-hosted GitHub Enterprise host without
a github DNS label carries provider: "unknown", yet the server serves its pull
requests as GitHub after refineUnknownProjectKinds
(PullRequestService.ts:493-588). So the panel works normally and only the error
view comes up empty. Upstream's gating; widening it means deciding what
provider: "unknown" should imply for URL construction, which is a bigger call
than this PR.

The review cleared the parts that mattered: SCP and git:// remotes fall back to
the canonical host, malformed hosts and repository paths return null, credentials
are stripped via URL.origin, non-GitHub providers are correctly excluded,
url.pathname assignment percent-encodes stray characters, and Electron's
setWindowOpenHandler means target="_blank" really does reach the system
browser on desktop.

t3dotggand others added 2 commits August 28, 2026 20:55
A GitHub API error left the pull request view with only Retry, even though the
pull request was still perfectly reachable on GitHub. Rate limiting is the
common case.
The error view now offers Open on GitHub, built from the saved project host and
pull request reference with no extra API call, so it works precisely when the
API does not. Error states for GitLab, Bitbucket, Azure DevOps, and unknown
providers are unchanged.
Adopted from T3 Code 7068e86f76e908c77ff04d1a684840257eab3a8a
(pingdotgg/t3code#8507).
Adaptation: one conflict in docs/user/source-control.md, where upstream's new
bullet named T3 Code twice. Resolved Pylon-first, keeping Pylon's product name
and its existing command-click bullet.
…e too
Review follow-up. The thread right panel has a second pull request error state,
shown when the environment's server is too old to browse pull requests, and it
rendered with no retry and no GitHub link. That made it a dead end, and it
contradicted the docs sentence this branch added, which promises the button
whenever Pylon cannot load a GitHub pull request.
The surface already carries projectId, repository, and number, and ChatView
already reads every project, so the link is built with the same helper and the
same conditional-spread pattern the detail panel uses. A pull request stays
readable on GitHub whether the failure was an API error or an old server.
@rynfar
rynfarforce-pushed the upstream/2026-08-28-pr-open-on-github branch from d7109b3 to 42a669eCompareAugust 29, 2026 02:55
@rynfar
rynfar merged commit 92dce5a into pylonAug 29, 2026
15 checks passed
@rynfar
rynfar deleted the upstream/2026-08-28-pr-open-on-github branch August 29, 2026 03:04
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:Mvouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@rynfar@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(web): open GitHub pull requests in browser when loading fails - #134

Merged
rynfar merged 2 commits into
pylonfrom
upstream/2026-08-28-pr-open-on-github
Aug 29, 2026
Merged

fix(web): open GitHub pull requests in browser when loading fails#134
rynfar merged 2 commits into
pylonfrom
upstream/2026-08-28-pr-open-on-github

Conversation

@rynfar

@rynfarrynfar commented Aug 28, 2026

Copy link
Copy Markdown
Collaborator

A GitHub API error left the pull request view with only Retry, even though
the pull request was still perfectly reachable on GitHub. Rate limiting is the
common case, and retrying is exactly what does not help.

The error view now offers Open on GitHub, built from the saved project host
and pull request reference with no extra API call — so it works precisely when
the API does not. Error states for GitLab, Bitbucket, Azure DevOps, and unknown
providers are unchanged.

Adopted from T3 Code 7068e86f76e908c77ff04d1a684840257eab3a8a
(pingdotgg/t3code#8507).

Adaptation

One conflict, in docs/user/source-control.md: upstream's new bullet named
"T3 Code" twice. Resolved Pylon-first, keeping Pylon's product name and its
existing command-click bullet. Confirmed no T3 branding leaked into any adopted
file.

Verification

  • vp test run openPullRequestLink.test.ts PullRequestsUnavailableState.test.tsx — 33 passed

  • vp run -F @t3tools/web typecheck — clean

  • gitHubPullRequestBrowserUrl builds a URL that gets opened in a browser, so I
    mutation-probed its two guards rather than trusting the tests existed:

    • dropping the ./.. path-segment check produces
      https://github.com/repository/pull/1 where null is expected — caught;
    • dropping the http:/https: protocol allowlist breaks the SCP-style remote
      path — caught.

    Both guards are therefore genuinely covered, in both directions.

Before/after image pending the consolidated real-client pass for this batch.
Upstream's own before/after screenshots are on pingdotgg/t3code#8507.

Claude Opus 5 via Claude Code.


View with [code]smithAutofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:M labels Aug 28, 2026
@github-actions

github-actionsBot commented Aug 28, 2026

Copy link
Copy Markdown

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ProviderMetricMain baselineThis PRImpactPR ceiling
CodexTotal thread wire13.3 KiB13.3 KiB−6 B (−0.0%)15.1 KiB
CodexThread snapshot wire6.9 KiB6.9 KiB−7 B (−0.1%)7.3 KiB
CodexLive turn WebSocket wire6.4 KiB6.4 KiB+1 B (+0.0%)7.8 KiB
CodexLive turn WebSocket decoded55.5 KiB55.5 KiB0 B (0.0%)66.4 KiB
CodexLive turn messages990 (0.0%)21
ClaudeTotal thread wire13.3 KiB13.3 KiB−63 B (−0.5%)15.1 KiB
ClaudeThread snapshot wire6.9 KiB6.9 KiB+6 B (+0.1%)7.3 KiB
ClaudeLive turn WebSocket wire6.5 KiB6.4 KiB−69 B (−1.0%)7.8 KiB
ClaudeLive turn WebSocket decoded56.4 KiB56.3 KiB−88 B (−0.2%)66.4 KiB
ClaudeLive turn messages119−2 (−18.2%)21

Baseline: 3d6035f · PR result: 42a669e · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 109.4 KiB
  • Claude decoded thread snapshot: 110.1 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

@rynfar

Copy link
Copy Markdown
CollaboratorAuthor

Independent review pass. Two findings — one fixed, one documented.

Fixed in d7109b3ec — the other pull request error surface was a dead end.
The thread right panel shows a second PullRequestsUnavailableState when the
environment's server is too old to browse pull requests, with no retry and no
GitHub link. That contradicted the docs sentence this branch adds, which promises
the button whenever Pylon cannot load a GitHub pull request. The surface already
carries projectId, repository, and number, and ChatView already reads every
project, so it now builds the link with the same helper and the same
conditional-spread pattern the detail panel uses.

Documented — self-hosted GitHub installs still get no button. The helper gates
on identity.provider === "github". A self-hosted GitHub Enterprise host without
a github DNS label carries provider: "unknown", yet the server serves its pull
requests as GitHub after refineUnknownProjectKinds
(PullRequestService.ts:493-588). So the panel works normally and only the error
view comes up empty. Upstream's gating; widening it means deciding what
provider: "unknown" should imply for URL construction, which is a bigger call
than this PR.

The review cleared the parts that mattered: SCP and git:// remotes fall back to
the canonical host, malformed hosts and repository paths return null, credentials
are stripped via URL.origin, non-GitHub providers are correctly excluded,
url.pathname assignment percent-encodes stray characters, and Electron's
setWindowOpenHandler means target="_blank" really does reach the system
browser on desktop.

t3dotggand others added 2 commits August 28, 2026 20:55
A GitHub API error left the pull request view with only Retry, even though the
pull request was still perfectly reachable on GitHub. Rate limiting is the
common case.
The error view now offers Open on GitHub, built from the saved project host and
pull request reference with no extra API call, so it works precisely when the
API does not. Error states for GitLab, Bitbucket, Azure DevOps, and unknown
providers are unchanged.
Adopted from T3 Code 7068e86f76e908c77ff04d1a684840257eab3a8a
(pingdotgg/t3code#8507).
Adaptation: one conflict in docs/user/source-control.md, where upstream's new
bullet named T3 Code twice. Resolved Pylon-first, keeping Pylon's product name
and its existing command-click bullet.
…e too
Review follow-up. The thread right panel has a second pull request error state,
shown when the environment's server is too old to browse pull requests, and it
rendered with no retry and no GitHub link. That made it a dead end, and it
contradicted the docs sentence this branch added, which promises the button
whenever Pylon cannot load a GitHub pull request.
The surface already carries projectId, repository, and number, and ChatView
already reads every project, so the link is built with the same helper and the
same conditional-spread pattern the detail panel uses. A pull request stays
readable on GitHub whether the failure was an API error or an old server.
@rynfar
rynfarforce-pushed the upstream/2026-08-28-pr-open-on-github branch from d7109b3 to 42a669eCompareAugust 29, 2026 02:55
@rynfar
rynfar merged commit 92dce5a into pylonAug 29, 2026
15 checks passed
@rynfar
rynfar deleted the upstream/2026-08-28-pr-open-on-github branch August 29, 2026 03:04
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:Mvouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@rynfar@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(web): open GitHub pull requests in browser when loading fails - #134

Merged
rynfar merged 2 commits into
pylonfrom
upstream/2026-08-28-pr-open-on-github
Aug 29, 2026
Merged

fix(web): open GitHub pull requests in browser when loading fails#134
rynfar merged 2 commits into
pylonfrom
upstream/2026-08-28-pr-open-on-github

Conversation

@rynfar

@rynfarrynfar commented Aug 28, 2026

Copy link
Copy Markdown
Collaborator

A GitHub API error left the pull request view with only Retry, even though
the pull request was still perfectly reachable on GitHub. Rate limiting is the
common case, and retrying is exactly what does not help.

The error view now offers Open on GitHub, built from the saved project host
and pull request reference with no extra API call — so it works precisely when
the API does not. Error states for GitLab, Bitbucket, Azure DevOps, and unknown
providers are unchanged.

Adopted from T3 Code 7068e86f76e908c77ff04d1a684840257eab3a8a
(pingdotgg/t3code#8507).

Adaptation

One conflict, in docs/user/source-control.md: upstream's new bullet named
"T3 Code" twice. Resolved Pylon-first, keeping Pylon's product name and its
existing command-click bullet. Confirmed no T3 branding leaked into any adopted
file.

Verification

  • vp test run openPullRequestLink.test.ts PullRequestsUnavailableState.test.tsx — 33 passed

  • vp run -F @t3tools/web typecheck — clean

  • gitHubPullRequestBrowserUrl builds a URL that gets opened in a browser, so I
    mutation-probed its two guards rather than trusting the tests existed:

    • dropping the ./.. path-segment check produces
      https://github.com/repository/pull/1 where null is expected — caught;
    • dropping the http:/https: protocol allowlist breaks the SCP-style remote
      path — caught.

    Both guards are therefore genuinely covered, in both directions.

Before/after image pending the consolidated real-client pass for this batch.
Upstream's own before/after screenshots are on pingdotgg/t3code#8507.

Claude Opus 5 via Claude Code.


View with [code]smithAutofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:M labels Aug 28, 2026
@github-actions

github-actionsBot commented Aug 28, 2026

Copy link
Copy Markdown

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ProviderMetricMain baselineThis PRImpactPR ceiling
CodexTotal thread wire13.3 KiB13.3 KiB−6 B (−0.0%)15.1 KiB
CodexThread snapshot wire6.9 KiB6.9 KiB−7 B (−0.1%)7.3 KiB
CodexLive turn WebSocket wire6.4 KiB6.4 KiB+1 B (+0.0%)7.8 KiB
CodexLive turn WebSocket decoded55.5 KiB55.5 KiB0 B (0.0%)66.4 KiB
CodexLive turn messages990 (0.0%)21
ClaudeTotal thread wire13.3 KiB13.3 KiB−63 B (−0.5%)15.1 KiB
ClaudeThread snapshot wire6.9 KiB6.9 KiB+6 B (+0.1%)7.3 KiB
ClaudeLive turn WebSocket wire6.5 KiB6.4 KiB−69 B (−1.0%)7.8 KiB
ClaudeLive turn WebSocket decoded56.4 KiB56.3 KiB−88 B (−0.2%)66.4 KiB
ClaudeLive turn messages119−2 (−18.2%)21

Baseline: 3d6035f · PR result: 42a669e · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 109.4 KiB
  • Claude decoded thread snapshot: 110.1 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

@rynfar

Copy link
Copy Markdown
CollaboratorAuthor

Independent review pass. Two findings — one fixed, one documented.

Fixed in d7109b3ec — the other pull request error surface was a dead end.
The thread right panel shows a second PullRequestsUnavailableState when the
environment's server is too old to browse pull requests, with no retry and no
GitHub link. That contradicted the docs sentence this branch adds, which promises
the button whenever Pylon cannot load a GitHub pull request. The surface already
carries projectId, repository, and number, and ChatView already reads every
project, so it now builds the link with the same helper and the same
conditional-spread pattern the detail panel uses.

Documented — self-hosted GitHub installs still get no button. The helper gates
on identity.provider === "github". A self-hosted GitHub Enterprise host without
a github DNS label carries provider: "unknown", yet the server serves its pull
requests as GitHub after refineUnknownProjectKinds
(PullRequestService.ts:493-588). So the panel works normally and only the error
view comes up empty. Upstream's gating; widening it means deciding what
provider: "unknown" should imply for URL construction, which is a bigger call
than this PR.

The review cleared the parts that mattered: SCP and git:// remotes fall back to
the canonical host, malformed hosts and repository paths return null, credentials
are stripped via URL.origin, non-GitHub providers are correctly excluded,
url.pathname assignment percent-encodes stray characters, and Electron's
setWindowOpenHandler means target="_blank" really does reach the system
browser on desktop.

t3dotggand others added 2 commits August 28, 2026 20:55
A GitHub API error left the pull request view with only Retry, even though the
pull request was still perfectly reachable on GitHub. Rate limiting is the
common case.
The error view now offers Open on GitHub, built from the saved project host and
pull request reference with no extra API call, so it works precisely when the
API does not. Error states for GitLab, Bitbucket, Azure DevOps, and unknown
providers are unchanged.
Adopted from T3 Code 7068e86f76e908c77ff04d1a684840257eab3a8a
(pingdotgg/t3code#8507).
Adaptation: one conflict in docs/user/source-control.md, where upstream's new
bullet named T3 Code twice. Resolved Pylon-first, keeping Pylon's product name
and its existing command-click bullet.
…e too
Review follow-up. The thread right panel has a second pull request error state,
shown when the environment's server is too old to browse pull requests, and it
rendered with no retry and no GitHub link. That made it a dead end, and it
contradicted the docs sentence this branch added, which promises the button
whenever Pylon cannot load a GitHub pull request.
The surface already carries projectId, repository, and number, and ChatView
already reads every project, so the link is built with the same helper and the
same conditional-spread pattern the detail panel uses. A pull request stays
readable on GitHub whether the failure was an API error or an old server.
@rynfar
rynfarforce-pushed the upstream/2026-08-28-pr-open-on-github branch from d7109b3 to 42a669eCompareAugust 29, 2026 02:55
@rynfar
rynfar merged commit 92dce5a into pylonAug 29, 2026
15 checks passed
@rynfar
rynfar deleted the upstream/2026-08-28-pr-open-on-github branch August 29, 2026 03:04
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:Mvouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@rynfar@t3dotgg
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

fix(web): open GitHub pull requests in browser when loading fails - #134

Merged
rynfar merged 2 commits into
pylonfrom
upstream/2026-08-28-pr-open-on-github
Aug 29, 2026
Merged

fix(web): open GitHub pull requests in browser when loading fails#134
rynfar merged 2 commits into
pylonfrom
upstream/2026-08-28-pr-open-on-github

Conversation

@rynfar

@rynfarrynfar commented Aug 28, 2026

Copy link
Copy Markdown
Collaborator

A GitHub API error left the pull request view with only Retry, even though
the pull request was still perfectly reachable on GitHub. Rate limiting is the
common case, and retrying is exactly what does not help.

The error view now offers Open on GitHub, built from the saved project host
and pull request reference with no extra API call — so it works precisely when
the API does not. Error states for GitLab, Bitbucket, Azure DevOps, and unknown
providers are unchanged.

Adopted from T3 Code 7068e86f76e908c77ff04d1a684840257eab3a8a
(pingdotgg/t3code#8507).

Adaptation

One conflict, in docs/user/source-control.md: upstream's new bullet named
"T3 Code" twice. Resolved Pylon-first, keeping Pylon's product name and its
existing command-click bullet. Confirmed no T3 branding leaked into any adopted
file.

Verification

  • vp test run openPullRequestLink.test.ts PullRequestsUnavailableState.test.tsx — 33 passed

  • vp run -F @t3tools/web typecheck — clean

  • gitHubPullRequestBrowserUrl builds a URL that gets opened in a browser, so I
    mutation-probed its two guards rather than trusting the tests existed:

    • dropping the ./.. path-segment check produces
      https://github.com/repository/pull/1 where null is expected — caught;
    • dropping the http:/https: protocol allowlist breaks the SCP-style remote
      path — caught.

    Both guards are therefore genuinely covered, in both directions.

Before/after image pending the consolidated real-client pass for this batch.
Upstream's own before/after screenshots are on pingdotgg/t3code#8507.

Claude Opus 5 via Claude Code.


View with [code]smithAutofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

@github-actionsgithub-actionsBot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:M labels Aug 28, 2026
@github-actions

github-actionsBot commented Aug 28, 2026

Copy link
Copy Markdown

Thread transfer impact

✅ Thread transfer remains within every enforced ceiling.

ProviderMetricMain baselineThis PRImpactPR ceiling
CodexTotal thread wire13.3 KiB13.3 KiB−6 B (−0.0%)15.1 KiB
CodexThread snapshot wire6.9 KiB6.9 KiB−7 B (−0.1%)7.3 KiB
CodexLive turn WebSocket wire6.4 KiB6.4 KiB+1 B (+0.0%)7.8 KiB
CodexLive turn WebSocket decoded55.5 KiB55.5 KiB0 B (0.0%)66.4 KiB
CodexLive turn messages990 (0.0%)21
ClaudeTotal thread wire13.3 KiB13.3 KiB−63 B (−0.5%)15.1 KiB
ClaudeThread snapshot wire6.9 KiB6.9 KiB+6 B (+0.1%)7.3 KiB
ClaudeLive turn WebSocket wire6.5 KiB6.4 KiB−69 B (−1.0%)7.8 KiB
ClaudeLive turn WebSocket decoded56.4 KiB56.3 KiB−88 B (−0.2%)66.4 KiB
ClaudeLive turn messages119−2 (−18.2%)21

Baseline: 3d6035f · PR result: 42a669e · Source CI: success

Scenario and decoded snapshot size

10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.

  • Codex decoded thread snapshot: 109.4 KiB
  • Claude decoded thread snapshot: 110.1 KiB

Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.

@rynfar

Copy link
Copy Markdown
CollaboratorAuthor

Independent review pass. Two findings — one fixed, one documented.

Fixed in d7109b3ec — the other pull request error surface was a dead end.
The thread right panel shows a second PullRequestsUnavailableState when the
environment's server is too old to browse pull requests, with no retry and no
GitHub link. That contradicted the docs sentence this branch adds, which promises
the button whenever Pylon cannot load a GitHub pull request. The surface already
carries projectId, repository, and number, and ChatView already reads every
project, so it now builds the link with the same helper and the same
conditional-spread pattern the detail panel uses.

Documented — self-hosted GitHub installs still get no button. The helper gates
on identity.provider === "github". A self-hosted GitHub Enterprise host without
a github DNS label carries provider: "unknown", yet the server serves its pull
requests as GitHub after refineUnknownProjectKinds
(PullRequestService.ts:493-588). So the panel works normally and only the error
view comes up empty. Upstream's gating; widening it means deciding what
provider: "unknown" should imply for URL construction, which is a bigger call
than this PR.

The review cleared the parts that mattered: SCP and git:// remotes fall back to
the canonical host, malformed hosts and repository paths return null, credentials
are stripped via URL.origin, non-GitHub providers are correctly excluded,
url.pathname assignment percent-encodes stray characters, and Electron's
setWindowOpenHandler means target="_blank" really does reach the system
browser on desktop.

t3dotggand others added 2 commits August 28, 2026 20:55
A GitHub API error left the pull request view with only Retry, even though the
pull request was still perfectly reachable on GitHub. Rate limiting is the
common case.
The error view now offers Open on GitHub, built from the saved project host and
pull request reference with no extra API call, so it works precisely when the
API does not. Error states for GitLab, Bitbucket, Azure DevOps, and unknown
providers are unchanged.
Adopted from T3 Code 7068e86f76e908c77ff04d1a684840257eab3a8a
(pingdotgg/t3code#8507).
Adaptation: one conflict in docs/user/source-control.md, where upstream's new
bullet named T3 Code twice. Resolved Pylon-first, keeping Pylon's product name
and its existing command-click bullet.
…e too
Review follow-up. The thread right panel has a second pull request error state,
shown when the environment's server is too old to browse pull requests, and it
rendered with no retry and no GitHub link. That made it a dead end, and it
contradicted the docs sentence this branch added, which promises the button
whenever Pylon cannot load a GitHub pull request.
The surface already carries projectId, repository, and number, and ChatView
already reads every project, so the link is built with the same helper and the
same conditional-spread pattern the detail panel uses. A pull request stays
readable on GitHub whether the failure was an API error or an old server.
@rynfar
rynfarforce-pushed the upstream/2026-08-28-pr-open-on-github branch from d7109b3 to 42a669eCompareAugust 29, 2026 02:55
@rynfar
rynfar merged commit 92dce5a into pylonAug 29, 2026
15 checks passed
@rynfar
rynfar deleted the upstream/2026-08-28-pr-open-on-github branch August 29, 2026 03:04
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:Mvouch:trustedPR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@rynfar@t3dotgg