Commit Graph
100 Commits
Author SHA1 Message Date
nesquena-hermes 5f01033c44 test: drop unused pytest import (ruff F401) — from #5346 be894353 2026-07-01 17:17:11 +00:00
nesquena-hermes 0025466168 test: make cancelStream harnesses tolerate the new reason param + stdout provenance log
Codex gate on #5346 flagged two brittle static extractors that broke on the
cancelStream(reason) signature change + the new '[stream] cancel requested'
stdout log:

- test_cancel_stream_owner_guard.py: the Node harness parsed ALL of stdout as
  JSON; the provenance console.info line (fires during runAll) polluted it.
  Parse the LAST non-empty stdout line (the result JSON is always emitted last,
  after runAll resolves).
- test_sprint36.py: two extractors did src.find('async function cancelStream()')
  (exact, no params). Switched to a signature-tolerant regex and widened the
  catch-block window (the provenance log/comments now precede the try/catch).

Both pre-existing tests, updated to match the intentional #5345 change (not the
code bent to fit the test).
2026-07-01 17:17:11 +00:00
6716f03f4d fix(webui): stop false clarify-unavailable toast; add interrupt provenance (#5345)
/api/clarify/pending always returns HTTP 200 when present (returns
{"pending": null} for an unknown session — it never 404s). The front-end
clarify poller warned "Clarify endpoint unavailable. Please restart
server." on ANY caught error whose message merely contained "404" or
"not found", so an unrelated stale-session 404 ("Session not found", e.g.
an old-profile session polling briefly after a profile switch) or a
transient error produced a misleading missing-endpoint toast that pointed
operators at the wrong layer.

Clarify polling now branches on the structured HTTP status that api()
attaches to the thrown Error (err.status):
- 404 "Session not found" -> handled as a stale-session poll (stop + hide
  card silently), no toast;
- restart-server warning fires only on a genuine route-not-found 404 whose
  body is NOT session-scoped;
- poll failures are logged with path, status, polling session id, and
  current session id for diagnosis.

Interrupt provenance: cancelStream()/cancelSessionStream() now log a
'[stream] cancel requested' line with the trigger reason
(composer-stop / slash-stop / slash-interrupt / busy-interrupt /
sidebar-stop). Passive UI lifecycle events (session switch, tab hide, page
unload) already tear down only the local SSE transport via
closeLiveStream() and never call /api/chat/cancel — only explicit
Stop/interrupt paths interrupt the backend agent/tool run. This is
confirmed by test_clarify_pending_never_404s locking the handler shape.

Supersedes #5343 (which handled only the profile-switch sub-case and kept
the broad message-scrape). Adds tests/test_issue5345_*.py (9 tests).

Co-authored-by: claw-io <claw-io@users.noreply.github.com>
Co-authored-by: ruizanthony <ruizanthony@users.noreply.github.com>
2026-07-01 17:17:11 +00:00
nesquena-hermes 7d58c1e8e1 docs(changelog): prune index-only ghost sessions (#5331) 2026-07-01 17:12:20 +00:00
nesquena-hermes ef9a8b733e stage #5333 2026-07-01 15:53:18 +00:00
nesquena-hermes 3569d84a56 test: drop unused api.models import (ruff F401) 2026-07-01 09:19:04 +00:00
nesquena-hermes cda6483153 docs(changelog): view-only delegated subagent session transcript recovery (#5307) 2026-07-01 09:13:34 +00:00
nesquena-hermes 794837d635 Merge #5307 (subagent child transcript view-only recovery) into stage 2026-07-01 09:13:08 +00:00
nesquena-hermes b65ab14538 fix(#5307): gate /api/goal + /api/btw subagent write paths (Codex round 11) 2026-07-01 08:55:58 +00:00
nesquena-hermes ae8496a060 test: widen brittle static-grep windows for delete/duplicate route assertions (#5307 guard lines shifted markers past the fixed windows; functionality unchanged) 2026-07-01 08:49:37 +00:00
nesquena-hermes cdbd84585a fix(#5307): gate final 4 subagent write paths (Codex round 10)
_session_is_subagent_view_only guard added to the remaining paths that could
mutate a stale persisted subagent sidecar:
- _handle_handoff_summary (appends tool msg to state.db)
- _handle_chat_sync (fallback POST /api/chat)
- /api/session/draft POST (composer_draft save)
- /api/personality/set (per-session personality save)
Fixes #5307
2026-07-01 08:47:34 +00:00
nesquena-hermes e6e7454c7a fix(#5307): gate ALL remaining session-mutation routes + stale-webui-row coercion (Codex round 9)
Enumerated every /api/session/<mutation> route and applied _session_is_subagent_view_only:
duplicate, branch, retry, undo, toolsets, compress, archive (existing-sidecar path)
now 400 for subagent children; delete/clear/truncate/pin already gated; rename/move/update
route through the gated _get_or_materialize_session (403). This closes the data-loss
paths (delete_cli_session, retry/undo truncate, branch/duplicate fork).

Also: /api/sessions list coercion now also honors state.db source='subagent' for rows
whose stale index says webui/fork, so they can't surface as writable/CLI sidebar rows.
Fixes #5307
2026-07-01 08:38:47 +00:00
nesquena-hermes 23743c5976 fix(#5307): guard direct mutation routes + coerce list rows (Codex round 8)
The root non-CLI classification surfaced subagent rows in the sidebar without
read_only, exposing delete/truncate/pin — and /api/session/delete calls
delete_cli_session() which erases the child's state.db transcript (data loss).

- /api/sessions list: coerce subagent rows to read_only=True + is_cli_session=False
  so the UI offers no mutation affordances.
- New _session_is_subagent_view_only() shared guard; applied to the direct
  mutation routes that bypass _get_or_materialize_session(): delete / clear /
  truncate / pin now 400 for subagent children. (rename/move already route
  through the gated _get_or_materialize_session and 403.)
- tests: guard helper + static contract that all 4 routes + list coercion present.
Fixes #5307
2026-07-01 08:21:03 +00:00
nesquena-hermes 9eb208ebc3 fix(#5307): root-fix subagent classification + GET serialization (Codex round 7)
- api/agent_sessions.py is_cli_session_row(): add 'subagent' to non_cli_sources
  so EVERY consumer (sidebar rows, /api/sessions, etc.) classifies a delegated
  child as non-CLI (the root the per-site fixes were compensating for).
- api/routes.py GET /api/session happy path: coerce is_cli_session=False +
  read_only=True in the serialized payload for a subagent child before redaction,
  so a stale writable sidecar can't be exposed as writable to the browser.
Fixes #5307
2026-07-01 08:10:24 +00:00
nesquena-hermes 2e33e40272 fix(#5307): guard persisted subagent sidecars against writable use (Codex round 6)
- _get_or_materialize_session happy path: reject an already-persisted subagent
  sidecar (source_tag/raw_source=='subagent' or state.db subagent) even when it
  was stored read_only=False (pre-fix materialization), so chat-start can't write it.
- import_cli existing-session refresh: coerce read_only=True on the persisted
  sidecar (and response) when it's a subagent child.
- test: persisted read_only=False subagent sidecar is still refused by the helper.
Fixes #5307
2026-07-01 08:04:47 +00:00
nesquena-hermes 6e2ead5b1b fix(#5307): close cross-profile + existing-session subagent edges (Codex round 5)
- import_cli _read_only_view now also treats resolved cli_meta source_tag/raw_source
  =='subagent' as view-only (all_profiles=true resolves cli_meta from a non-active
  profile, which the active-profile state.db _sa_child check could miss).
- import_cli existing-session refresh branch no longer hardcodes is_cli_session=True
  for a subagent child (both the persisted update and the response payload).
Fixes #5307
2026-07-01 07:55:00 +00:00
nesquena-hermes 161fdeba7a fix(#5307): gate the 3rd/final import_cli_session write path (archive fallback)
Codex round 4 found POST /api/session/archive's missing-sidecar fallback also
calls import_cli_session(). grep confirms exactly 3 import_cli_session() call
sites in routes.py; all 3 now refuse source='subagent' children:
  - 4792 _get_or_materialize_session (chat-start) -> PermissionError
  - 22382 import_cli endpoint -> read-only view payload
  - 13885 archive fallback -> 400 'Subagent sessions cannot be archived'
So no path can materialize a delegated child as a writable WebUI sidecar.
Fixes #5307
2026-07-01 07:48:34 +00:00
nesquena-hermes c989acc991 fix(#5307): gate subagent children in the shared materialize chokepoint (Codex round 3)
Codex found a 3rd writable path: POST /api/chat/start -> _get_or_materialize_session()
materialized source='subagent' as a writable sidecar before the not_claimable guard.
Fix: refuse subagent children (PermissionError) at that shared chokepoint, checked via
_is_subagent_child_session_id(sid) (state.db source, independent of cli_meta) BEFORE the
materialize path — so all three entry points (GET synth, import_cli, chat-start) now
consistently keep a delegated child view-only. CLI/TUI/Desktop materialization preserved.

Tests: materialize helper refuses subagent child + still allows tui.
Fixes #5307
2026-07-01 07:44:11 +00:00
nesquena-hermes 3ecb2625aa fix(#5307): close 2 more subagent-child writable-session holes (Codex round 2)
- api/routes.py GET /api/session synthesized response: stop hardcoding
  is_cli_session=True; serialize bool(synth.is_cli_session) so a recovered
  subagent child stays not-CLI-classified (was overriding the helper's False).
- api/routes.py POST /api/session/import_cli: gate source='subagent' into the
  read-only view payload (is_cli_session=False, imported=False) BEFORE
  import_cli_session(), so a subagent child can never be materialized as a
  writable WebUI sidecar via this endpoint.
- tests: assert import_cli routes subagent children read-only (no materialize).

Both were paths that bypassed the _is_claimable_cli_source denylist. Fixes #5307
2026-07-01 07:35:48 +00:00
nesquena-hermes a823ab5ff8 fix(#5307): recover subagent child transcript view-only (Codex hardening)
Reworked per the Codex gate finding: the first approach widened the client
import predicate, which (a) conflicted with #3603's intentional _isExternalSession
gate and (b) let import_cli persist the subagent child as a WRITABLE, CLI-classified
session that then passed the poll-skip/active-refresh gates.

Corrected to a server-side, view-only recovery:
- api/routes.py: mark source='subagent' as NON-claimable in _is_claimable_cli_source
  (both cli_meta and state.db source denylists). A subagent child now resolves via
  the not_claimable branch -> read-only Session with its state.db transcript, and
  build_session takes is_cli_flag (False for subagent children) so the recovered
  session is NOT CLI-classified and can't widen the frontend _isExternalSession gates.
- static/sessions.js: REVERTED to master (no client change needed; #3603 contract intact).
- tests: assert reason=not_claimable, read_only=True, is_cli_session!=True, transcript present;
  #2782 deleted-webui 404 preserved; #3603 _isExternalSession contract preserved.

58 tests green (5307 + 3603 + claim-cli + core-data-loss). Fixes #5307
2026-07-01 07:24:16 +00:00
nesquena-hermes bed98c787c fix(sessions): load delegated subagent child transcript from state.db (#5307)
A delegated subagent child (source='subagent' in state.db) usually has no WebUI
sidecar but is registered in the WebUI index sharing the parent's lineage. That
made GET /api/session -> _claim_or_synthesize_cli_session return 'was_webui' ->
404, so the child pane opened empty despite state.db holding messages.

- api/routes.py: add _state_db_session_source() + _is_subagent_child_session_id();
  exclude subagent children from the was_webui 404 gate so they recover their
  state.db transcript (the #2782 self-heal 404 for deleted WebUI sessions is kept).
- static/sessions.js: add _isSubagentChildSession() + _sessionNeedsServerImportForLoad()
  (kept separate from _isExternalSession to avoid widening refresh-gating); the
  main session-tap, lineage-segment, and child-open handlers now trigger the
  import/merge path for subagent children.
- tests: test_5307_subagent_child_transcript.py (7 tests).

Fixes #5307
2026-07-01 07:15:19 +00:00
nesquena-hermes 97b5979fd8 docs(changelog): keep active-parent delegate children stably visible (#5306/#5305) 2026-07-01 07:05:37 +00:00
nesquena-hermes 1a429cda3b stage #5320 2026-07-01 07:05:14 +00:00
nesquena-hermes 38ca286acc docs(changelog): honor busy input mode on first send (#5170) 2026-07-01 06:54:46 +00:00
nesquena-hermes 3d780836d3 stage #5170 2026-07-01 06:54:07 +00:00
nesquena-hermes f942b712ad docs(changelog): gate reasoning_content replay for provider-facing history (#5024) 2026-07-01 06:50:23 +00:00
nesquena-hermes d6c01245c5 stage #5024 2026-07-01 06:49:44 +00:00
nesquena-hermes 6095f639ba docs(changelog): native OIDC login for WebUI (#5012) 2026-07-01 06:45:55 +00:00
nesquena-hermes 36436c9397 stage #5012 2026-07-01 06:45:22 +00:00
nesquena-hermes 578e70c2bc docs(changelog): gate embedded-terminal endpoints to local origins (#5268) 2026-07-01 06:41:41 +00:00
nesquena-hermes 9973b36cce stage #5268 2026-07-01 06:41:09 +00:00
nesquena-hermes ebdd48079a fix(sidebar): keep active-parent delegate children stably visible (flicker) (#5306)
#5306 (flicker): while a parent WebUI session is the active/streaming session,
a linked delegate subagent child that transiently reports message_count===0
between /api/sessions polls was dropped by _sidebarRowHasVisibleMessages BEFORE
_attachChildSessionsToSidebarRows could stack it under its parent. It never
entered sessionsRaw, so the row vanished, then reappeared on the next refresh
once its list metadata caught up — the flicker. Extend the visibility predicate
with an active-parent exception (mirroring the existing active-session
exception): a child_session whose parent_session_id is the active sidebar
session stays visible even at message_count 0. Scoped to the active parent so
truly-empty unrelated sessions are still hidden.

#5305 (orphan): a delegated subagent child whose WebUI parent is filtered out of
the current render (project/profile/source scope) was promoted to a contextless
top-level "Subagent Session" orphan. Suppress cross-surface child_session rows
whose parent row is absent from the render instead of orphaning them, mirroring
the existing archived-hidden-parent suppression (#4293). The genuinely-external
parent case (messaging/CLI) still orphans via the parentIsExternal branch.

Tests: tests/test_5306_subagent_sidebar_flicker.py (7 tests) locks both
invariants and the no-regression guards, executing the real sessions.js helper
regions under node like the existing lineage tests.
2026-07-01 06:36:02 +00:00
nesquena-hermes 0533871ef5 docs(changelog): docker rsync .playwright exclude (#5316) 2026-07-01 06:35:55 +00:00
nesquena-hermes b4bfda5504 stage #5316 2026-07-01 06:35:35 +00:00
nesquena-hermes 948e8bfc67 docs(changelog): composer footer control reordering (#5075) 2026-07-01 06:23:51 +00:00
nesquena-hermes 04191939d2 stage #5075 2026-07-01 06:13:17 +00:00
nesquena-hermes adb528cfcb fix(#5170): persist busy-input-mode mirror on Settings autosave + panel-load (Codex: mirror only written on boot-apply, so a Settings change didn't survive the boot race) 2026-07-01 01:45:44 +00:00
nesquena-hermes 2ec7df8a27 rebase #5170 onto current master (union-resolved busy-mode boot conflicts: keep persisted pref on settings-load-fail + preserve placeholder-hint/showBusyPlaceholderHint) 2026-07-01 01:40:53 +00:00
nesquena-hermes d257e5f36c fix(security): gate embedded-terminal endpoints to local origins when auth disabled
The embedded workspace terminal spawns a PTY shell that runs arbitrary
commands as the server-process user. check_auth() returns True
unconditionally when no password/passkey is configured (the default
out-of-the-box state), so without a network-scope gate the terminal
endpoints were reachable by any unauthenticated caller able to hit the
port — which on a passwordless public bind is remote code execution.

Apply the same local-origin gate the onboarding/bootstrap endpoints use
(_onboarding_gate_allows) to /api/terminal/{start,input,resize,close} and
/api/terminal/output: with auth disabled, accept only loopback/private
origins, ignore spoofable X-Forwarded-For/X-Real-IP unless
HERMES_WEBUI_TRUST_FORWARDED_FOR=1, and honor HERMES_WEBUI_ONBOARDING_OPEN=1
as the explicit opt-out for a deliberately-exposed server. Auth-enabled
servers (cookie already verified upstream) and genuine same-host clients
are unaffected.

Also fixes a latent test-isolation leak in
test_extension_route_remains_behind_webui_auth: it set HERMES_WEBUI_PASSWORD
but never invalidated the process-wide password-hash cache, so its result
depended on suite execution order (exposed when the new test file shifted
ordering). Invalidate before+after so it reads the env var deterministically.

12 new gate tests in tests/test_cvd3_terminal_local_origin_gate.py.
2026-07-01 00:40:25 +00:00
nesquena-hermes 7298d91dec docs(changelog): prune orphan zero-message sidebar sessions (#4988) 2026-07-01 00:20:13 +00:00
nesquena-hermes 9bd71e9bae Merge #4988 (enihcam prune orphan zero-msg sessions) into stage
# Conflicts:
#	CHANGELOG.md
2026-07-01 00:19:56 +00:00
nesquena-hermes 1dfdf6a2c1 docs(changelog): extension skin base scheme (#5271) 2026-07-01 00:09:37 +00:00
nesquena-hermes a17df9fd22 Merge #5271 into stage 2026-07-01 00:08:40 +00:00
nesquena-hermes 39a3a6e703 docs(changelog): expand zhCN localization (#5279) 2026-07-01 00:04:24 +00:00
nesquena-hermes 14bb0ae31a Merge #5279 into stage 2026-06-30 23:58:46 +00:00
nesquena-hermes e4b901da53 fix(i18n): restore large_text_paste keys dropped in zh during rebase resolution 2026-06-30 23:55:15 +00:00
nesquena-hermes c80311a5db docs(changelog): SSE-recovery follow-intent sticky guard (#5217) 2026-06-30 23:35:00 +00:00
nesquena-hermes e0f42ca900 Merge #5217 into stage 2026-06-30 23:35:00 +00:00
nesquena-hermes f7ec3c7b39 test(#5217): scope follow-intent ordering assertion to _handleStreamError + strip EOF blank line (Codex gate nits) 2026-06-30 23:18:00 +00:00
nesquena-hermes 740a3a693e docs(changelog): deep-link ?q= composer prefill, converged (#4969) 2026-06-30 23:08:16 +00:00
nesquena-hermes 373c3e4b63 Merge #4969 into stage 2026-06-30 23:07:53 +00:00
nesquena-hermes a616163523 docs(changelog): default-Kanban dispatch fix (#5289) + PWA new-chat hydration defer (#5287) 2026-06-30 22:45:35 +00:00
nesquena-hermes 338060e910 Merge #5287 into stage-b1 2026-06-30 22:45:08 +00:00
nesquena-hermes 7df031592c Merge #5289 into stage-b1 2026-06-30 22:45:06 +00:00
nesquena-hermes ec5f9715a1 docs(changelog): two opt-in neon skins (#4738) 2026-06-30 22:22:14 +00:00
nesquena-hermes 3e84d7bf11 Merge #4738 (savagebread neon skins + skin-persistence fix) into stage 2026-06-30 22:21:28 +00:00
nesquena-hermes 0b2507ac9f fix(#4738): register neon-soft/neon-paint in _SETTINGS_SKIN_VALUES (server-side skin persistence) 2026-06-30 22:13:36 +00:00
nesquena-hermes a20d42893d docs(changelog): opt-in Shift+Enter send-key mode (#5005) 2026-06-30 21:52:20 +00:00
nesquena-hermes 78ca4d43a1 Merge #5005 (futureworld678 Shift+Enter) into stage 2026-06-30 21:51:42 +00:00
nesquena-hermes 512824dcc3 docs(changelog): configurable provider budget + %-used (#5120) 2026-06-30 21:34:35 +00:00
nesquena-hermes 0b74397fa6 Merge #5120 (rodboev budget limit) into stage 2026-06-30 21:28:51 +00:00
nesquena-hermes f579ed83dc fix(#5002): repaint sidebar after quick-create newSession (Codex: newSession doesn't render; callers must) 2026-06-30 21:12:14 +00:00
nesquena-hermes ee7f6b584d fix(#5002): hydrate _projectQuickCreate at boot + rebuild sidebar on toggle change
Codex gate findings: (1) the opt-in flag was only set when Settings opened, so an
enabled setting didn't take effect on a fresh load — now hydrated from /api/settings
at boot (mirrors _largeTextPasteAsAttachment, default-false); (2) toggling the
checkbox now rebuilds the sidebar so the + buttons appear/disappear immediately.
2026-06-30 21:06:35 +00:00
nesquena-hermes 34f4a72256 docs(changelog): opt-in per-project new-conversation shortcuts (#5002) 2026-06-30 20:56:49 +00:00
nesquena-hermes 8a5172275d Merge #5002 (per-project quick-create, opt-in) into stage 2026-06-30 20:56:05 +00:00
nesquena-hermes a103775e42 docs(changelog): OpenAI-compatible TTS backend, SSRF-hardened (#5079) 2026-06-30 20:39:51 +00:00
nesquena-hermes ba401d3784 Merge #5079 (OpenAI TTS + SSRF hardening) into stage 2026-06-30 20:39:04 +00:00
nesquena-hermes eb2c4b1e7d fix(#5079): no-redirect opener for OpenAI TTS (block redirect-to-private SSRF + bearer leak)
A public TTS host could 301/302/303-redirect POST /audio/speech to an internal
target (e.g. http://169.254.169.254), and urllib's default redirect handler
would follow it carrying the Authorization bearer — both an SSRF bounce past the
base-url guard and a credential leak. Now uses a no-redirect opener
(_NoRedirectTtsHandler raises on any redirect) via the _tts_open seam. +redirect
rejection regression test. Residual DNS-rebinding TOCTOU (re-resolve at connect)
is a narrower low-severity window noted for follow-up.
2026-06-30 20:37:43 +00:00
nesquena-hermes 6bcb728f08 fix(#5079): block private/link-local/reserved IP targets in OpenAI TTS base_url (SSRF hardening)
The base_url validator accepted any https host; an https URL pointing at an
internal/link-local/loopback/reserved IP (e.g. https://169.254.169.254 cloud
metadata, https://10.x internal) passed the scheme-only check. Now resolves the
host and rejects blocked-target addresses (private/loopback/link-local/reserved/
multicast/unspecified), while still allowing public OpenAI-compatible hosts and
the explicit localhost-over-http dev case. DNS-resolution failure is allowed
(unreachable host can't be an SSRF vector + avoids false-rejecting public hosts
that don't resolve in sandboxed envs). +5 regression vectors.
2026-06-30 20:37:43 +00:00
nesquena-hermes 93d31ebad5 docs(changelog): Kanban modal skills/max_runtime/parents (#4881) 2026-06-30 19:51:22 +00:00
nesquena-hermes 027699b570 Merge #4881 (rodboev Kanban modal fields) into stage 2026-06-30 19:50:46 +00:00
nesquena-hermes b098e5c658 feat(#4676): gate per-project quick-create buttons behind opt-in setting
Add a default-OFF 'project_quick_create_buttons' setting that gates the
per-project '+' quick-create buttons on sidebar project chips. The chip
render site only calls _attachProjectQuickCreateButton when the new
window._projectQuickCreate runtime flag is enabled, so the buttons do
not appear unless the user opts in via Settings.

Mirrors the large_text_paste_as_attachment opt-in plumbing (defaults,
allowlist, settings collect/restore/save, window hydration at both sites,
checkbox row, i18n across all locales).
2026-06-30 19:49:07 +00:00
nesquena-hermes c4b4d874ac docs(changelog): Mermaid toolbar controls in chat (#4871) 2026-06-30 19:27:47 +00:00
nesquena-hermes d954d4c861 Merge #4871 (rodboev Mermaid toolbar) into stage 2026-06-30 19:27:15 +00:00
nesquena-hermes 66714f04e8 docs(changelog): mobile titlebar prioritize session title (#4574) 2026-06-30 19:11:32 +00:00
nesquena-hermes 492fdfb84a Merge #4574 (rodboev mobile titlebar) into stage 2026-06-30 19:10:38 +00:00
nesquena-hermes ea92608e69 docs(changelog): mobile touch targets + approval layout (#5019) 2026-06-30 18:55:07 +00:00
nesquena-hermes 61cc0d167b Merge #5019 (disco32r mobile touch targets) into stage 2026-06-30 18:54:36 +00:00
nesquena-hermes 049b98ad01 docs(changelog): priority-queue batch pq1 (#5168 #5211) 2026-06-30 18:06:34 +00:00
nesquena-hermes c7767f9295 Merge #5211 (search-ranking) into stage-pq1 2026-06-30 18:06:11 +00:00
nesquena-hermes 1f00e4de8c Merge #5168 (pet-handoff) into stage-pq1 2026-06-30 18:06:09 +00:00
nesquena-hermes f07b1315ca docs(changelog): wave-5 (#5161) 2026-06-30 17:25:36 +00:00
nesquena-hermes 121059b384 Merge #5161 (pr/5144-busy-composer-placeholder-hint) into stage-w5 2026-06-30 17:25:03 +00:00
nesquena-hermes ab5a757ffe docs(changelog): wave-4 batch (#5248 #5207) 2026-06-30 17:14:12 +00:00
nesquena-hermes 67a789d9af docs(changelog): wave-3 batch (#5260 #4957) 2026-06-30 17:06:31 +00:00
nesquena-hermes 5370623743 docs(changelog): wave-2 batch (#5266 #5264 #5253 #5244) 2026-06-30 16:36:43 +00:00
nesquena-hermes 62310be565 Merge #5244 (fix/subagent-sidebar-stacking) into stage-w2 2026-06-30 16:35:58 +00:00
nesquena-hermes 4a7159a2ee Merge #5253 (franksong2702/fix-live-worklog-manual-scroll) into stage-w2 2026-06-30 16:35:56 +00:00
nesquena-hermes 3a12ac6bb8 Merge #5264 (fix/large-text-paste-toggle-upstream) into stage-w2 2026-06-30 16:35:55 +00:00
nesquena-hermes 6c5e488579 Merge #5266 (fix/hidden-tab-multipane-attach-bool) into stage-w2 2026-06-30 16:35:53 +00:00
nesquena-hermes 3a2f5cdedb docs(changelog): wave-1 batch (#5276 #5274 #5272 #5256 #5254 #5257) 2026-06-30 16:21:26 +00:00
nesquena-hermes 21233f2df8 Merge #5257 (franksong2702/fix-transparent-live-snapshot) into stage-w1 2026-06-30 16:19:52 +00:00
nesquena-hermes 9dc56a7284 Merge #5254 (pr/5250-settings-search-menu-clip) into stage-w1 2026-06-30 16:19:50 +00:00
nesquena-hermes 90180bd56c Merge #5256 (franksong2702/fix-session-menu-delete-delay) into stage-w1 2026-06-30 16:19:49 +00:00
nesquena-hermes b76264c310 Merge #5272 (fix/5141-terminal-failure-transcript-evaluator) into stage-w1 2026-06-30 16:19:47 +00:00
nesquena-hermes a09bc4e1dc Merge #5274 (pr/5270-cli-webui-continuity) into stage-w1 2026-06-30 16:19:46 +00:00
nesquena-hermes 2ac8162820 Merge #5276 (pr/5273-active-done-viewed-sync) into stage-w1 2026-06-30 16:19:44 +00:00
nesquena-hermes 73ac59ebed docs(changelog): continue /goal after gateway turns (#5251, #5092) 2026-06-30 05:12:20 +00:00
nesquena-hermes e87ed43557 docs(changelog): enforce active profile on request-supplied session IDs (#5198) 2026-06-30 04:43:42 +00:00
nesquena-hermesandstarship-s 468b61e513 fix(auth): release STREAM_SESSION_OWNERS on worker early-return + stale-run prune
Gate hardening for #5198: the new stream-owner map leaked entries on three
paths that bypass the teardown finally — worker early-return when the stream
was cancelled before startup (streaming.py, gateway_chat.py) and the direct
ACTIVE_RUNS stale-zombie prune (routes.py). Each now calls unregister_stream_owner.
Adds a regression test proving the early-return path no longer leaks.

Co-authored-by: starship-s <starship-s@users.noreply.github.com>
2026-06-30 04:39:00 +00:00