Skip to content

enhance(cli, task): Interactive Ctrl+C drain with force-quit escalation#687

Merged
JeanMertz merged 4 commits into
mainfrom
prr250
May 29, 2026
Merged

enhance(cli, task): Interactive Ctrl+C drain with force-quit escalation#687
JeanMertz merged 4 commits into
mainfrom
prr250

Conversation

@JeanMertz
Copy link
Copy Markdown
Collaborator

When jp finishes its main work, it waits for background tasks (e.g. title generation) before exiting. Previously this was a silent, blocking call with no user feedback and no way to interrupt it.

This commit replaces that with an interactive drain loop. If background tasks are still running after 1 second, a ⏱ Finishing background tasks… Ns line is printed to stderr (TTY only). The first Ctrl+C (SIGINT/SIGTERM) switches the line to a 2-second countdown and signals graceful cancellation via the existing soft-cancel token. A second Ctrl+C — or SIGQUIT — escalates to a hard force-quit that aborts the JoinSet immediately and drops any pending workspace mutations.

The escalation path required a second force_token on TaskHandler. The soft-cancel token already existed but was only fired internally; it is now also exposed via cancel_token() so the drain loop can signal it externally. is_empty() is added to short-circuit the whole drain when there is nothing to wait for.

As a related fix, TitleGeneratorTask now accepts an is_tty flag and suppresses the OSC-2 terminal-title sequence when the process is not attached to a TTY. Without this guard, the escape bytes leaked into captured pipes or CI logs when running jp non-interactively.

JeanMertz added 3 commits May 29, 2026 10:00
The role-header model id was being sourced from `ModelDetails.id`
returned by the provider. Some providers rewrite the id — for example,
Anthropic resolves an unversioned name to a date-suffixed canonical
form. This caused the live turn header and the replay header to show
different model strings for the same conversation.

On replay, `TurnRenderer::reconfigure` reads the per-turn
`PartialAppConfig` snapshot stored in the conversation, which always
holds the *configured* id. Pinning the live path to the same source
(`cfg.assistant.model.id.resolved()`) keeps both paths consistent and
stable across API version drift.

`TurnRenderer::reconfigure` is updated in the same direction: identity
fields (assistant name and model id) are now read from the partial
directly, before the full `AppConfig::from_partial_with_defaults`
rebuild, so the role header never depends on default-filling for these
two stable fields. A new `render_model_id` helper maps a fully-empty
partial id to `None`, suppressing the `(model)` suffix from the header
rather than showing an empty string.

Signed-off-by: Jean Mertz <git@jeanmertz.com>
Signed-off-by: Jean Mertz <git@jeanmertz.com>
When `jp` finishes its main work, it waits for background tasks (e.g.
title generation) before exiting. Previously this was a silent, blocking
call with no user feedback and no way to interrupt it.

This commit replaces that with an interactive drain loop. If background
tasks are still running after 1 second, a `⏱ Finishing background tasks…
Ns` line is printed to stderr (TTY only). The first Ctrl+C
(SIGINT/SIGTERM) switches the line to a 2-second countdown and signals
graceful cancellation via the existing soft-cancel token. A second
Ctrl+C — or SIGQUIT — escalates to a hard force-quit that aborts the
`JoinSet` immediately and drops any pending workspace mutations.

The escalation path required a second `force_token` on `TaskHandler`.
The soft-cancel token already existed but was only fired internally; it
is now also exposed via `cancel_token()` so the drain loop can signal it
externally. `is_empty()` is added to short-circuit the whole drain when
there is nothing to wait for.

As a related fix, `TitleGeneratorTask` now accepts an `is_tty` flag and
suppresses the OSC-2 terminal-title sequence when the process is not
attached to a TTY. Without this guard, the escape bytes leaked into
captured pipes or CI logs when running `jp` non-interactively.

Signed-off-by: Jean Mertz <git@jeanmertz.com>
Base automatically changed from prr249 to main May 29, 2026 08:52
…scalation

Signed-off-by: Jean Mertz <git@jeanmertz.com>
@JeanMertz JeanMertz merged commit db7ab75 into main May 29, 2026
14 checks passed
@JeanMertz JeanMertz deleted the prr250 branch May 29, 2026 09:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant