Commit Graph
583 Commits
Author SHA1 Message Date
wushenghua 032fb3c6e1 fix(web): re-subscribe push when VAPID key changes (stale hub subscriptions) 2026-08-03 14:58:40 +08:00
SSU-WEI HUANGandGitHub cd570adf66 Improve fork and rewind actions (#1336) 2026-08-03 12:33:06 +08:00
weixiang1862andGitHub cc39021abc feat(web): show hidden directories in workspace browser (#1331)
* feat(web): show hidden directories in workspace browser

Add optional includeHidden param to the machine list-directory RPC so the
WorkspaceBrowser can toggle hidden (dot-prefixed) entries. Default remains
filtered for backward compatibility; the toggle persists via localStorage.

* fix(web): disable show-hidden toggle while directory loading

Prevent overlapping list-directory requests with opposite includeHidden
values; the toggle is now disabled while a directory load is active.
2026-08-03 12:32:50 +08:00
SSU-WEI HUANGandGitHub a111d0bc82 feat: use official Pi agent logo (#1335)
* feat: add official Pi agent logo

* fix: honor selected theme for Pi logo
2026-08-03 12:32:39 +08:00
2d904de76e fix(web): migrate chat-path attachments on scratchlist park (#1227)
* fix(web): migrate chat-path attachments on scratchlist park (#1226)

When an image is attached via the normal upload adapter before scratchlist
mode is enabled, toggling mode swapped adapters and send() dropped the
metadata — park stored text-only and cleared chips. Migrate pending
chat-path files into hub scratchlist storage on send, and fail closed if
non-hub paths still reach the park wrapper.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(web): defer chat-path cleanup until scratchlist park succeeds

send() migrates before scratchlist.add; deleting the original upload
there left retries pointing at a missing chat blob when park failed.
Stamp migratedFromPath and clean up only after the park attempt result.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(web): park scratchlist before composer.send clears chips

assistant-ui empties text/attachments before onNew, so return false from
park could not restore retryable state and rejected cleanup deleted the
migrated hub blob. Intercept park from a live snapshot; clear only after
accept; releaseWithoutDelete so clearAttachments keeps parked hubs.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(web): lock composer while scratchlist park is in flight

Disable input/send and hide chip remove during migrate+add so mid-flight
edits are not wiped on success and hub blobs are not deleted out from
under the accepted entry.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(web): do not clear composer if park snapshot changed mid-flight

Compare post-await composer state to the pre-park snapshot before
clearing; disable DragDropZone and scratchlist promote while parking
so parent paths cannot add chips the clear would silently drop.

Addresses Codex Major on #1227 (preserve post-snapshot composer changes).

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(web): defer migrated chat-path cleanup until park snapshot clears

Return ScratchlistParkResult.beforeClear from onParkScratchlist so
finalizeMigratedScratchlistParkCleanup runs only after HappyComposer
confirms the composer was unchanged mid-flight.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(web): flush rich mentions before scratchlist park snapshot

Park snapshots composer.text after flushSerializedText so session
@-mention chips serialize to markdown links before scratchlist add.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(web): validate park snapshot before scratchlist add

Split prepare/commit/abort so mid-flight composer edits abort orphan
hub blobs instead of parking a duplicate. Reuse restored hub paths in
prepareScratchlistParkAttachments so remounted chips do not re-upload.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(web): ignore scratchlist toggle hotkey while park is in flight

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-03 10:39:01 +08:00
SSU-WEI HUANGandGitHub c3a5522207 Add realtime dictation providers (#1329)
* feat: add realtime dictation providers

* fix: cancel realtime dictation startup

* fix: refresh local dictation availability

* fix: preserve dictation on disconnect

* fix: normalize OpenAI language hints
2026-08-03 10:03:06 +08:00
3c3bffdfbd feat: message-level conversation fork and rewind (#1263)
* feat: add message-level conversation fork and rewind

Expose native Codex/Grok/Claude history controls through hub REST+RPC and web ConfirmDialog actions, without file rewind or composed forks. Also reconcile the duplicate hub V14→V15 migration so typecheck can pass.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix: hydrate fork transcript and consume Claude --fork-session

Forked HAPI children now copy the source transcript prefix so navigation is not a blank thread, and Claude drops --fork-session after the first launch so relaunches do not branch again.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix: harden fork/rewind concurrency and durable history points

Skip pending scheduled rows when hydrating fork transcripts, serialize fork/rewind per session, and persist conversation history points/indexes across existing-session bootstrap and Grok relaunches.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix: close remaining fork/rewind races and UI anchoring

Block sends and scheduled maturation while history actions run, order fork prefixes by invocation time, inherit history locators into children, and only offer Fork current on the live tail boundary.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix: address remaining fork/rewind bot findings

Materialize Claude --fork-session before the first child prompt, validate
HAPI history boundaries before native RPC, expose forkCurrent on a latest
user boundary, fully demote unsupported conversationHistory capabilities,
and fix the truncate test setup order.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix: align fork-current ids and Claude fork bootstrap

Compare the latest fork boundary in assistant-ui threadMessageId space,
spawn Claude forks with the persisted session mode, and preserve
forkedFrom across existing-session bootstrap.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix: close fork/rewind consistency holes at the contract layer

Hold the source history lock until Claude child binds a distinct native
id, persist Codex localId→turnId locators, and mark/block diverged
sessions when native rewind outruns HAPI truncate.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix: use Codex stable lastTurnId for historical fork

Map HAPI's exclusive boundary to the previous turn's inclusive
lastTurnId so native fork context matches the hydrated transcript.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix: require exact Grok native resume for fork children

Reject newSession fallback when forkedFrom is set, and keep the hub
history lock until the child binds the forked grokSessionId.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix: kill active fork children before failed-fork cleanup

Bind/readiness failures can leave the child process running; deleteSession
rejects active rows, so terminate first then remove the HAPI session.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix: close remaining fork lock, hydrate, and todos gaps

Reject mode switches during history actions, batch-copy fork
transcripts in one SQLite transaction, and rebuild todos after
fork hydrate / rewind truncate.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix: allow Codex historical fork before the first turn

Use experimental beforeTurnId when there is no previous turn for the
stable inclusive lastTurnId boundary.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix: mark Grok history busy immediately after dequeue

Hub idle checks clear once messages-consumed fires; hold the busy flag
across permission sync and rewind-points lookup before prompt starts.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix: encode copied conversation history content

* fix(web): hide local conversation history actions

* style(codex): remove trailing whitespace

* fix(fork): preserve children when cleanup is unconfirmed

* fix(history): confirm cleanup and guard rewind divergence

* fix(history): probe capabilities before advertising

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-03 09:28:01 +08:00
AnanovoandGitHub 3f03e8daa1 feat(web): add expandable message composer (#1319)
* feat(web): add expandable message composer

* fix(web): preserve composer selection when expanding

* fix(web): keep composer toolbar actions tappable

* fix(web): preserve composer escape behavior

* fix(web): apply overflow-safe toolbar alignment
2026-08-03 09:27:12 +08:00
KorenKritaandGitHub aff2c1225d fix(web): preserve uploads when previews fail (#1323) 2026-08-03 09:26:13 +08:00
KorenKritaandGitHub b8481c9ece fix(web): keep autocomplete results query-stable (#1321)
* fix(web): keep autocomplete results query-stable

* fix(web): hide stale published suggestions
2026-08-03 09:26:00 +08:00
KorenKritaandGitHub 413fbb8714 fix(web): preserve queued edits across cancellation (#1324) 2026-08-03 09:25:45 +08:00
KorenKritaandGitHub 52dda73045 fix(web): align rich composer DOM and Unicode boundaries (#1325)
* fix(web): align rich composer DOM offsets

* fix(web): truncate session titles safely

* fix(web): preserve session title size bounds

* fix(web): normalize empty wrapper offsets
2026-08-03 09:25:25 +08:00
KorenKritaandGitHub fb3988a81f fix(web): restore failed sends atomically (#1326)
* fix(web): restore failed sends atomically

* fix(web): wait for composer draft hydration

* fix(web): count restored attachments after success

* fix(web): keep scratchlist copy available

* fix(web): move suppressed retry errors to target session
2026-08-03 09:25:01 +08:00
wushenghuaandGitHub 0725fabe84 feat(web): pin running sessions in an in-progress section with state badges (#1315)
* feat(web): pin running sessions in an 'in progress' section with a live badge

* feat(web): show project name on pinned running session rows

* feat(web): make the pinned 'in progress' section collapsible

* fix(web): don't auto-expand directory groups when opening pinned running sessions

* fix(web): keep running section open while searching; clear auto-expand guard when selection leaves a group

* feat(web): show machine label on pinned running session rows

* fix(web): make running-section toggle keyboard-accessible with correct filtered state

* feat(web): split pinned running section into working/pending/idle groups with distinct badges
2026-08-03 09:24:44 +08:00
SSU-WEI HUANGandGitHub 9d07857570 Add provider-backed dictation mode (#1327) 2026-08-03 06:05:58 +08:00
AnanovoandGitHub fb6f697555 fix(web): display Windows file search paths correctly (#1311)
* fix(web): display Windows file search paths correctly

* fix(hub): scope path normalization to Windows
2026-08-02 20:04:46 +08:00
AnanovoandGitHub a6f302ebd1 fix(web): preserve mobile scroll intent after pointer cancellation (#1312)
Keep touch and pen input eligible to cancel initial bottom settling when native panning dispatches pointercancel before scroll. Add interaction coverage for the mobile event sequence and unrelated global cancellations.
2026-08-02 19:53:31 +08:00
AnanovoandGitHub f018c6027b fix(web): restore composer attachment uploads (#1313) 2026-08-02 19:49:03 +08:00
SSU-WEI HUANGandGitHub 5b91504263 Add read-only session status panel (#1301)
* feat(web): add session status panel

* fix(web): include nested session activity

* fix(web): preserve incomplete status details

* fix(web): handle anonymous terminal completion

* fix(web): classify pending status accurately

* fix(web): retain ambiguous terminal candidates
2026-08-02 17:33:54 +08:00
KorenKritaandGitHub b7da8d3ab2 fix(web): show Pi reasoning effort (#1303) 2026-08-02 17:33:29 +08:00
KorenKritaandGitHub 147102a877 fix(web): preserve rich composer caret (#1305) 2026-08-02 17:33:15 +08:00
AnanovoandGitHub 68299631f9 feat(web): customize composer toolbar visibility (#1298) 2026-08-02 13:14:00 +08:00
AnanovoandGitHub 74ec247b92 fix(web): make inactive session notices flush with headers (#1299) 2026-08-02 13:04:27 +08:00
KorenKritaandGitHub 1ca7af44d2 fix(pi): keep archived sessions visible (#1297) 2026-08-02 10:00:15 +08:00
SSU-WEI HUANGandGitHub f213bc348c fix(web): require user intent to cancel initial scroll (#1291)
* fix(web): require user intent to cancel initial scroll

* fix(web): snapshot scroll intent before consumption
2026-08-02 09:27:37 +08:00
SSU-WEI HUANGandGitHub 545af9b4e0 fix(pi): expose native skills through $ completion (#1286) 2026-08-02 08:49:46 +08:00
SSU-WEI HUANGandGitHub 2556729ba8 fix(codex): use app-server native skills (#1289)
* fix(codex): use native skill catalog

* fix(codex): refresh changed skill inventory

* fix(codex): preserve skill fallback on discovery error

* fix(web): refresh skills when completion opens
2026-08-02 08:49:35 +08:00
SSU-WEI HUANGandGitHub 82da539d32 fix(claude): separate skills from slash commands (#1293)
* fix(claude): separate skills from slash commands

* fix(claude): make native skills ready before use

* fix(claude): keep skill commands before attachments

* fix(claude): align skill catalog with launch args

* fix(claude): include launch plugin skills

* fix(claude): use native loaded skill list

* refactor(claude): remove obsolete metadata callback

* fix(claude): wait for skill catalog before draining messages

* fix(claude): cancel deferred startup messages

* fix(claude): bound skill catalog startup probe
2026-08-02 08:49:14 +08:00
SSU-WEI HUANGandGitHub 4683b0cb47 fix(web): refresh skill inventories (#1295) 2026-08-02 08:48:56 +08:00
weishu 9b299eaab7 feat(web): migrate to @assistant-ui/react 0.14 (tap 0.9.8 with update-depth fix)
- @assistant-ui/react ^0.11.53 -> ^0.14.29, react-markdown ^0.11.9 -> ^0.14.7
- resolves @assistant-ui/tap 0.9.8, which ships the upstream fix for
  bulk message prepends (per-scheduler MAX_UPDATE_DEPTH guard, PR
  assistant-ui/assistant-ui#5370) that the local patch covered for 0.3.5
- API migration: useAssistantApi -> useAui, useAssistantState -> useAuiState
  with s.* selector access; TextMessagePart type-guard for content.find;
  portable DefaultComponentsMap annotation for memoizeMarkdownComponents

Verified: tsc clean, 1762 unit tests, history-load e2e 12/12 against the
unpatched upstream scheduler.
2026-08-02 00:12:29 +08:00
weishu 58ff91e5c4 fix(web): correct context window calculation for local-mode sessions
Remote sessions get an authoritative context_window injected into usage by
the CLI (from SDK result modelUsage), but local-mode sessions forward raw
transcript JSONL whose usage has no context_window, so the web fell back to
getContextBudgetTokens — which could not tell Fable's 1M window from its
bare id (only the "[1m]" suffix was recognized) and received session.model,
which is usually null for local sessions, defaulting to a 200k budget. A 1M
Fable session with ~256k of context showed 135% used with an over-limit
warning instead of ~26%.

- modelConfig: recognize Fable ids (fable, fable[1m], claude-fable-*) as 1M
- reducer: LatestUsage carries the usage-bearing message's own model
- StatusBar: new contextModel prop feeds the fallback heuristic only;
  the model prop's other semantics are unchanged
- HappyComposer forwards it; SessionChat passes
  latestUsage.model ?? session.model
2026-08-02 00:00:55 +08:00
AnanovoandGitHub 0537ddf84a feat(web): make session header metadata configurable (#1267)
* feat(web): make session header metadata configurable

* fix(web): align mobile header metadata priority
2026-08-01 23:26:17 +08:00
Haoqing WangandGitHub 079556b43a fix(web): stop flashing the reconnecting banner on self-healing blips (#1230)
EventSource reports an error the moment a connection drops, including
while it is already retrying by itself - readyState is still CONNECTING
and the stream is typically back within a few seconds. useSSE forwards
that straight to onDisconnect, and App turned it into a full-width
"reconnecting" banner synchronously, so a blip the browser recovered from
on its own still read as a broken network.

Route the disconnect through a small hook that waits out a grace period
first. Genuine outages still surface the banner, just a moment later;
recoveries that beat the timer stay silent. The sibling syncing banner
already debounces this way in useSyncingState.

The grace period is anchored to the first drop, so repeated failed
retries cannot push the banner back indefinitely.
2026-08-01 23:25:40 +08:00
AnanovoandGitHub 6aae44498d fix(web): align browse button and select chevrons (#1279)
* fix(web): align new-session browse button

* fix(web): inset select chevrons
2026-08-01 22:55:21 +08:00
Junmo KimandGitHub 084d3462cf fix(web): keep line numbers clear when code wraps (#1260)
* fix(web): reserve code gutter padding

* fix(web): expose diff wrap controls

* test(ci): run terminal wrap regression
2026-08-01 17:11:40 +08:00
AnanovoandGitHub bbcef8c300 fix(web): preserve share export layout fidelity (#1277)
* fix(web): preserve share export layout fidelity

* fix(web): keep mobile and multi-image exports responsive

* fix(web): distinguish coarse pointers from touch desktops
2026-08-01 17:10:51 +08:00
AnanovoandGitHub 01bffa3c8c fix(web): stabilize chat scrolling and mobile alignment (#1278)
* fix(web): stabilize chat scrolling and mobile alignment

* fix(web): scope chat scroll containment
2026-08-01 17:10:38 +08:00
AnanovoandGitHub fd20e584d6 feat(web): refine composer status bar (#1281) 2026-08-01 17:09:49 +08:00
weishu 51d8c04e0a feat(web): collapse session machine filter into header menu on mobile
Replace the always-visible wrapping chip row below the md breakpoint with a
filter icon button in the session list header (right side, next to the new
session button). The button opens a radio menu with per-machine counts and
an inline health summary, shows an active-filter dot, clamps to the
remaining viewport/safe-area space, and supports Escape/Arrow-key
navigation with focus restore. Desktop keeps the one-tap chip bar.
2026-08-01 13:26:15 +08:00
weishu b1b0d590a7 feat(web): hide browse affordances unless a machine reports workspace roots 2026-08-01 11:36:12 +08:00
weishu b6897ee736 feat(web): replace session list refresh button with pull-to-refresh
Remove the refresh icon button from the session list toolbar and make
the list itself the refresh affordance via a touch pull gesture.

Gesture (SessionList):
- Touch listeners on the scrollable list container; pull engages only
  at scrollTop 0, with 16px feedback / 64px trigger thresholds, and
  fires on release past the trigger. Mirrors the established
  pull-to-load-older pattern in HappyThread.
- Touch-only by design: desktop has no overscroll bounce, so a wheel
  pull feels broken; desktop keeps relying on SSE live updates and
  query focus refetch.
- onRefresh widened to () => Promise<unknown> | void so the indicator
  tracks the in-flight refetch and ignores re-entrant pulls.

Feedback:
- Status pill over the list (role=status, aria-live) shows
  pull/release/refreshing states with a spinner while refreshing; it
  also covers the initial useSessions load (isLoading), which lost its
  only busy indication when the toolbar button was removed.
- The success toast is dropped (the pill is the feedback); the failure
  toast is kept. handleRefresh now returns its promise.

Empty states (review P2s):
- SessionsEmptyState and the no-results message move from the shrink-0
  header container into the scroll container, so the gesture works on
  the visible empty state (retry path after a failed initial fetch)
  and short viewports scroll instead of crushing the gesture area.
- SessionsEmptyState is gated on !isLoading so a slow initial request
  no longer flashes the final empty state with active actions.

i18n: add sessions.refresh.pull/release/refreshing (en + zh-CN),
remove now-unused button.refresh and sessions.refresh.success.*.
Desktop wheel pull was implemented and then reverted after review.
2026-08-01 10:37:09 +08:00
AnanovoandGitHub 39da5c4b8e fix(web): align compact dialog titles (#1253) 2026-07-31 18:17:57 +01:00
AnanovoandGitHub f985d56ba5 fix(web): open Windows absolute file paths in session viewer (#1113) 2026-07-31 18:17:45 +01:00
Junmo KimandGitHub 770439730a fix(web): keep abort next to Send by default (#988)
* refactor(web): pin abort button to end of composer left cluster

Abort's position shifted with conditional siblings (terminal/switch/
schedule), making the destructive action's location unpredictable.
Move it to the last child of the left button group so it's always
immediately left of Send — pure JSX reorder, no markup/props/handler
changes.

* fix(web): keep abort last in default toolbar

Keep the product default predictable without changing saved custom order or the registry used to append missing items.
2026-07-31 18:17:34 +01:00
SSU-WEI HUANGandGitHub 7ad454f9a2 fix(web): prioritize session names in narrow sidebar (#1029) 2026-07-31 18:17:23 +01:00
da921821ee fix(web): show Auto instead of Default for Cursor model picker (#1248)
* fix(web): show Auto instead of Default for Cursor model picker

Cursor CLI uses `auto` for automatic model selection; labeling it
"Default" in HAPI was confusing and inconsistent with `agent --list-models`.

Fixes #1247

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(web): align Cursor unavailable copy with Auto label

Co-authored-by: Cursor <cursoragent@cursor.com>

* chore: re-trigger Codex PR review

Co-authored-by: Cursor <cursoragent@cursor.com>

* docs(web): update Cursor catalog JSDoc for Auto label

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-31 18:17:11 +01:00
SSU-WEI HUANGandGitHub 259d69cd8f fix(web): show composer status for Cursor (#1250) 2026-07-31 18:16:52 +01:00
weishu 3f73a5f6ef feat(web): collapse session search into the sidebar toolbar row
Move the session-list search out of its dedicated full-width row and
into the sidebar toolbar, so the sidebar gets one compact header row
instead of two stacked rows.

Behavior:
- Collapsed by default: a search icon sits at the left of the toolbar
  row, on the same line as the existing tool icons (codex import,
  refresh, browse, settings, new session).
- Clicking the icon expands the input to fill the entire row width
  (tool icons hide) and focuses the input; when focus leaves the
  search container the input collapses back to the icon.
- Query and date range stay applied while collapsed; the icon shows
  an indicator dot whenever any filter is active.
- The date-range picker stays inside the expanded input.

Implementation:
- SessionList gains a headerActions prop and renders a single header
  row: [collapsible search] [spacer] [optional renderHeader plus]
  [headerActions].
- SessionsPage drops its own toolbar wrapper and passes its five
  buttons through headerActions instead.
- The safe-area top inset moves to the router container wrapping both
  the error banner and the list, so iOS PWA error text no longer sits
  beneath the status bar/notch.

Focus handling (review follow-ups):
- Controls that unmount themselves on click (clear-query X, picker
  backdrop, range-end selection, picker footer Clear) silently moved
  focus to <body>, leaving the search expanded but no longer
  collapsible via blur. Each now returns focus to the input; the
  picker footer Clear is wired through a dedicated onClear prop.
- Header actions can no longer be suppressed by a stale expanded
  state: they render whenever the search control itself is absent
  (e.g. the session list empties via SSE), and the expansion resets
  when the list becomes empty.

i18n: add sessions.search.open (en / zh-CN).

Tests: adapt existing search/date-filter tests to expand the search
before interacting; add regressions for collapse-on-blur query
persistence, focus restore after clearing the query and after
clearing the date range, and header actions surviving an emptied
session list.
2026-07-31 19:52:27 +08:00
bc543dc494 feat: rich composer session @-mentions + inspect_peer (#1228)
* feat(web): feature-flagged rich composer for inline session @ mentions

Custom segmented contenteditable (not TipTap) inserts caret-local session
atoms from the existing @ picker and serializes to markdown links on send.
Textarea path remains default until flag parity dogfood.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(web): rich composer mention boundary + #1215 refs

Treat U+FFFC mirror atoms as word boundaries so @ after a session
token still opens autocomplete. Point comments at Fixes #1215.

Co-authored-by: Cursor <cursoragent@cursor.com>

* test(web): peer-stack e2e for rich composer session @ mentions (#1215)

Smoke: flag on, @ picker inserts inline session atom chip (not prose dump).
Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(web): preserve newlines in rich composer Enter-newline mode

Chromium splits contenteditable on Enter into block divs; serialize those
as \\n and insert <br> when parent leaves Enter unhandled (Shift+Enter /
enter-inserts-newline).

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(web): show @ badge when rich composer mentions flag is on

Dogfood was invisible: flag-off looks like a normal textarea, and flag-on
had no chrome. Surface a small @ badge when enabled.

* fix(web): rich session composer on by default (not a user setting)

The plan dual-path was an engineering kill-switch, not an opt-in. Default
to the segmented composer; only richMentions=0 disables. Drop the flag
badge and record a peer-stack motion proof covering chips + baseline UX.

* fix(web): make rich composer Shift+Enter create a visible newline

Trailing <br>+empty text node was a silent no-op at EOL. Use
insertLineBreak (ZWSP pad fallback), assert real \\n in peer e2e.

* feat(web): hover tooltips on rich composer session chips

Show full title, status, short id, and path on chip hover via a portal
bubble fed by live useSessions lookup (drafts fall back to title + id).

* fix(web): dismiss rich composer chip tooltips on mouse leave

contenteditable pointerout/relatedTarget was flaky so tips stuck after
leaving the chip. Hit-test on pointermove, clear on prose/input/leave.

* fix(web): address cold-review Blocker/Majors on rich composer

Exclude peer e2e from default Playwright; force plain-text paste; restore
newline hard-stop in findActiveWord; fix root-anchored selection mapping
and nested-block serialize; cover with unit tests.

* chore: drop accidental .cursor files from rich-composer tip

* fix(web): close remaining cold-review gaps on rich composer

Drop absolute peer e2e tooling imports, prove chip→markdown send, and
harden paste/EOL/focus/tooltip/Enter edges before Meta rematerialize.

Co-authored-by: Cursor <cursoragent@cursor.com>

* chore: absorb soup playwright.config union for clean remat

Keep fork peer-stack timeouts/annotated-video wiring and add testIgnore
for e2e/peer so the next driver rematerialize does not conflict.

Co-authored-by: Cursor <cursoragent@cursor.com>

* revert: drop fork playwright tooling from upstreamable tip

Peer-stack annotated-video + HAPI_PEER wiring stay on fork main / soup.
Product tip only needs testIgnore for e2e/peer (see docs/tooling/peer-stack.md).

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(web): fix rich composer Shift+Enter double newline and paste space

Prefer manual newline+pad over execCommand insertLineBreak, and stop
applying autocomplete trailing-space on paste/drop paths.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(web): pad EOL Shift+Enter after Range.insertNode split

insertNode always leaves an empty text sibling, so !nextSibling never
saw EOL; detect meaningful trailing content and cover with jsdom tests.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(web): drop custom onDrop from rich composer

Intercepting drop without caretRangeFromPoint landed text at EOF or
no-oped in-editor moves. Native CE drop is enough for #1215; paste
still forces plain text.

Co-authored-by: Cursor <cursoragent@cursor.com>

* feat(web): sidebar-parity tooltips on rich composer session chips

Reuse SessionRowSummary (flavor, thinking/attention, schedule, todos,
relative ago, path) for chip hover so the tip matches the session list.

Co-authored-by: Cursor <cursoragent@cursor.com>

* chore: keep peer-stack e2e off the upstreamable tip

Peer specs and playwright.peer.config stay on fork main per
docs/tooling/peer-stack.md; default config still testIgnore's e2e/peer.

Co-authored-by: Cursor <cursoragent@cursor.com>

* feat: cite sessions with UUID wire + inspect_peer for agent/overseer

Rich composer chips already serialize to [title](/sessions/<id>); flush
before send so the agent prompt never gets title-only chip text. Add
inspect_peer (MCP + hapi inspect-peer) as the read twin of ping_peer so
that same id is immediately usable for overseer/agent peer lookup, with
system-prompt glue from citations to inspect/ping.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(cli): gate inspect_peer behind permission approval

Cross-session history reads need the same prompt path as ping_peer:
keep inspect_peer off Claude --allowedTools and treat it as sensitive
in ACP/OpenCode read-only mode so prompt injection cannot silently
enumerate peer transcripts.

Co-authored-by: Cursor <cursoragent@cursor.com>

* chore: clarify playwright peer testIgnore is upstream-safe

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(web): keep session UUIDs on rich composer copy/cut/paste

Copy/cut write wire markdown so chips do not collapse to @title-only
clipboard text; paste reparses session links back into atoms.

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-31 19:42:56 +08:00
AnanovoandGitHub c5f1928eb0 fix(web): consolidate Codex import in new session (#1240)
* fix(web): consolidate Codex import in new session

* fix(web): clear imported Codex history selection
2026-07-31 18:12:30 +08:00