[cold-review] feat(web): searchable session picker on share target (#980)#76
Draft
heavygee wants to merge 28 commits into
Draft
[cold-review] feat(web): searchable session picker on share target (#980)#76heavygee wants to merge 28 commits into
heavygee wants to merge 28 commits into
Conversation
…iann#992) * refactor(claude): thread session's selected model into SDKToLogConverter Adds an optional selectedModel field to the converter's context, wired from session.getModel() in the launcher, so a later commit can seed the turn-1 contextWindow estimate for presets whose system/init model arrives without the "[1m]" suffix. No behavior change yet. * fix(claude): key contextWindow cache by model to stop 1M/200k flicker The remote launcher re-emits system/init on every turn for the same converter instance. Its init-time estimate only checked whether the model string ended in "[1m]", but current claude CLI versions strip that suffix from system/init for some 1M presets (fable[1m] arrives as "claude-fable-5"), so the estimate guessed 200k for them. The one authoritative value is result.modelUsage[<model>].contextWindow, which arrives after the heuristic has already injected 200k into that turn's assistant message and then gets clobbered back to 200k by the very next turn's init - producing the observed 200k<->1M oscillation in the web status bar. Cache the authoritative contextWindow per model id instead of a single session-wide number, and only let system/init seed a heuristic guess for a model that has no cached value yet, so a same-model re-init no longer downgrades an already-learned value. Two observed facts about the CLI's model ids drive the design: system/init.model and the result.modelUsage keys always agree with each other within a session (both bare for plain/fable[1m], both suffixed for opus[1m]/sonnet[1m]), while each per-turn assistant message reports its model bare and thus can't distinguish a 200k plain preset from its 1M "[1m]" variant on tiers where they share a base id. So the cache is keyed on the raw id (init/result agree, no normalization) and assistant injection looks the value up via resolvedModel (the last init id) rather than the lossy message.model. Keying raw keeps a plain preset and its [1m] variant on distinct entries; looking up via resolvedModel also means sidechain (Task subagent) messages carry the main session window rather than the subagent's own, since the web status bar picks the most recent usage message without filtering sidechains and would otherwise flicker to the subagent's smaller window while it runs. For presets whose init model arrives bare even though they are 1M (fable[1m]), the originally-selected preset - which preserves the "[1m]" suffix - seeds the turn-1 estimate, kept live across mid-session model switches via updateSelectedModel() (called from the launcher on every turn) so it never goes stale. * fix(web): recognize [1m] suffix on full Claude model ids in budget fallback getContextBudgetTokens already special-cased "[1m]" for short preset values (e.g. "opus[1m]") but fell through to the default 200k budget for full model ids (e.g. "claude-opus-4-8[1m]"), which is what the CLI now reports once context_window isn't available and this fallback is consulted. Check the suffix on that branch too so it stays a correct last-resort even without a session-provided context_window. * refactor(web): merge duplicate Claude context-budget branches isClaudeModelPreset(trimmedModel) and the startsWith('claude-') branch below it had become byte-for-byte identical bodies after the [1m] suffix check was added to both. Merge them into one condition; no behavior change. * fix(claude): distinguish fable from fable[1m] when the CLI reports both bare The per-model contextWindow cache keyed on the raw system/init model id, on the assumption that a 1M preset and its plain form always land on distinct ids. That holds for opus[1m]/sonnet[1m] (the CLI reports the "[1m]" suffix on their init and result ids) but not for fable: the CLI reports both "fable" and "fable[1m]" with the same bare id "claude-fable-5". So the "seed only if not already cached" guard would skip re-seeding when switching fable[1m] -> fable, leaving the stale 1M in place until fable's own result arrived - the same switch flicker this change set out to remove, just for fable specifically. Fold the selected preset's "[1m]" back into the cache key (computeContextWindowKey): when the init model arrives bare but the session selected an "[1m]" preset, key the entry as "<id>[1m]" so the 1M and plain variants stay distinct; ids the CLI already suffixed are left as-is. Seeding, lookups, and the current-model result entry all use this resolved key. Subagent result entries (e.g. haiku) keep their own raw id so the session's "[1m]" is never folded onto a model that isn't the selected one.
* fix(cli): add darwin vm_stat memory percent parser Add readDarwinMemoryUsedPercent, a pure parser that computes macOS used memory as App Memory + Wired + Compressed (anonymous + wired-down + occupied-by-compressor pages), matching Activity Monitor's "Memory Used" figure. Page size is parsed from the vm_stat header rather than hardcoded, since it differs between Apple Silicon (16KB) and Intel (4KB) Macs. Not wired up yet; covered by unit tests, including a verbatim vm_stat capture from a 16GB Mac mini where the pre-fix total - freemem() path reported 99% (counting reclaimable cache as used) while App+Wired+ Compressed is 79% — the number a user sees in Activity Monitor. * fix(cli): wire darwin memory percent into computeMemoryPercent Add a platform() === 'darwin' branch that shells out to vm_stat (1s timeout, guarded by try/catch) and feeds its output to readDarwinMemoryUsedPercent. On any failure or undefined result it falls through to the existing total - freemem() fallback, matching the Linux branch's structure. This fixes the Machine capacity tooltip showing a stuck ~99% "High pressure" warning on macOS runners: os.freemem() there counts reclaimable file cache as used, so it reports near-total usage. Summing only App Memory + Wired + Compressed reports the same figure Activity Monitor shows.
* fix: improve Qwen realtime compatibility * fix: preserve Qwen endpoint query parameters
…nn#957) * feat(web): markdown Source | Preview toggle in session file pane Add Source | Preview toggle for .md/.mdx files in the session file route, defaulting to preview with localStorage persistence. Reuse chat markdown pipeline via MarkdownRenderer standalone mode (no assistant-ui thread). Includes unit tests, Playwright smoke, and e2e fixture. Closes tiann#954 Co-authored-by: Cursor <cursoragent@cursor.com> * fix(web): cast standalone MarkdownRenderer components for react-markdown Soup verify gate: defaultComponents merge type is wider than react-markdown Components; standalone file-pane path needs explicit cast. * fix(web): route file-pane markdown fences through SyntaxHighlighter Standalone file preview now mirrors chat code-block rendering: fenced blocks use SyntaxHighlighter and MARKDOWN_COMPONENTS_BY_LANGUAGE (mermaid included) without requiring ThreadPrimitive context. Addresses HAPI Bot Major on tiann#957. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(web): detect fenced vs inline code in standalone markdown preview Move block detection to the pre override (react-markdown v10 does not pass inline to custom code components). Add inline-code regression test. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Cursor <cursoragent@cursor.com>
* feat(web): mermaid diagram lightbox on click Click rendered mermaid blocks in chat to open a zoomable full-screen viewer. Re-renders from source in the modal with the current theme. Closes tiann#737. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(web): fit mermaid lightbox to viewport on open Auto-scale diagrams to fill the viewer instead of opening at intrinsic mermaid size. Reset returns to fit; zoom label is relative to fit (100%). Co-authored-by: Cursor <cursoragent@cursor.com> * fix(web): fit mermaid lightbox to device screen not inner panel Use visualViewport for fit scale, full-screen pan layer, and a floating toolbar so the diagram can use the whole display. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(web): show mermaid lightbox by reusing inline SVG Second mermaid.render on open often left a 0×0 SVG while fit scale was computed from the loading placeholder. Reuse the inline SVG in the modal and measure viewBox with retried fit-to-screen. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(web): uniquify mermaid SVG ids in lightbox clone Inlining the same mermaid markup twice duplicates element ids and breaks url(#ref) resolution in the modal copy. Prefix ids and hrefs for lightbox only. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(web): give mermaid lightbox SVG explicit dimensions Mermaid emits width="100%" with max-width in px; that collapses to 0×0 inside the centered lightbox layer. Derive width/height from viewBox for the uniquified lightbox clone. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(web): render mermaid lightbox via isolated SVG data URL String id rewrites broke mermaid's embedded CSS so only labels appeared zoomed. Rasterize the inline SVG to a data-URL img instead of duplicating markup in the DOM. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(web): lightbox re-renders SVG for sequence diagrams Data-URL images drop or blank some mermaid diagram types (sequence). Re-render with a modal-specific id into inline SVG on a code-bg panel, and add sequence theme variables for dark/light. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(web): mermaid lightbox uses inline SVG in shadow DOM Reuse the inline render in an isolated shadow root so sequence CSS stays intact, and fit the viewport from viewBox dimensions instead of the loading placeholder or width="100%" layout. Co-authored-by: Cursor <cursoragent@cursor.com> * test(web): Playwright lightbox coverage per mermaid diagram type Add e2e harness and a script that opens the lightbox for each diagram kind (flowchart through kanban). Fit uses inline getBBox() so compact charts like gitGraph fill the viewport. Co-authored-by: Cursor <cursoragent@cursor.com> * test(web): bounded Playwright via webServer, fix gantt fit sizing Playwright owns Vite lifecycle (no agent-spawned dev server). Fit uses viewBox unless viewBox padding is excessive (gitGraph); wide charts use width-based coverage in e2e. Co-authored-by: Cursor <cursoragent@cursor.com> * chore(web): gitignore Playwright test-results Co-authored-by: Cursor <cursoragent@cursor.com> * fix(web): address PR 741 bot feedback (typecheck, fit floor, gitignore) Guard lightbox open when svg is null; allow fit scale down to 0.01 while keeping 0.25 minimum for manual zoom; ignore Playwright test-results/ correctly. Co-authored-by: Cursor <cursoragent@cursor.com> * test(web): Playwright asserts click expands diagram vs inline Measure inline vs lightbox bounding box after click; require visible growth (area ratio or max dimension) plus dialog + shadow SVG content. Co-authored-by: Cursor <cursoragent@cursor.com> * test(web): Playwright against live HAPI session for mermaid lightbox Add seed script for a dedicated chat session, live hub Playwright suite (HAPI_LIVE=1), and dogfood doc. Live tests fail until driver serves shadow-DOM lightbox (catches gray-box regression on stale bundles). Co-authored-by: Cursor <cursoragent@cursor.com> * fix(web): undo wrapper transform in lightbox fit; carry fit floor in zoom Resolves PR tiann#741 review threads (HAPI Bot Major): 1. measureSvgIntrinsicSize / measureContentSize prefer intrinsic dimensions (viewBox -> width/height attrs -> img.naturalSize) before getBoundingClientRect. When the rect is the only signal, divide by scaleRef.current so the 50/200ms refit retries stop compounding with the wrapper's scale(...) transform. Large diagrams no longer jump tiny or oversize after async render completes. 2. Interactive zoom (wheel/keys/buttons/pinch) now clamps with Math.min(MIN_SCALE, baseScaleRef.current). A diagram fitted below the normal 25% floor stays reachable instead of snapping back to 25% and clipping. Zoom-out button disabled threshold uses the same min. 3. Add Vitest coverage for both helpers (intrinsic precedence, scale-aware rect fallback, divide-by-zero guard) so regressions surface without needing the full Playwright stack. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(scripts): mermaid seed refuses to wipe non-fixture sessions HAPI Bot Major (PR tiann#741): SESSION_ID is documented as overridable, and the script unconditionally deletes every message for the target session before seeding fixtures. If pointed at a real session id, that's silent data loss. Refuse to proceed when an existing session id has a tag other than 'mermaid-lightbox-e2e'. New ids and the canonical fixture session still seed normally; real sessions throw before any DELETE runs. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(web): normalize mermaid svg for lightbox shadow root Mermaid emits width="100%" on every diagram. Inside a shadow root whose host has no explicit size, that collapses to zero in Chromium for most diagram types - only ones that ship pixel attrs (e.g. journey) happen to render. Operator confirmed on the live driver: every diagram except journey opened to a grey rounded square. MermaidLightboxSvg now runs normalizeMermaidSvgForStandaloneDisplay before injecting (strips width/height="100%", bakes viewBox dims as pixels) and sets :host{display:inline-block} so the host sizes to the SVG. Inline svg in chat is unchanged - only the lightbox copy is normalized. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(web): keep mermaid lightbox content below the toolbar Operator screenshot showed the diagram top (e.g. pie 'Pets' title) clipped behind the toolbar bar. Two causes: 1. getScreenFitSize used the full viewport height, so the fit scale sized the diagram to fill an area the toolbar overlapped. 2. The viewport (drag/zoom area) was inset-0; content centered on the full viewport center, not the visible region's center, pushing the top behind the toolbar. Measure the toolbar with a ResizeObserver, subtract its height from the fit calculation (clamped at zero), and start the viewport region below the toolbar (top: toolbarHeight). Fit scale recomputes whenever toolbar height changes. Adds Vitest coverage for getScreenFitSize reserved-top math. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(web): guard ResizeObserver before constructing it HAPI Bot Major (PR tiann#741): Vitest jsdom does not polyfill ResizeObserver, so the toolbar measure effect throws ReferenceError when the existing mermaid-diagram React tests open the lightbox. Same code path is also brittle in any browser/webview without the API. Fall back to plain window 'resize' listener when ResizeObserver is absent. Toolbar height won't auto-update on element resize without it, but the lightbox still renders and the resize listener catches the common viewport-rotation case. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(scripts): live mermaid playwright wrapper runs from repo root HAPI Bot Minor (PR tiann#741): the wrapper sets cwd to scripts/, but the test:mermaid-lightbox:live npm script lives in the repo-root package.json, so spawning npm there exited before Playwright started. Switch cwd to the repo root and drop the unused WEB_DIR constant. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(web): accept signed viewBox values in mermaid lightbox normalize HAPI Bot Minor (PR tiann#741): the viewBox regex only matched digits, dots, and spaces, so a valid viewBox with negative origin (e.g. '-8 -8 640 480') returned null. normalizeMermaidSvgForStandaloneDisplay then became a no-op and left width='100%', re-introducing the zero-sized lightbox render this PR is meant to fix for the affected diagrams. Switch to the bot's suggested regex (signed numbers, single or double quotes, comma or space separators) and reject NaN parts. Adds Vitest coverage for signed origins, single quotes, comma separators, the malformed/no-viewBox null paths, and an end-to-end normalize test that fails against the old regex. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(web): align @playwright/test on 1.60.0 across workspaces HAPI Bot Major (PR tiann#741): web/package.json pinned @playwright/test at 1.49.1 while the root workspace and bun.lock were on 1.60.0. The mismatch surfaced after rebasing onto upstream/main, where the root had already moved to 1.60.0 while my web devDependency lagged from an older commit. A frozen install would reject the lockfile and the new web e2e script could resolve a different Playwright than root scripts. Bump the web devDependency to 1.60.0 and regenerate bun.lock so all workspaces share one Playwright version. Co-authored-by: Cursor <cursoragent@cursor.com> * fix(web): move mermaid playwright fixtures out of public HAPI Bot Minor (PR tiann#741): the e2e and smoke fixtures lived under web/public, so Vite copied them verbatim into web/dist and the hub asset generator embedded them in production bundles. Both pages import Vite dev-only paths (/@react-refresh and /src/dev/...), so the production /mermaid-lightbox-{e2e,smoke}.html routes would 404 on those imports. Move both fixtures to web/e2e-fixtures/ to match the existing scratchlist-fixture pattern (relative ../src/dev import, served by Vite at /e2e-fixtures/...) and update the Playwright spec to hit the new path. Build now ships 112 PWA precache entries instead of 114 (both fixtures excluded from dist). Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Cursor <cursoragent@cursor.com>
Use semantic events as the visible text source and preserve completed plans as ordered plan proposal cards.
* fix(codex): support model-reported reasoning efforts * fix(web): prevent service worker edge caching * ci: retrigger stuck Actions run * fix(codex): accept dynamic reasoning effort values * fix(web): restore reasoning effort on model switch failure
* test: reproduce issue tiann#1020 * fix: preserve Codex safety behavior (closes tiann#1020) * test: cover Codex safety buffering dismissal * test: cover Codex safety retry edge cases * fix: keep dismissed safety buffering prompts hidden
Surface the same reasoning label already shown in the composer StatusBar in the top SessionHeader for codex/opencode sessions. Also show an explicit Fast badge only when serviceTier is fast (tiann#1004-aligned). Closes tiann#1015 (header display portion). Co-authored-by: Cursor <cursoragent@cursor.com>
…ir (tiann#1014) * feat(cursor): multitask slash, autoReview mode, native worktree/add-dir Close the highest-value Cursor Agent gaps for remote HAPI: expand ACP-safe slash pass-through (/multitask, worktree, add-dir, …), add autoReview permission mode (--auto-review spawn + mid-session slash), and route Cursor New Session worktrees through agent --worktree instead of HAPI sibling trees. Fixes tiann#1013 Co-authored-by: Cursor <cursoragent@cursor.com> * fix(cli): accept --mode autoReview for hapi cursor Align --mode parsing with CURSOR_PERMISSION_MODES so documented `hapi cursor --mode autoReview` enables Smart Auto instead of silently falling back to default. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: Cursor <cursoragent@cursor.com>
* fix(codex): bridge MCP elicitation through user input * fix(codex): allow MCP elicitation in yolo mode * fix(codex): preserve MCP form semantics * fix(codex): accept implicit MCP form mode * fix(codex): harden MCP elicitation prompts * fix(codex): require valid MCP choice answers * fix(codex): round-trip MCP array elicitation * fix(web): require explicit MCP URL confirmation * fix(codex): preserve MCP array item types * fix(codex): support multi-select MCP elicitation * fix(codex): allow MCP elicitation in read-only mode * fix(codex): route MCP tool approvals through permissions
Co-authored-by: LIUZHIRU <ryuu@fine-net.co.jp>
* test: define Grok Build integration behavior * feat: add Grok Build agent integration * test: cover Grok permissions and resume paths * docs: add Grok Build setup guide * fix: scope Grok ACP discovery to session cwd * fix: align Grok permission UI semantics * docs: clarify Grok runner setup * test: require Grok create model and effort options * feat: add Grok create model and effort pickers * test: define Grok runtime parity behavior * feat: add Grok runtime ACP controls and discovery * fix: tighten Grok runtime controls * fix: suppress nonfatal Grok title quota errors * feat: support Grok Auto permission mode * feat: forward ACP native session titles for Grok * fix: guard Grok Windows shell arguments
…n#1026) Legacy rows and inserts left sessions.active_at NULL while SessionSchema required a number, so CLI GET /cli/sessions/:id failed Zod and resume surfaced HTTP 500. Persist active_at on insert, harden hub read coerce, and nullish-transform activeAt in SessionSchema (output stays number). Fixes tiann#1025 Co-authored-by: Debian <heavygee@oos-linux.in.lockhouse> Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: zj1123581321 <zj1123581321@users.noreply.github.com>
Add search to the Android share-target picker so operators can attach shared content to inactive or older sessions, not just recent actives. Reuses sidebar search helpers; caps default active list with a search hint. Co-authored-by: Cursor <cursoragent@cursor.com>
ShareSeedConsumer was consuming the sessionStorage transfer id on first mount even when the target session was inactive. Reopening into a new session id remounted the chat with the key already gone, dropping the shared payload. Consume and seed only after sessionActive is true. Co-authored-by: Cursor <cursoragent@cursor.com>
fe47607 to
cdaa996
Compare
Deferring consume until active left a global pending slot that the next unrelated active SessionChat could claim. Bind the pending transfer to the picked session id, retarget on reopen/spawn id-swap, and only consume when the mounting session matches. Co-authored-by: Cursor <cursoragent@cursor.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fork-side cold-review stage PR. Not for merge.
Upstream target: tiann#980
See branch feat/share-target-session-search for the upstream-ready diff (web/ only, 6 files).
Made with Cursor