fix(cli): remove supervise queue highlight
This commit is contained in:
@@ -17,7 +17,6 @@ import os
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import time
|
||||
import traceback
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime, timezone
|
||||
@@ -59,7 +58,6 @@ from ._common import PROG
|
||||
|
||||
|
||||
_REFRESH_INTERVAL_MS = 1000
|
||||
_NEW_PROPOSAL_HIGHLIGHT_SEC = 5.0
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@@ -99,20 +97,6 @@ def _approval_status(qp: QueuedProposal, verb: str) -> str:
|
||||
return base
|
||||
|
||||
|
||||
def _is_recent(
|
||||
proposal_id: str,
|
||||
first_seen: dict[str, float] | None,
|
||||
now: float | None,
|
||||
) -> bool:
|
||||
"""True if `proposal_id` was first seen within the highlight window."""
|
||||
if first_seen is None or now is None:
|
||||
return False
|
||||
started = first_seen.get(proposal_id)
|
||||
if started is None:
|
||||
return False
|
||||
return (now - started) < _NEW_PROPOSAL_HIGHLIGHT_SEC
|
||||
|
||||
|
||||
def _detail_lines(
|
||||
qp: QueuedProposal,
|
||||
*,
|
||||
@@ -388,21 +372,19 @@ def _main_loop(stdscr: "curses._CursesWindow") -> None:
|
||||
curses.curs_set(0)
|
||||
stdscr.timeout(_REFRESH_INTERVAL_MS)
|
||||
green_attr = _try_init_green()
|
||||
first_seen: dict[str, float] = {}
|
||||
selected = 0
|
||||
status_line = ""
|
||||
saw_first_tick = False
|
||||
supervise_pane_id = os.environ.get("TMUX_PANE", "")
|
||||
seen_ids: set[str] = set()
|
||||
|
||||
while True:
|
||||
pending = discover_pending()
|
||||
if selected >= len(pending):
|
||||
selected = max(0, len(pending) - 1)
|
||||
|
||||
now = time.monotonic()
|
||||
live_ids = {qp.proposal.id for qp in pending}
|
||||
newly_arrived = live_ids - first_seen.keys()
|
||||
if saw_first_tick and newly_arrived:
|
||||
newly_arrived = live_ids - seen_ids
|
||||
if seen_ids and newly_arrived:
|
||||
try:
|
||||
curses.beep()
|
||||
except curses.error:
|
||||
@@ -413,15 +395,11 @@ def _main_loop(stdscr: "curses._CursesWindow") -> None:
|
||||
if qp.proposal.id in newly_arrived:
|
||||
selected = i
|
||||
break
|
||||
for proposal_id in live_ids:
|
||||
first_seen.setdefault(proposal_id, now)
|
||||
for stale_id in list(first_seen.keys() - live_ids):
|
||||
del first_seen[stale_id]
|
||||
saw_first_tick = True
|
||||
seen_ids = live_ids
|
||||
|
||||
_render(
|
||||
stdscr, pending, selected, status_line,
|
||||
first_seen=first_seen, now=now, green_attr=green_attr,
|
||||
green_attr=green_attr,
|
||||
)
|
||||
|
||||
try:
|
||||
@@ -478,8 +456,6 @@ def _render(
|
||||
selected: int,
|
||||
status_line: str,
|
||||
*,
|
||||
first_seen: dict[str, float] | None = None,
|
||||
now: float | None = None,
|
||||
green_attr: int = 0,
|
||||
) -> None:
|
||||
stdscr.erase()
|
||||
@@ -512,8 +488,6 @@ def _render(
|
||||
f"{_proposed_payload_label(p.tool)}"
|
||||
)
|
||||
attr = curses.A_REVERSE if i == selected else curses.A_NORMAL
|
||||
if _is_recent(p.id, first_seen, now):
|
||||
attr |= green_attr
|
||||
stdscr.addnstr(row, 0, line, w - 1, attr)
|
||||
row += 1
|
||||
if row >= h - 3:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
- **Status:** Active
|
||||
- **Status:** Draft
|
||||
- **Author:** didericis
|
||||
- **Created:** 2026-06-03
|
||||
- **Issue:** #174
|
||||
@@ -127,8 +127,8 @@ problem is everything that got bolted onto that core after.
|
||||
dashboard.py` to `bot_bottle/cli/supervise.py`. The dispatcher
|
||||
in `bot_bottle/cli/__init__.py` and the help text both update.
|
||||
- **Strip the curses loop to proposal-only.** The remaining
|
||||
surface is: list pending proposals (with the new-arrival bell +
|
||||
green highlight from PRD 0013), Enter for detail view,
|
||||
surface is: list pending proposals (with the new-arrival bell
|
||||
from PRD 0013), Enter for detail view,
|
||||
`a`/`m`/`r` for approve / modify / reject, `q` to quit. No
|
||||
agents pane, no Tab, no agent picker, no `n`/`x`/`e`/`p`, no
|
||||
tmux dispatch, no `bottles` dict on the main loop.
|
||||
@@ -141,10 +141,9 @@ problem is everything that got bolted onto that core after.
|
||||
`operator_edit_allowlist`, and their imports come out.
|
||||
- **Collapse the model module.** `dashboard_model.py`'s
|
||||
proposal-side helpers (`QueuedProposal`, `discover_pending`,
|
||||
`_approval_status`, `_is_recent`, `_detail_lines`,
|
||||
`_approval_status`, `_detail_lines`,
|
||||
`_failed_url_host`, `_proposed_payload_label`,
|
||||
`_suffix_for_tool`, `_REFRESH_INTERVAL_MS`,
|
||||
`_NEW_PROPOSAL_HIGHLIGHT_SEC`) move back into
|
||||
`_suffix_for_tool`, `_REFRESH_INTERVAL_MS`) move back into
|
||||
`supervise.py` (CLI) or into `bot_bottle/supervise.py`
|
||||
(the daemon-side module) — wherever they fit. The agents /
|
||||
picker / tmux helpers in that module (`PANE_*`,
|
||||
@@ -205,7 +204,7 @@ ripgrep
|
||||
view, same as today.
|
||||
- `q` / Esc quits. There are no dashboard-owned bottles, so no
|
||||
per-process teardown decision — `q` just exits.
|
||||
- The new-arrival bell + green highlight + (if in tmux) the
|
||||
- The new-arrival bell + (if in tmux) the
|
||||
`tmux select-pane` jump back to the supervise pane stay,
|
||||
because they're real wins for the operator's "I was typing at
|
||||
claude and a proposal landed" case. They don't require any of
|
||||
@@ -229,7 +228,7 @@ bot_bottle/cli/supervise.py
|
||||
- reject(qp, *, reason)
|
||||
- QueuedProposal, discover_pending
|
||||
- _detail_lines, _approval_status,
|
||||
_is_recent, _failed_url_host,
|
||||
_failed_url_host,
|
||||
_proposed_payload_label,
|
||||
_suffix_for_tool
|
||||
```
|
||||
@@ -262,7 +261,7 @@ a clear pointer forward. No PRD body is rewritten.
|
||||
Keep:
|
||||
- `tests/cli/test_dashboard*.py` cases that exercise
|
||||
`discover_pending`, `approve`, `reject`, `_detail_lines`,
|
||||
`_is_recent`, `_approval_status`, `_failed_url_host`,
|
||||
`_approval_status`, `_failed_url_host`,
|
||||
`_proposed_payload_label`, `_suffix_for_tool`,
|
||||
`_modify` / `edit_in_editor`.
|
||||
- `tests/cli/test_dashboard_once.py` (or equivalent) — the
|
||||
|
||||
@@ -1,39 +0,0 @@
|
||||
"""Unit: supervise's new-proposal highlight window.
|
||||
|
||||
The curses rendering itself is exercised manually; this isolates
|
||||
the pure decision `is the proposal still in its post-arrival
|
||||
highlight window?`"""
|
||||
|
||||
import unittest
|
||||
|
||||
from bot_bottle.cli import supervise as supervise_cli
|
||||
|
||||
|
||||
class TestIsRecent(unittest.TestCase):
|
||||
def test_just_seen_is_recent(self):
|
||||
self.assertTrue(supervise_cli._is_recent("p1", {"p1": 100.0}, now=100.5))
|
||||
|
||||
def test_seen_within_window(self):
|
||||
# Default window is 5s.
|
||||
self.assertTrue(
|
||||
supervise_cli._is_recent("p1", {"p1": 100.0}, now=104.9),
|
||||
)
|
||||
|
||||
def test_seen_past_window_is_not_recent(self):
|
||||
self.assertFalse(
|
||||
supervise_cli._is_recent("p1", {"p1": 100.0}, now=106.0),
|
||||
)
|
||||
|
||||
def test_unknown_proposal_is_not_recent(self):
|
||||
self.assertFalse(
|
||||
supervise_cli._is_recent("p2", {"p1": 100.0}, now=100.5),
|
||||
)
|
||||
|
||||
def test_none_args_safe_default(self):
|
||||
self.assertFalse(supervise_cli._is_recent("p1", None, None))
|
||||
self.assertFalse(supervise_cli._is_recent("p1", {"p1": 100.0}, None))
|
||||
self.assertFalse(supervise_cli._is_recent("p1", None, 100.5))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user