Repository navigation
fix: preserve percent-encoded path in DisplayURL - #13788
happysnaker wants to merge 1 commit into
Conversation
|
Thanks for your pull request! While it doesn't meet all of our standard requirements, it appears to be a small, focused contribution and has been routed to the team for review. Note: We still encourage linking to an issue with the |
5ef3685 to
2537a3b
Compare
|
The build failures on macOS/Windows/Ubuntu appear to be pre-existing infrastructure issues unrelated to this change. The lint, govulncheck, and all integration tests pass. The change is local to |
| // Preserve percent-encoding from the original URL path | ||
| if u.RawPath != "" { | ||
| path = u.RawPath | ||
| } |
There was a problem hiding this comment.
u.RawPath is only populated when the raw path differs from the default escaping of u.Path, so this misses the common case. e.g. https://x/a%20b decodes Path to "a b" whose canonical escape is "a%20b", which matches raw, so RawPath stays "" and you fall back to the decoded Path. u.EscapedPath() handles both and is what you want here.
cc-web の subscribe_pr_activity が無い環境向けに、コメントの作成・編集、review、CI の失敗、PR の close を 1 行 1 イベントで出すポーリングループを gh.md に置き、Monitor ツールで回す形にする。前回見た内容を状態ファイルに残すので、Monitor が 30 分で失効しても同じファイルで再起動すれば続きから見る。PR が閉じたら、開始時点で既に閉じていた場合も含めて 1 行出して終わる。 HTTP は gh api でなく curl で送る。Monitor は Bash と同じサンドボックス内で動き、macOS ではサンドボックス内の gh api が TLS 検証に失敗する (SSL_CERT_FILE を指定しても同じ。gh auth token と curl は通る)。 実測は gh.md に書いたコードブロックを取り出したものでサンドボックス内で行った: 新規コメント・コメント編集 (状態ファイルを前回に見せかけて検出)、前回 open だった閉じた PR、開始時点で閉じている PR、cli/cli#13788 の CI 失敗 3 件。Monitor から通知として届くことも確認した。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
cc-web の subscribe_pr_activity が無い環境向けに、コメントの作成・編集、review、CI の失敗、PR の close を 1 行 1 イベントで出すポーリングループを gh.md に置き、Monitor ツールで回す形にする。前回見た内容を状態ファイルに残すので、Monitor が 30 分で失効しても同じファイルで再起動すれば続きから見る。PR が閉じたら、開始時点で既に閉じていた場合も含めて 1 行出して終わる。 HTTP は gh api でなく curl で送る。Monitor は Bash と同じサンドボックス内で動き、macOS ではサンドボックス内の gh api が TLS 検証に失敗する (SSL_CERT_FILE を指定しても同じ。gh auth token と curl は通る)。 実測は gh.md に書いたコードブロックを取り出したものでサンドボックス内で行った: 新規コメント・コメント編集 (状態ファイルを前回に見せかけて検出)、前回 open だった閉じた PR、開始時点で閉じている PR、cli/cli#13788 の CI 失敗 3 件。Monitor から通知として届くことも確認した。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
gh が無い環境の curl のフォールバックで check 名をクエリに直接書いていたので、Actions で普通にある `build (ubuntu-latest)` のような空白入りの名前では curl が URL rejected で失敗し、& を含む名前ではクエリが壊れる (Codex Review の指摘)。--get --data-urlencode で渡す形にし、トークンは標準入力から -H @- で渡すと明記する。cli/cli#13788 で、直接書くと URL rejected、--data-urlencode では `build (ubuntu-latest)` の run が 1 件返ることを確認した。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* verify.ts: コメントを修正 * pr-workflow: 同じ名前の check run を全部待ち、watch で再実行に置き換えられた失敗も拾う check 待ち: 同じ名前の check run が複数あると (別の workflow や GitHub App が同じ名前で作る)、どれか 1 つが completed になった時点で抜けていた (Codex Review の指摘)。check_name で絞って取り、1 件以上あり全部が completed になるまで待つ。終了コードの判定は command grep にする。Claude Code の Bash ツールでは grep が組み込みの ugrep を呼ぶ関数に置き換えられ、-q と -v を併用したときの終了コードが本物と逆になり、未完了の run があっても抜けた (zsh と bash の両方で判定式を試して確認)。 watch: Checks API の check-runs は filter の既定が latest で、再実行で置き換えられた run を返さない (docs)。ポーリングの合間や Monitor の再起動中に失敗した run が再実行で成功すると、その失敗を見逃していた (Codex Review の指摘)。filter=all で取る。denoland/deno の 6c924f8 で、latest では 1 件、all では 2 件になり、all にだけ置き換えられた failure が出ることを確認した。get がクエリ付きのパスを受け取れるようにする。 gh.md に書いた check 待ちのループをそのまま取り出し、空白を含む check 名で結果を返すこと、無い check 名で timeout になることを確認した。watch のスクリプトも取り出したものが試験したものと一致し、サンドボックス内で CI 失敗・閉じた PR・新規コメントの検出が変わらないことを確認した。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * cc-web の subscribe_pr_activity の配送を実測に合わせて書き直す canon: facts/claude-code/subscribe-pr-activity-events (#13 を 2026-09-16/17 に購読して記録) の実測で、未確定・古いままだった記述を直す。 - CI の成功は届く。ただし head の SHA ごとに 1 回だけの check suite のロールアップで、conclusion を持たない。同じコミットの再実行で緑になっても届かない。失敗は check run ごとに毎回届く。 - push、label などのメタデータ変更、merge conflict は届かない。 - get_status は Actions だけのリポでは緑でも pending / 0 件を返すので CI の判定に使わない。 - スレッドの PRRT_… は payload に無いので取り直す。comment_id はそのまま返信に使える。 - close で購読が解除され、reopen で再購読される。 cc-web-sandbox-signals の他の箇所も、同じ時期の cc-web の実測と矛盾していたので直す: mcp__github__ には get_job_logs がある (呼び方も書く)、2026-09-16 のセッションでは GH_TOKEN / GITHUB_TOKEN が設定され git push が通った、CI 成功を PR コメントで中継する必要があるのは同じコミットの再実行を待つときだけ。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * cc-web-sandbox-signals: description をいつ使うかだけの 1 行にする 中身の要約 (配送の癖、到達表、create-then-sweep、Monitor) と例文が並び、スキル一覧で毎回読み込まれる description として長すぎた。発火の条件 (cc-web のセッションで PR や CI のイベントを待つ、外部イベントを受ける、egress のエラー、Monitor) と、ローカル CLI 側 (cc-cli-sandbox) と取り違えないための一文だけを残す。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * pr-workflow: github-mcp-server の CI 確認を、push したコミットの SHA 指定で読む形にする get_check_runs の結果には run ごとのコミットの SHA が無く、呼び出しの内部で PR の head を読むので、push 直後は前のコミットの run を返しうる。head の照合を前後に挟んでも内部の読みは保証されず、started_at で絞ってもキュー待ちや needs: で後から始まった前のコミットの run と区別できない (自己レビューで指摘が続いた)。push したコミットの成功は get_check_runs では判定せず、git ls-remote で読んだ SHA を指定して Checks API を読む (gh があれば gh.md の手順、無ければトークンで curl)。どちらもできなければ確かめられなかったと報告する。旧来の commit status は、get_status が返す sha が push したコミットと一致するときだけ使う (github-mcp-server で sha を返すことを確認)。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * pr-workflow: watch スクリプトのコメントから外部システムの挙動の主張を外す watch スクリプトの 2 つのコメント (Checks API の filter の既定の挙動、コマンド引数が ps で他のユーザーから見えること) は、外部システムの観測可能な挙動を主張していて、writing-comments の規約 (そういうコメントは書かず、落ちるテストで固定する) に反していた (Codex Review の指摘)。コメントを外し、理由はスクリプトの下の注記に書く。スクリプトのロジックは変えていない。gh.md から取り出したものが試験したものと一致し、閉じた PR と CI 失敗の検出が変わらないことを確認した。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * pr-workflow: curl のフォールバックで check 名を URL エンコードして渡す gh が無い環境の curl のフォールバックで check 名をクエリに直接書いていたので、Actions で普通にある `build (ubuntu-latest)` のような空白入りの名前では curl が URL rejected で失敗し、& を含む名前ではクエリが壊れる (Codex Review の指摘)。--get --data-urlencode で渡す形にし、トークンは標準入力から -H @- で渡すと明記する。cli/cli#13788 で、直接書くと URL rejected、--data-urlencode では `build (ubuntu-latest)` の run が 1 件返ることを確認した。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * pr-workflow / cc-web-sandbox-signals: 外部の性質の説明を canon に移し、本文は指示と参照にする スキルの利用者が行動するのに要らない、外部システムの性質や実測の経緯 (push 直後の head の遅れ、get_check_runs の返り値に SHA が無いこと、Monitor がサンドボックス内で動き gh api が TLS で失敗すること、ps で引数が見えること、Checks API の filter の既定、grep の置き換え、subscribe_pr_activity の配送の測定条件や過去の観測) を本文から外し、canon の該当ページ (新設 4 ページを含む) への参照にする。本文には手順と、誤って書き換えられやすい箇所の「こうしない」だけを残す。watch スクリプトは変えていない。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * pr-workflow / cc-web-sandbox-signals: 行動に要る注意 (自分のコメントの配送・PR Steward・status の state・新規コメント) を本文に戻す Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * pr-workflow / cc-web-sandbox-signals: get_status の sha 欠落を cc-web の実装に限定し、根拠の canon を正す Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * pr-workflow / cc-web-sandbox-signals: cc-web の get_status の sha は未確認と書く (観測の実装が特定できないため) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * cc-web-sandbox-signals: 普通は要らない create-then-sweep を別ファイルに出し、本文からリンクする Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * authoring-skills: スキルの書き方のスキルを足す description はトリガーだけ、本文は行動に要る指示だけ (外部の性質は canon)、普通は要らない内容は別ファイルに出す、を書く。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * authoring-skills: 自然言語の書き方の参照先を REVIEW.md に直す Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * authoring-skills / setup-repo: 本文に書くかは実行者に要るかで決め、canon を読めない前提で写さない cc-web でも add_repo で canon を足せば読める (canon: facts/claude-code/cc-web-session-repo-scope)。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * pr-workflow / cc-web-sandbox-signals: 実行者に要るが canon にしか無かった注意を本文に足す gh pr checks の check 0 件での exit 1、PR Steward 監視中は配送されないこと、トークンを標準入力で渡すこと。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * pr-workflow / cc-web-sandbox-signals: 標準入力で渡すのはトークンでなくヘッダー行だと書き、create-then-sweep もそうする Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * authoring-skills: 規則から採らない基準の否定・帰結・事情を削る Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * cc-web-sandbox-signals: 2 節以降を実行者に要る指示にし、到達範囲の実測は canon に移す 到達範囲の表と CLI との違いは canon: facts/claude-code/cc-web-egress-proxy。WebSocket の橋は普通は要らないので別ファイルにする。 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * cc-web-sandbox-signals / cc-cli-sandbox: 接続先のエラーの見分け方を実測どおりに戻し、移した到達範囲の表への言及を外す Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
## Why Getting a PR to green is a repeated chore with no skill behind it. `ship-changes` opened PRs and, when landing, did one background `gh pr checks --watch`. The `do` playbooks stopped at "ship". Nothing waited for checks, classified a failure, or fixed one from the PR's own diff and waited again. I merge after reviewing the diff on GitHub myself, so this has to stop at green and hand the PR back, not merge it. This adds `babysit-pr`, modelled on tstack's [`babysit-pr`](https://github.com/t3dotgg/tstack/tree/main/skills/babysit-pr) and pstack's babysit playbook, cut down to checks. It waits with T3 Code's `watch_pull_request`, or elsewhere with a bundled `gh` script. It reads the failed log, classifies the failure, fixes failures from the PR's own diff, and replies with the PR link once the checks pass on the latest head. ## Scope - `skills/babysit-pr/SKILL.md` (model-invoked: "babysit", "watch", "monitor" a PR, "get it green"): - Find the PR. A delegated child reports back instead of watching. - Wait. In T3 Code with `watch_pull_request`, elsewhere with `scripts/wait-green`, and never in a hand-rolled sleep loop. - Classify each failure into one of four cases: - the PR's own code: fix it and push once; - code the PR doesn't touch while the branch is behind its base: `gh pr update-branch`, which merges the base in without a force-push; - a flake: rerun once; - anything else: report and stop. - An expired log (HTTP 410) gets a rerun to produce a fresh log. Babysitting stops after three fix pushes that each fail again. - Hand back the PR link, its check state, the fixes and reruns, review comments (listed, not acted on) and how far it is behind its base. It merges only on an explicit ask, through Landing. - `skills/babysit-pr/scripts/wait-green <pr> [--repo owner/name]`: waits for checks to register on the head, then runs `gh pr checks --watch --fail-fast`. It pauses one more interval for workflows that register late, then prints one line. Exit 0 = green or merged, 1 = needs you (failed check, conflict, closed), 2 = bad input or no CI within 5 minutes. Bash 3.2 compatible. - `do` playbooks: - `build` step 9 ships, then babysits, and its Reply includes the babysit reply. - `design` step 6 now points to `build`'s steps 5–9 instead of repeating its ship step. - `general` runs `babysit-pr` for babysit requests, and answers a one-off "is it green" with `gh pr checks`. - The `do` table lists babysitting under general. - `ship-changes/references/landing.md`: the inline wait-and-fix steps after arming auto-merge now point to `babysit-pr`, so failure handling lives in one place. - Left out: - acting on review comments and bot-triage rules; - stack and merge-frontier handling; - review-bot gating, as in tstack's `--until ready`. ## Tradeoffs - **A small `gh` wrapper instead of tstack's `pr-wait`.** `pr-wait` is a 550-line Python poller that also tracks comments, review bots and base moves. For checks only, `gh pr checks --watch` does the watching. The script covers what `gh` misses: - a just-pushed head reports "no checks" until CI registers; - a workflow can register after the others finish; - a branch can be behind its base without GitHub saying so. - **Counting `behind_by` instead of trusting `mergeStateStatus`.** GitHub reports `BEHIND` only when nothing else blocks the merge. On a PR with failing checks it says `BLOCKED` even when the branch is behind, which the cold runs hit. - **Merging the base in rather than rebasing a stale branch.** `gh pr update-branch` needs no force-push. A stack is reported instead of updated. ## Blast radius This only changes skill text and one new script. `build` and `design` runs that ship now keep going until the checks are green, instead of stopping once the PR is open. `ship-changes` Landing now hands its wait to `babysit-pr`. If `babysit-pr` isn't installed, the agent skips that step and the PR is still open on GitHub. ## Verification - `skills/create-skill/scripts/check-skill.sh skills/babysit-pr skills/do skills/ship-changes`: passes. - `wait-green` against real PRs: - green (cli/cli#14858): exit 0 with `12 pass, 8 skipping; 0 commits behind trunk`; - merged (rigomart/phonaria#386): exit 0; - failing (cli/cli#13788): exit 1 with each failed job's link; - missing argument, unknown flag, unknown PR: exit 2. - The "no checks within 5 minutes" path hasn't been run. - Two fresh agents ran the skill read-only on vercel/next.js#100860, a README change failing `lint / build`. Both read the log and reproduced the Prettier failure in the PR's own file with the repo's pinned Prettier. Both classified it as the PR's own code, with the same one-line fix and no rerun. They also showed the branch 3 commits behind while `mergeStateStatus` said `BLOCKED`, which led to the `behind_by` count. - Not yet run on a real babysit with fix pushes, or with T3 Code's watcher. One cold run's auto-mode classifier blocked `wait-green` as an external write, even though it only reads.
Summary
Fixes #13546
DisplayURLwas usingu.Pathwhich is the unescaped version of the URL path. This caused branch names with special characters (like quotes) to be displayed incorrectly in the terminal when usinggh pr create --web.For example, a branch named
test-"quoted"-branch-prwould display as:Instead of the correct:
Changes
Uses
u.RawPath(when available) instead ofu.Pathto preserve the original percent-encoding from the URL.