feat(attach): --continue on re-attach + keep bottles on dashboard quit #47

Merged
didericis merged 3 commits from reattach-resume-flag into main 2026-05-26 14:04:33 -04:00
Owner

Summary

Two-part fix for the dashboard's re-attach + quit behavior:

1. Re-attach now passes --continue to claude.

Re-entering a running bottle from the dashboard (Enter on the agents pane) invokes claude with --continue so the session jumps straight to the most recent transcript — no session-picker prompt. First-attach paths (./cli.py start and the dashboard's new-agent n flow) leave it off; there's no prior session to continue.

attach_claude gains a resume: bool = False kwarg; the dashboard's _attach_to_bottle passes True. When the kwarg is set, --continue is appended to claude's argv. (Originally tried --resume, but that surfaces the picker even when only one session exists.)

2. q no longer tears down bottles.

The bottles dict held @contextmanager-wrapped launch contexts. On Python interpreter shutdown those generators' finally blocks ran via GC, invoking each bottle's teardown — net effect: q was implicitly tearing down every dashboard-launched bottle even though the keypress handler just return'd.

os._exit(0) skips all Python-level cleanup so the docker compose projects survive. curses.endwin() first to restore the terminal since the brutal exit also bypasses curses.wrapper's normal cleanup.

This matches PRD 0020's resolved-question answer (q does NOT tear down; teardown is always explicit via x or ./cli.py cleanup).

Status

  • 465 unit tests pass
  • Tmux integration (option 3 from the research doc) split off into a separate PR
## Summary Two-part fix for the dashboard's re-attach + quit behavior: **1. Re-attach now passes `--continue` to claude.** Re-entering a running bottle from the dashboard (Enter on the agents pane) invokes claude with `--continue` so the session jumps straight to the most recent transcript — no session-picker prompt. First-attach paths (`./cli.py start` and the dashboard's new-agent `n` flow) leave it off; there's no prior session to continue. `attach_claude` gains a `resume: bool = False` kwarg; the dashboard's `_attach_to_bottle` passes `True`. When the kwarg is set, `--continue` is appended to claude's argv. (Originally tried `--resume`, but that surfaces the picker even when only one session exists.) **2. `q` no longer tears down bottles.** The `bottles` dict held `@contextmanager`-wrapped launch contexts. On Python interpreter shutdown those generators' `finally` blocks ran via GC, invoking each bottle's teardown — net effect: `q` was implicitly tearing down every dashboard-launched bottle even though the keypress handler just `return`'d. `os._exit(0)` skips all Python-level cleanup so the docker compose projects survive. `curses.endwin()` first to restore the terminal since the brutal exit also bypasses curses.wrapper's normal cleanup. This matches PRD 0020's resolved-question answer (`q` does NOT tear down; teardown is always explicit via `x` or `./cli.py cleanup`). ## Status - 465 unit tests pass - Tmux integration (option 3 from the research doc) split off into a separate PR
didericis added 3 commits 2026-05-26 13:48:35 -04:00
Re-entering a running bottle from the dashboard (Enter on the
agents pane) now invokes claude with `--resume` so the session
picks up the prior conversation history rather than starting a
fresh transcript. The first-attach paths (`./cli.py start` and
the dashboard's new-agent `n` flow) leave it off — the
transcript doesn't exist yet there.

`attach_claude` gains a `resume: bool = False` kwarg;
`_attach_to_bottle` in the dashboard passes `True`.
`--resume` alone surfaces claude's session picker even when only
one session exists. `--continue` jumps to the most recent session
non-interactively, which is the actual behavior the dashboard's
Enter re-attach wants for typical bottle-with-one-session cases.
fix(dashboard): use os._exit on quit so bottles survive the dashboard
test / unit (pull_request) Successful in 18s
test / integration (pull_request) Successful in 1m9s
ae6d11f09d
The `bottles` dict held `@contextmanager`-wrapped launch contexts.
On normal Python interpreter shutdown those context managers'
generators got GC'd, which raised GeneratorExit at the yield
point and ran the `finally` block — invoking each bottle's
teardown and tearing down the compose project. Net effect: `q`
WAS implicitly stopping every dashboard-launched bottle even
though the keypress handler just `return`'d.

`os._exit(0)` skips all Python-level cleanup (GC, atexit, etc.),
so the docker compose projects survive the dashboard exit
untouched. Curses gets explicit `endwin()` first because the
brutal exit skips curses.wrapper's normal terminal restoration.

Matches PRD 0020's resolved-question answer (`q` does NOT tear
down bottles; teardown is always explicit via `x` or
`./cli.py cleanup`).
didericis force-pushed reattach-resume-flag from 2ff1730588 to ae6d11f09d 2026-05-26 13:48:35 -04:00 Compare
didericis changed title from feat(attach): pass --resume on dashboard re-attach to feat(attach): pass --continue on dashboard re-attach + keep bottles on quit 2026-05-26 13:51:56 -04:00
didericis force-pushed reattach-resume-flag from cdb1bffabd to ae6d11f09d 2026-05-26 14:04:16 -04:00 Compare
didericis changed title from feat(attach): pass --continue on dashboard re-attach + keep bottles on quit to feat(attach): --continue on re-attach + keep bottles on dashboard quit 2026-05-26 14:04:28 -04:00
didericis merged commit c8c72debff into main 2026-05-26 14:04:33 -04:00
Sign in to join this conversation.