fix(ci): disable uv cache for release-consistency job - #6
Merged
Conversation
The release-consistency job runs only check-release-consistency.py, which is stdlib-only (tomllib/re/argparse) and never invokes uv. No uv cache directory is therefore created. setup-uv v9 fails its post step when told to save a cache path that does not exist on disk: Cache path /home/runner/work/_temp/setup-uv-cache does not exist on disk. The check itself passed; only the cleanup step failed, which still failed the job. This surfaced after bumping setup-uv v4 -> v9 in #5. It passed on that PR's run and failed on the post-merge main run, so it is timing-dependent on whether a cache was restored, not deterministic. Set enable-cache: false for this job only. Every other setup-uv job runs uv sync or uv build and legitimately populates the cache.
There was a problem hiding this comment.
Pull request overview
This PR fixes a CI failure in the release-consistency job by preventing astral-sh/setup-uv from attempting to save a cache that is never created in that job (since it only runs a stdlib-only Python script and does not invoke uv).
Changes:
- Disabled
setup-uvcaching for therelease-consistencyjob viaenable-cache: false. - Added inline rationale in the workflow explaining why caching must be disabled for this specific job.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
NetDevAutomate
added a commit
that referenced
this pull request
Sep 3, 2026
…cache fix(ci): disable uv cache for release-consistency job
NetDevAutomate
added a commit
that referenced
this pull request
Sep 3, 2026
POST /api/session/start now routes through transport=pty by default, calling active.acquire(config, PTYTransport) and returning a ws_url the frontend feeds to /api/session/ws. The legacy tmux+ttyd path is reachable via transport=ttyd in the body or STUDYLOOP_TRANSPORT=ttyd env override (operator kill-switch). Why: closes the §1.5b gap flagged in Amendment #5 — without this bridge, the new WS route was reachable by tests only. Now the full request path works: picker POSTs /session/start → server acquires active session + PTYTransport → returns ws_url → browser opens WS and gets live PTY stream. Transport dispatch: - Body field ``transport: pty|ttyd`` (optional, default pty). - STUDYLOOP_TRANSPORT env wins over body — operator emergency switch per plan §1.9 without touching clients. - On pty path: no tmux check, no ttyd spawn, no tmux metadata in session_state.json. Writes transport=pty into state for clarity. Binary missing (503) now returns a structured payload: {error, agent, binary, install_hint}. Hints cover all five registered agents (claude, codex, gemini, kiro, opencode) so the UI — or an agent orchestrating installs — has a concrete next step. Per-agent "self-heal and retry" is §1.10 follow-up. Adapter shell wrapping: PTYTransport's build_launch_cmd returns ["/bin/sh", "-c", adapter.launch_cmd(...)]. Adapters legitimately use pipes/&& (their launch_cmd returns shell strings), so we execvpe /bin/sh instead of splitting via shlex. Mirrors what tmux send-keys effectively did. Tests: - +5 in test_web_session_start_pty.py: happy path returns ws_url and bypasses tmux, pty-is-default when unset, 409 when active, 503 with install_hint, env=ttyd overrides body=pty (routes to legacy branch and trips the tmux check). - Existing test_web_session.py: 4 legacy guard tests updated to pass transport=ttyd explicitly — they were testing tmux-based semantics that only apply to that branch now. 1985 passed, 145 deselected (was 1980 → +5 net). Ruff + format clean. Plan: Amendment #5 "§1.5b REST→PTY bridge" follow-up is now closed. Amendment #6 (below) documents the contract for §1.7 frontend. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
NetDevAutomate
added a commit
that referenced
this pull request
Sep 3, 2026
Drops the latest-stable @xterm/xterm UMD bundle, @xterm/addon-fit, @xterm/addon-webgl, and xterm.css into web/static/vendor/ and loads them from index.html. No Alpine component yet — that's §1.7 and ships in its own PR so the frontend iteration can proceed alone. Why: unblocks §1.7's agentTerminal() component. With the UMD globals (Terminal, FitAddon, WebglAddon) available at DOMContentLoaded time, the component can mount into a <div> and pipe the /api/session/ws stream directly — no ESM, no build step, no service worker rewrites. Files vendored (versions pinned in index.html): - xterm-6.0.0.js (477 KB, UMD) - xterm-6.0.0.css (7 KB) - xterm-addon-fit-0.11.0.js (1.5 KB) - xterm-addon-webgl-0.19.0.js (242 KB) Load order matters: xterm-6.0.0.js defers first, then the two addons defer after it. test_xterm_umd_bundles_load_in_correct_order locks this so a future reorder can't silently break addon init. Plus Amendment #6 to the refactor plan documenting §1.5b + §1.6 landing and the §1.7 frontend contract (ws_url from /session/start is the exact string to feed new WebSocket). Tests: +7 smoke tests (test_web_vendor_xterm.py) — file presence, size sanity (>1KB JS, >500B CSS), index.html references, and script load order. 1992 passed total (1985 → 1992). Ruff + format clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
NetDevAutomate
added a commit
that referenced
this pull request
Sep 3, 2026
…cache fix(ci): disable uv cache for release-consistency job
NetDevAutomate
added a commit
that referenced
this pull request
Sep 3, 2026
POST /api/session/start now routes through transport=pty by default, calling active.acquire(config, PTYTransport) and returning a ws_url the frontend feeds to /api/session/ws. The legacy tmux+ttyd path is reachable via transport=ttyd in the body or STUDYLOOP_TRANSPORT=ttyd env override (operator kill-switch). Why: closes the §1.5b gap flagged in Amendment #5 — without this bridge, the new WS route was reachable by tests only. Now the full request path works: picker POSTs /session/start → server acquires active session + PTYTransport → returns ws_url → browser opens WS and gets live PTY stream. Transport dispatch: - Body field ``transport: pty|ttyd`` (optional, default pty). - STUDYLOOP_TRANSPORT env wins over body — operator emergency switch per plan §1.9 without touching clients. - On pty path: no tmux check, no ttyd spawn, no tmux metadata in session_state.json. Writes transport=pty into state for clarity. Binary missing (503) now returns a structured payload: {error, agent, binary, install_hint}. Hints cover all five registered agents (claude, codex, gemini, kiro, opencode) so the UI — or an agent orchestrating installs — has a concrete next step. Per-agent "self-heal and retry" is §1.10 follow-up. Adapter shell wrapping: PTYTransport's build_launch_cmd returns ["/bin/sh", "-c", adapter.launch_cmd(...)]. Adapters legitimately use pipes/&& (their launch_cmd returns shell strings), so we execvpe /bin/sh instead of splitting via shlex. Mirrors what tmux send-keys effectively did. Tests: - +5 in test_web_session_start_pty.py: happy path returns ws_url and bypasses tmux, pty-is-default when unset, 409 when active, 503 with install_hint, env=ttyd overrides body=pty (routes to legacy branch and trips the tmux check). - Existing test_web_session.py: 4 legacy guard tests updated to pass transport=ttyd explicitly — they were testing tmux-based semantics that only apply to that branch now. 1985 passed, 145 deselected (was 1980 → +5 net). Ruff + format clean. Plan: Amendment #5 "§1.5b REST→PTY bridge" follow-up is now closed. Amendment #6 (below) documents the contract for §1.7 frontend. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
NetDevAutomate
added a commit
that referenced
this pull request
Sep 3, 2026
Drops the latest-stable @xterm/xterm UMD bundle, @xterm/addon-fit, @xterm/addon-webgl, and xterm.css into web/static/vendor/ and loads them from index.html. No Alpine component yet — that's §1.7 and ships in its own PR so the frontend iteration can proceed alone. Why: unblocks §1.7's agentTerminal() component. With the UMD globals (Terminal, FitAddon, WebglAddon) available at DOMContentLoaded time, the component can mount into a <div> and pipe the /api/session/ws stream directly — no ESM, no build step, no service worker rewrites. Files vendored (versions pinned in index.html): - xterm-6.0.0.js (477 KB, UMD) - xterm-6.0.0.css (7 KB) - xterm-addon-fit-0.11.0.js (1.5 KB) - xterm-addon-webgl-0.19.0.js (242 KB) Load order matters: xterm-6.0.0.js defers first, then the two addons defer after it. test_xterm_umd_bundles_load_in_correct_order locks this so a future reorder can't silently break addon init. Plus Amendment #6 to the refactor plan documenting §1.5b + §1.6 landing and the §1.7 frontend contract (ws_url from /session/start is the exact string to feed new WebSocket). Tests: +7 smoke tests (test_web_vendor_xterm.py) — file presence, size sanity (>1KB JS, >500B CSS), index.html references, and script load order. 1992 passed total (1985 → 1992). Ruff + format clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
NetDevAutomate
added a commit
that referenced
this pull request
Sep 3, 2026
POST /api/session/start now routes through transport=pty by default, calling active.acquire(config, PTYTransport) and returning a ws_url the frontend feeds to /api/session/ws. The legacy tmux+ttyd path is reachable via transport=ttyd in the body or STUDYLOOP_TRANSPORT=ttyd env override (operator kill-switch). Why: closes the §1.5b gap flagged in Amendment #5 — without this bridge, the new WS route was reachable by tests only. Now the full request path works: picker POSTs /session/start → server acquires active session + PTYTransport → returns ws_url → browser opens WS and gets live PTY stream. Transport dispatch: - Body field ``transport: pty|ttyd`` (optional, default pty). - STUDYLOOP_TRANSPORT env wins over body — operator emergency switch per plan §1.9 without touching clients. - On pty path: no tmux check, no ttyd spawn, no tmux metadata in session_state.json. Writes transport=pty into state for clarity. Binary missing (503) now returns a structured payload: {error, agent, binary, install_hint}. Hints cover all five registered agents (claude, codex, gemini, kiro, opencode) so the UI — or an agent orchestrating installs — has a concrete next step. Per-agent "self-heal and retry" is §1.10 follow-up. Adapter shell wrapping: PTYTransport's build_launch_cmd returns ["/bin/sh", "-c", adapter.launch_cmd(...)]. Adapters legitimately use pipes/&& (their launch_cmd returns shell strings), so we execvpe /bin/sh instead of splitting via shlex. Mirrors what tmux send-keys effectively did. Tests: - +5 in test_web_session_start_pty.py: happy path returns ws_url and bypasses tmux, pty-is-default when unset, 409 when active, 503 with install_hint, env=ttyd overrides body=pty (routes to legacy branch and trips the tmux check). - Existing test_web_session.py: 4 legacy guard tests updated to pass transport=ttyd explicitly — they were testing tmux-based semantics that only apply to that branch now. 1985 passed, 145 deselected (was 1980 → +5 net). Ruff + format clean. Plan: Amendment #5 "§1.5b REST→PTY bridge" follow-up is now closed. Amendment #6 (below) documents the contract for §1.7 frontend. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
NetDevAutomate
added a commit
that referenced
this pull request
Sep 3, 2026
Drops the latest-stable @xterm/xterm UMD bundle, @xterm/addon-fit, @xterm/addon-webgl, and xterm.css into web/static/vendor/ and loads them from index.html. No Alpine component yet — that's §1.7 and ships in its own PR so the frontend iteration can proceed alone. Why: unblocks §1.7's agentTerminal() component. With the UMD globals (Terminal, FitAddon, WebglAddon) available at DOMContentLoaded time, the component can mount into a <div> and pipe the /api/session/ws stream directly — no ESM, no build step, no service worker rewrites. Files vendored (versions pinned in index.html): - xterm-6.0.0.js (477 KB, UMD) - xterm-6.0.0.css (7 KB) - xterm-addon-fit-0.11.0.js (1.5 KB) - xterm-addon-webgl-0.19.0.js (242 KB) Load order matters: xterm-6.0.0.js defers first, then the two addons defer after it. test_xterm_umd_bundles_load_in_correct_order locks this so a future reorder can't silently break addon init. Plus Amendment #6 to the refactor plan documenting §1.5b + §1.6 landing and the §1.7 frontend contract (ws_url from /session/start is the exact string to feed new WebSocket). Tests: +7 smoke tests (test_web_vendor_xterm.py) — file presence, size sanity (>1KB JS, >500B CSS), index.html references, and script load order. 1992 passed total (1985 → 1992). Ruff + format clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
NetDevAutomate
added a commit
that referenced
this pull request
Sep 3, 2026
…cache fix(ci): disable uv cache for release-consistency job
NetDevAutomate
added a commit
that referenced
this pull request
Sep 3, 2026
…cache fix(ci): disable uv cache for release-consistency job
NetDevAutomate
added a commit
that referenced
this pull request
Sep 3, 2026
POST /api/session/start now routes through transport=pty by default, calling active.acquire(config, PTYTransport) and returning a ws_url the frontend feeds to /api/session/ws. The legacy tmux+ttyd path is reachable via transport=ttyd in the body or STUDYLOOP_TRANSPORT=ttyd env override (operator kill-switch). Why: closes the §1.5b gap flagged in Amendment #5 — without this bridge, the new WS route was reachable by tests only. Now the full request path works: picker POSTs /session/start → server acquires active session + PTYTransport → returns ws_url → browser opens WS and gets live PTY stream. Transport dispatch: - Body field ``transport: pty|ttyd`` (optional, default pty). - STUDYLOOP_TRANSPORT env wins over body — operator emergency switch per plan §1.9 without touching clients. - On pty path: no tmux check, no ttyd spawn, no tmux metadata in session_state.json. Writes transport=pty into state for clarity. Binary missing (503) now returns a structured payload: {error, agent, binary, install_hint}. Hints cover all five registered agents (claude, codex, gemini, kiro, opencode) so the UI — or an agent orchestrating installs — has a concrete next step. Per-agent "self-heal and retry" is §1.10 follow-up. Adapter shell wrapping: PTYTransport's build_launch_cmd returns ["/bin/sh", "-c", adapter.launch_cmd(...)]. Adapters legitimately use pipes/&& (their launch_cmd returns shell strings), so we execvpe /bin/sh instead of splitting via shlex. Mirrors what tmux send-keys effectively did. Tests: - +5 in test_web_session_start_pty.py: happy path returns ws_url and bypasses tmux, pty-is-default when unset, 409 when active, 503 with install_hint, env=ttyd overrides body=pty (routes to legacy branch and trips the tmux check). - Existing test_web_session.py: 4 legacy guard tests updated to pass transport=ttyd explicitly — they were testing tmux-based semantics that only apply to that branch now. 1985 passed, 145 deselected (was 1980 → +5 net). Ruff + format clean. Plan: Amendment #5 "§1.5b REST→PTY bridge" follow-up is now closed. Amendment #6 (below) documents the contract for §1.7 frontend. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
NetDevAutomate
added a commit
that referenced
this pull request
Sep 3, 2026
Drops the latest-stable @xterm/xterm UMD bundle, @xterm/addon-fit, @xterm/addon-webgl, and xterm.css into web/static/vendor/ and loads them from index.html. No Alpine component yet — that's §1.7 and ships in its own PR so the frontend iteration can proceed alone. Why: unblocks §1.7's agentTerminal() component. With the UMD globals (Terminal, FitAddon, WebglAddon) available at DOMContentLoaded time, the component can mount into a <div> and pipe the /api/session/ws stream directly — no ESM, no build step, no service worker rewrites. Files vendored (versions pinned in index.html): - xterm-6.0.0.js (477 KB, UMD) - xterm-6.0.0.css (7 KB) - xterm-addon-fit-0.11.0.js (1.5 KB) - xterm-addon-webgl-0.19.0.js (242 KB) Load order matters: xterm-6.0.0.js defers first, then the two addons defer after it. test_xterm_umd_bundles_load_in_correct_order locks this so a future reorder can't silently break addon init. Plus Amendment #6 to the refactor plan documenting §1.5b + §1.6 landing and the §1.7 frontend contract (ws_url from /session/start is the exact string to feed new WebSocket). Tests: +7 smoke tests (test_web_vendor_xterm.py) — file presence, size sanity (>1KB JS, >500B CSS), index.html references, and script load order. 1992 passed total (1985 → 1992). Ruff + format clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
NetDevAutomate
added a commit
that referenced
this pull request
Sep 3, 2026
…cache fix(ci): disable uv cache for release-consistency job
NetDevAutomate
added a commit
that referenced
this pull request
Sep 3, 2026
POST /api/session/start now routes through transport=pty by default, calling active.acquire(config, PTYTransport) and returning a ws_url the frontend feeds to /api/session/ws. The legacy tmux+ttyd path is reachable via transport=ttyd in the body or STUDYLOOP_TRANSPORT=ttyd env override (operator kill-switch). Why: closes the §1.5b gap flagged in Amendment #5 — without this bridge, the new WS route was reachable by tests only. Now the full request path works: picker POSTs /session/start → server acquires active session + PTYTransport → returns ws_url → browser opens WS and gets live PTY stream. Transport dispatch: - Body field ``transport: pty|ttyd`` (optional, default pty). - STUDYLOOP_TRANSPORT env wins over body — operator emergency switch per plan §1.9 without touching clients. - On pty path: no tmux check, no ttyd spawn, no tmux metadata in session_state.json. Writes transport=pty into state for clarity. Binary missing (503) now returns a structured payload: {error, agent, binary, install_hint}. Hints cover all five registered agents (claude, codex, gemini, kiro, opencode) so the UI — or an agent orchestrating installs — has a concrete next step. Per-agent "self-heal and retry" is §1.10 follow-up. Adapter shell wrapping: PTYTransport's build_launch_cmd returns ["/bin/sh", "-c", adapter.launch_cmd(...)]. Adapters legitimately use pipes/&& (their launch_cmd returns shell strings), so we execvpe /bin/sh instead of splitting via shlex. Mirrors what tmux send-keys effectively did. Tests: - +5 in test_web_session_start_pty.py: happy path returns ws_url and bypasses tmux, pty-is-default when unset, 409 when active, 503 with install_hint, env=ttyd overrides body=pty (routes to legacy branch and trips the tmux check). - Existing test_web_session.py: 4 legacy guard tests updated to pass transport=ttyd explicitly — they were testing tmux-based semantics that only apply to that branch now. 1985 passed, 145 deselected (was 1980 → +5 net). Ruff + format clean. Plan: Amendment #5 "§1.5b REST→PTY bridge" follow-up is now closed. Amendment #6 (below) documents the contract for §1.7 frontend. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
NetDevAutomate
added a commit
that referenced
this pull request
Sep 3, 2026
Drops the latest-stable @xterm/xterm UMD bundle, @xterm/addon-fit, @xterm/addon-webgl, and xterm.css into web/static/vendor/ and loads them from index.html. No Alpine component yet — that's §1.7 and ships in its own PR so the frontend iteration can proceed alone. Why: unblocks §1.7's agentTerminal() component. With the UMD globals (Terminal, FitAddon, WebglAddon) available at DOMContentLoaded time, the component can mount into a <div> and pipe the /api/session/ws stream directly — no ESM, no build step, no service worker rewrites. Files vendored (versions pinned in index.html): - xterm-6.0.0.js (477 KB, UMD) - xterm-6.0.0.css (7 KB) - xterm-addon-fit-0.11.0.js (1.5 KB) - xterm-addon-webgl-0.19.0.js (242 KB) Load order matters: xterm-6.0.0.js defers first, then the two addons defer after it. test_xterm_umd_bundles_load_in_correct_order locks this so a future reorder can't silently break addon init. Plus Amendment #6 to the refactor plan documenting §1.5b + §1.6 landing and the §1.7 frontend contract (ws_url from /session/start is the exact string to feed new WebSocket). Tests: +7 smoke tests (test_web_vendor_xterm.py) — file presence, size sanity (>1KB JS, >500B CSS), index.html references, and script load order. 1992 passed total (1985 → 1992). Ruff + format clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
NetDevAutomate
added a commit
that referenced
this pull request
Sep 3, 2026
…cache fix(ci): disable uv cache for release-consistency job
NetDevAutomate
added a commit
that referenced
this pull request
Sep 3, 2026
POST /api/session/start now routes through transport=pty by default, calling active.acquire(config, PTYTransport) and returning a ws_url the frontend feeds to /api/session/ws. The legacy tmux+ttyd path is reachable via transport=ttyd in the body or STUDYLOOP_TRANSPORT=ttyd env override (operator kill-switch). Why: closes the §1.5b gap flagged in Amendment #5 — without this bridge, the new WS route was reachable by tests only. Now the full request path works: picker POSTs /session/start → server acquires active session + PTYTransport → returns ws_url → browser opens WS and gets live PTY stream. Transport dispatch: - Body field ``transport: pty|ttyd`` (optional, default pty). - STUDYLOOP_TRANSPORT env wins over body — operator emergency switch per plan §1.9 without touching clients. - On pty path: no tmux check, no ttyd spawn, no tmux metadata in session_state.json. Writes transport=pty into state for clarity. Binary missing (503) now returns a structured payload: {error, agent, binary, install_hint}. Hints cover all five registered agents (claude, codex, gemini, kiro, opencode) so the UI — or an agent orchestrating installs — has a concrete next step. Per-agent "self-heal and retry" is §1.10 follow-up. Adapter shell wrapping: PTYTransport's build_launch_cmd returns ["/bin/sh", "-c", adapter.launch_cmd(...)]. Adapters legitimately use pipes/&& (their launch_cmd returns shell strings), so we execvpe /bin/sh instead of splitting via shlex. Mirrors what tmux send-keys effectively did. Tests: - +5 in test_web_session_start_pty.py: happy path returns ws_url and bypasses tmux, pty-is-default when unset, 409 when active, 503 with install_hint, env=ttyd overrides body=pty (routes to legacy branch and trips the tmux check). - Existing test_web_session.py: 4 legacy guard tests updated to pass transport=ttyd explicitly — they were testing tmux-based semantics that only apply to that branch now. 1985 passed, 145 deselected (was 1980 → +5 net). Ruff + format clean. Plan: Amendment #5 "§1.5b REST→PTY bridge" follow-up is now closed. Amendment #6 (below) documents the contract for §1.7 frontend. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
NetDevAutomate
added a commit
that referenced
this pull request
Sep 3, 2026
Drops the latest-stable @xterm/xterm UMD bundle, @xterm/addon-fit, @xterm/addon-webgl, and xterm.css into web/static/vendor/ and loads them from index.html. No Alpine component yet — that's §1.7 and ships in its own PR so the frontend iteration can proceed alone. Why: unblocks §1.7's agentTerminal() component. With the UMD globals (Terminal, FitAddon, WebglAddon) available at DOMContentLoaded time, the component can mount into a <div> and pipe the /api/session/ws stream directly — no ESM, no build step, no service worker rewrites. Files vendored (versions pinned in index.html): - xterm-6.0.0.js (477 KB, UMD) - xterm-6.0.0.css (7 KB) - xterm-addon-fit-0.11.0.js (1.5 KB) - xterm-addon-webgl-0.19.0.js (242 KB) Load order matters: xterm-6.0.0.js defers first, then the two addons defer after it. test_xterm_umd_bundles_load_in_correct_order locks this so a future reorder can't silently break addon init. Plus Amendment #6 to the refactor plan documenting §1.5b + §1.6 landing and the §1.7 frontend contract (ws_url from /session/start is the exact string to feed new WebSocket). Tests: +7 smoke tests (test_web_vendor_xterm.py) — file presence, size sanity (>1KB JS, >500B CSS), index.html references, and script load order. 1992 passed total (1985 → 1992). Ruff + format clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
NetDevAutomate
added a commit
that referenced
this pull request
Sep 5, 2026
POST /api/session/start now routes through transport=pty by default, calling active.acquire(config, PTYTransport) and returning a ws_url the frontend feeds to /api/session/ws. The legacy tmux+ttyd path is reachable via transport=ttyd in the body or STUDYLOOP_TRANSPORT=ttyd env override (operator kill-switch). Why: closes the §1.5b gap flagged in Amendment #5 — without this bridge, the new WS route was reachable by tests only. Now the full request path works: picker POSTs /session/start → server acquires active session + PTYTransport → returns ws_url → browser opens WS and gets live PTY stream. Transport dispatch: - Body field ``transport: pty|ttyd`` (optional, default pty). - STUDYLOOP_TRANSPORT env wins over body — operator emergency switch per plan §1.9 without touching clients. - On pty path: no tmux check, no ttyd spawn, no tmux metadata in session_state.json. Writes transport=pty into state for clarity. Binary missing (503) now returns a structured payload: {error, agent, binary, install_hint}. Hints cover all five registered agents (claude, codex, gemini, kiro, opencode) so the UI — or an agent orchestrating installs — has a concrete next step. Per-agent "self-heal and retry" is §1.10 follow-up. Adapter shell wrapping: PTYTransport's build_launch_cmd returns ["/bin/sh", "-c", adapter.launch_cmd(...)]. Adapters legitimately use pipes/&& (their launch_cmd returns shell strings), so we execvpe /bin/sh instead of splitting via shlex. Mirrors what tmux send-keys effectively did. Tests: - +5 in test_web_session_start_pty.py: happy path returns ws_url and bypasses tmux, pty-is-default when unset, 409 when active, 503 with install_hint, env=ttyd overrides body=pty (routes to legacy branch and trips the tmux check). - Existing test_web_session.py: 4 legacy guard tests updated to pass transport=ttyd explicitly — they were testing tmux-based semantics that only apply to that branch now. 1985 passed, 145 deselected (was 1980 → +5 net). Ruff + format clean. Plan: Amendment #5 "§1.5b REST→PTY bridge" follow-up is now closed. Amendment #6 (below) documents the contract for §1.7 frontend. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
NetDevAutomate
added a commit
that referenced
this pull request
Sep 5, 2026
Drops the latest-stable @xterm/xterm UMD bundle, @xterm/addon-fit, @xterm/addon-webgl, and xterm.css into web/static/vendor/ and loads them from index.html. No Alpine component yet — that's §1.7 and ships in its own PR so the frontend iteration can proceed alone. Why: unblocks §1.7's agentTerminal() component. With the UMD globals (Terminal, FitAddon, WebglAddon) available at DOMContentLoaded time, the component can mount into a <div> and pipe the /api/session/ws stream directly — no ESM, no build step, no service worker rewrites. Files vendored (versions pinned in index.html): - xterm-6.0.0.js (477 KB, UMD) - xterm-6.0.0.css (7 KB) - xterm-addon-fit-0.11.0.js (1.5 KB) - xterm-addon-webgl-0.19.0.js (242 KB) Load order matters: xterm-6.0.0.js defers first, then the two addons defer after it. test_xterm_umd_bundles_load_in_correct_order locks this so a future reorder can't silently break addon init. Plus Amendment #6 to the refactor plan documenting §1.5b + §1.6 landing and the §1.7 frontend contract (ws_url from /session/start is the exact string to feed new WebSocket). Tests: +7 smoke tests (test_web_vendor_xterm.py) — file presence, size sanity (>1KB JS, >500B CSS), index.html references, and script load order. 1992 passed total (1985 → 1992). Ruff + format clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes CI on
main, which went red immediately after #5 merged (run 30917393142).What broke
The
release-consistencyjob failed — but not on its actual check:The check passed; the cleanup step failed, which still fails the job.
Why
release-consistencyruns onlyscripts/check-release-consistency.py, which is stdlib-only (tomllib,re,argparse,pathlib). It never invokesuv— it installssetup-uvpurely to get a Python 3.12 interpreter on PATH. So no uv cache directory is ever created, and setup-uv v9 treats "asked to save a cache that does not exist" as an error where v4 did not.Introduced by the
setup-uvv4 → v9 bump in #5. Worth noting it passed on that PR's run and failed on the post-merge run of the same code — it depends on whether a cache happened to be restored first, so it is timing-dependent rather than deterministic. Not something the PR checks would reliably have caught.Fix
enable-cache: falseon that job only — exactly what the error message recommends. Audited every other job:uv syncuv buildviabuild-release.shrelease-consistencyis the only job in any workflow that pulls in setup-uv without ever running uv, so this is the complete set.Deliberately not switching it to
actions/setup-python, which would be the more structurally honest fix: it changes how the job gets its interpreter and risks apythonvspython3difference, for no benefit beyond skipping a ~1s uv download. Noted as a possible tidy-up, not done here.Verification
python scripts/check-release-consistency.pypasses locallyci.ymlparses, and the rendered step options are{'python-version': '3.12', 'enable-cache': False}The
Failed to save: Unable to reserve cache ... another job may be creating this cacheannotations ontest/audit/sastare a pre-existing concurrency warning between parallel jobs sharing one cache key. Warnings, not failures, and present before #5. Left alone.