Commit Graph

609 Commits

Author SHA1 Message Date
pewdiepie-archdaemon cc86c3dd04 Email reader: +4px breathing room under wrapped 2-row cluster (92→96px) 2026-06-12 07:52:31 +09:00
pewdiepie-archdaemon 32898a68eb Email reader: header grows on wrap + no slide-down at overlay break
1. Moved the min-height from .email-reader-header to .email-reader-meta
   (92px) inside the <600 container query. Targeting the container
   itself in its own @container rule was flaky; using a descendant
   that affects the parent's intrinsic height works reliably.
2. Dropped the margin-top:0 reset on the cluster in the <380 overlay
   rule — that was clearing the base -7px lift and sliding the
   cluster ~7px downward at the breakpoint. Now both states use the
   same -7px lift so the visual position is stable across the
   transition.
2026-06-12 07:50:48 +09:00
pewdiepie-archdaemon 55e438d18c Email reader: prune competing rules from grid-era refactor
Dropped the @media(769px) from-row min-height + align-items:center
and the strong > top:-2px nudge — leftovers from the grid layout
that were forcing extra height and label offsets the block-flow
meta doesn't need.

Consolidated docked overrides into a single flat block (no @media
wrapper) and merged the two .email-reader-meta declarations into
one. Same visual result, much less competing CSS to debug.
2026-06-12 07:50:02 +09:00
pewdiepie-archdaemon a653f74cab Email reader: grow header min-height to fit wrapped 2-row cluster
When the cluster wraps to 2 rows (44 + 4 gap + 44 = 92px tall), it
was peeking out below the header bottom because min-height stayed
at 60px (only ~44px of cluster room). Bumped min-height to 108px
inside the same <600 container query so the wrapped cluster sits
fully inside the header with 8px breathing room top + bottom.
2026-06-12 07:42:31 +09:00
muhamed hamed 3b3c0d6254 fix: detect HuggingFace token when downloading cookbook models (#3459)
Co-authored-by: Alexandre Teixeira <111787685+alteixeira20@users.noreply.github.com>
2026-06-11 21:53:16 +01:00
Michael c0cc0f954c fix: read allow_bash/allow_web_search from JSON body (#3229) (#3281)
* fix: read allow_bash/allow_web_search from JSON body (#3229)

API callers using Content-Type: application/json had bash and web
tools silently disabled because allow_bash / allow_web_search were
only read from FormData (which is empty for JSON requests).

Changes:
- Fall back to JSON body for allow_bash and allow_web_search values
- Only add bash/web_search to disabled_tools when explicitly set to a
  falsy value; when unset (None), defer to per-user privilege checks
- Admins with can_use_bash=True now get bash enabled by default

Fixes #3229

* fix: always send explicit allow_bash/allow_web_search from frontend

The backend 'is not None' guard (from prior commit) is correct for API
callers, but the frontend only sent allow_bash=true when the toggle was
ON — omission meant 'unspecified' which the backend treated as 'don't
disable'. Now the frontend always sends an explicit true/false value:

- allow_bash: sent on every request (checked ? 'true' : 'false')
- allow_web_search: explicit 'false' when toggle is off in agent mode

With explicit frontend values, the 'is not None' guard is safe:
- explicit true → tool enabled
- explicit false → tool disabled
- None (API caller omission) → defer to per-user privilege

---------

Co-authored-by: michaelxer <michaelxer@users.noreply.github.com>
Co-authored-by: Alexandre Teixeira <111787685+alteixeira20@users.noreply.github.com>
2026-06-11 19:14:41 +01:00
Carles Siles 3e65326c3f fix: expand cookbook error output tail from 12 to 50 lines (#1538)
* fix: expand cookbook error output tail from 12 to 50 lines

When a task reaches status 'error', the status endpoint was returning
only the last 12 lines of the subprocess log. The existing context-menu
'Copy last 50 lines' action was therefore copying the same 12 lines,
making it useless for diagnosing failures that produce long stack traces
or build output.

- Set _tail_lines = 50 when status == 'error', keep 12 for running tasks
- Initialise exit_code = None before the status-classification block so
  it is always defined in the result dict (was only set inside the
  is_alive branch, potential NameError in the dead-session path)
- Include exit_code in the task-status response dict
- JS poller captures exit_code from live data into local task state

The frontend output panel and 'Copy last 50 lines' now show the actual
error context without any UI changes.

* refactor: extract output-tail logic to testable helper + behavioral tests

Addresses review feedback on #1538: the previous tests were source-level
string guards. Extract the tail-slicing into a dependency-free helper
(routes/cookbook_output.error_aware_output_tail) and replace the guards
with behavioral tests that exercise the actual logic:

- error status with a 200-line snapshot -> exactly the last 50 lines
- running/ready/completed/stopped/unknown -> last 12 lines
- short snapshot -> all lines, no padding
- empty snapshot -> empty string
- error tail is a strict superset (suffix-compatible) of the non-error tail

The helper has no FastAPI/SQLAlchemy imports so it unit-tests without
standing up the app.

---------

Co-authored-by: Alexandre Teixeira <111787685+alteixeira20@users.noreply.github.com>
2026-06-11 17:55:33 +01:00
Kenny Van de Maele 620fdd0859 feat(agent): confine agent file/shell tools to a selectable workspace (#3665)
* feat(agent): workspace confinement via context-local binding + get_workspace tool

Bind the per-turn workspace once in execute_tool_block; the shared path
resolvers (_resolve_tool_path / _resolve_search_root) and the subprocess cwd
helper (agent_cwd) read it, so file tools + bash/python are confined centrally
and a new tool that uses the shared helpers cannot accidentally bypass it.

Adds the admin-gated /api/workspace/browse picker, a workspace pill + directory
modal (reusing existing modal/button CSS), the /workspace slash command, and a
get_workspace tool (replaces a system-prompt block). Confinement is OS-agnostic
(realpath/normcase/commonpath) and docker-safe (container paths, no host
assumptions). Reopens #2023.

* ux(workspace): clarify workspace is not a sandbox

Picker modal note + pill tooltip + get_workspace tool/output wording now state
plainly: read_file/write_file/edit_file/grep/glob/ls are confined to the folder,
but bash/python only start there (cwd) and are not sandboxed. Modal note reuses
the existing .muted class.

* fix(agent): treat an active workspace as file-work intent

A vague low-signal message (e.g. "look at the local project") matches no
domain keywords, so tool retrieval is skipped and only always-available tools
are offered — leaving the agent with no file access even though a workspace is
set. When a workspace is active, include the file/code tools (incl.
get_workspace) on low-signal turns so the agent can act on the folder.

Also requires the tool index (ChromaDB) to be reachable for normal retrieval;
that is an environment dependency, not part of this change.

* ux(workspace): hide pill + overflow entry in chat mode

Workspace only scopes the agent's file/shell tools, so the pill and the
overflow 'Workspace' entry are agent-only now — hidden in chat mode like the
bash toggle. Mode read from the DOM in syncWorkspaceIndicator; applyMode() is
called from the agent/chat setMode handler.

* prompt(tools): steer bash/python to defer to the dedicated file tools

bash/python schema descriptions (what native-tool-calling models read) were
bare and gave no steer, so models would do file ops via the shell (e.g. writing
SVG/HTML, which then dumps raw markup into the tool preview). Tell bash/python
in the schema + tool-index + prompt section to prefer read_file/write_file/
edit_file/grep/glob/ls and only be used for what those do not cover.

* prompt(tools): keep bash/python deferral generic (no hardcoded tool names)

Reference 'a dedicated tool' rather than listing read_file/write_file/grep/etc.
by name, so the guidance does not go stale if those tools are renamed.

* style(workspace): drop em-dashes from added code comments/strings

* ux(workspace): terser non-sandbox note in picker (no tool-name list)

* ux(workspace): mirror terse non-sandbox wording in pill tooltip

* chore: untrack local venv symlink (run-only, not part of the feature)

* prompt(workspace): keep get_workspace text generic (no hardcoded tool names)

* fix(agent): low-signal + workspace surfaces only read-only file tools

Intersect the files tool group with PLAN_MODE_READONLY_TOOLS so a vague message
in a workspace exposes read_file/grep/glob/ls/get_workspace for exploration, but
not write_file/edit_file/bash/python -- those wait for a request that actually
calls for them (RAG retrieval still adds them on a real ask).

* feat(workspace): cap browse listing at 500 dirs with a truncated hint

Mirror the filesystem_tools._CODENAV_MAX_HITS pattern with a module-local
_MAX_BROWSE_DIRS so a directory with thousands of children does not dump every
row into the picker; the response carries a truncated flag and the modal tells
the user to type a path to jump in.

* chore: untrack local venv symlink (run-only artifact)

* fix(workspace): vet the workspace root against the sensitive-path deny list at bind time

The in-workspace resolver deny-lists sensitive paths inside the workspace,
but the empty-path search root is the workspace itself, so a workspace of
~/.ssh could be listed via ls with no path. vet_workspace() (public, in
tool_execution next to the resolvers) rejects non-directories and sensitive
roots before the path is ever bound; chat_routes uses it instead of its
inline isdir check.

* fix(workspace): reject filesystem roots and stop showing rejected workspaces as active

Review findings from #3665:

P2: vet_workspace accepted / (and would accept drive/UNC roots), which makes
every absolute path 'inside' the workspace and collapses confinement into
host-wide file access. A root is its own dirname, so reject when
dirname(resolved) == resolved; the browse response now carries a selectable
flag and the picker disables 'Use this folder' on unselectable dirs.

P3: /workspace set stored any string client-side and the chat route silently
dropped rejected values, so the pill could claim a confinement that was not
in effect. New admin-gated /api/workspace/vet validates manual paths before
they persist (canonical path returned), and when a posted workspace is
rejected at send time the stream emits workspace_rejected so the client
clears the stored value and toasts instead of continuing silently.

* fix(workspace): check caller privilege before vetting the posted workspace

Review finding: /api/chat_stream called vet_workspace() on the posted value
for every caller and emitted workspace_rejected on failure, so a non-admin
who can chat but cannot use file/shell tools could distinguish existing
directories from missing/file/sensitive/root paths by whether the event
appeared. The resolution now lives in _resolve_request_workspace, which
drops the submitted value uniformly for non-admin callers, with no vetting
and no event, before the path ever touches the filesystem. Admin and
single-user behavior is unchanged. Test pins that valid and invalid paths
are indistinguishable for a non-admin and that vet_workspace is never
invoked for them.
2026-06-11 18:17:54 +02:00
Michael cc8ba04ea8 fix: use correct element IDs for privilege-gated button hiding (#3705)
* fix: use correct element IDs for privilege-gated button hiding

The privilege-gated button hiding in initializeEventListeners() used
stale element IDs that no longer exist in the DOM:

- 'tool-bash-btn' -> 'bash-toggle-btn' (the actual shell button ID)
- 'tool-image-btn' -> 'set-imgEnabledToggle' (admin settings toggle,
  since no standalone image button exists in the composer)

Without this fix, users without can_use_bash / can_generate_images
privileges still see buttons that appear to work but then fail.

* fix: remove incorrect image generation toggle targeting

The set-imgEnabledToggle is the global admin Image Generation master
switch, not a per-user composer control. Non-admins without
can_generate_images never render that toggle, so the lookup is null
and the branch no-ops. Admins without the privilege get the app-wide
toggle force-unchecked based on personal privilege, which is confusing.

There is no composer image button in the DOM, so nothing to hide here.
Drop the can_generate_images block entirely as vdmkenny requested.

---------

Co-authored-by: michaelxer <michaelxer@users.noreply.github.com>
2026-06-11 16:19:06 +02:00
pewdiepie-archdaemon 4913a1363b Email reader: block-flow meta with absolute cluster — no more jump
Replaced the grid layout (which made From row height depend on
cluster height, causing To/Cc to shoot up or down at the wrap
breakpoint) with a plain block stack:
- meta = position:relative block
- From row + details = natural block flow with padding-right
  reserving space for the absolute cluster on the right
- cluster = position:absolute top-right, width changes per
  container query (308px wide / 158px narrow / 180px overlay)
- padding-right tightens from 320px → 170px → 0 as the cluster
  shrinks and finally goes overlay
- details margin-top dropped from -10px to 0 since there's no
  grid row gap to compensate for

To/Cc now hugs From with no jumps when the cluster wraps or
overlays.
2026-06-11 22:54:29 +09:00
pewdiepie-archdaemon 6edcc07c1b Email reader: lock From-row height when details expanded to kill jump
Removed the medium-mode -12px details margin compensation — it
under/over-shot depending on grid row sizing. Replaced with a
:has() rule: when the user expands To/Cc, the From row gets
min-height 92px (matching the cluster's 2-row max height). Row 1
becomes the same size whether the cluster is 1 row (wide) or 2
rows (narrow), so resizing across the 600px wrap breakpoint no
longer makes To/Cc shoot up 4px.
2026-06-11 22:47:53 +09:00
pewdiepie-archdaemon 7369c7c642 Email reader: extra 2px details lift in wrapped-cluster mode (no jump) 2026-06-11 22:43:23 +09:00
pewdiepie-archdaemon 7db4e8df4a Email reader: pull To/Cc details 2px tighter under From (-8px → -10px) 2026-06-11 22:41:02 +09:00
pewdiepie-archdaemon 5d5cfc07d7 Email reader: pull To/Cc details up 2px so they don't jump at overlay break 2026-06-11 22:38:48 +09:00
pewdiepie-archdaemon d592b1e6af Email reader: reserve row-1 height when cluster goes absolute
When the cluster snaps to absolute overlay at <380px, it stops
contributing to grid row sizing — row 1 was collapsing to the From
row's natural height, which made the To/Cc details slide upward and
left the floating cluster visually misaligned against them. Setting
min-height:88px on the From row inside the same container query
holds row 1 at the cluster's two-row height so nothing jumps.
2026-06-11 22:36:43 +09:00
pewdiepie-archdaemon b5449ea3f9 Email reader: 6px slack on cluster width to enforce 2-row max
Was fanning out to 3 rows because the 152px max-width (3 icons +
2 gaps exact) had no slack — subpixel rounding could push the
third icon over and trigger another wrap. Bumped to 158px in the
in-grid mode (600px breakpoint) and 180px in the absolute-overlay
mode (380px breakpoint, where the 22px padding-left from the
gradient fade was also eating into the 3-icon row width).
2026-06-11 22:32:00 +09:00
pewdiepie-archdaemon 73dbf3cde7 Email reader: lock cluster to 158px wide + right-edge anchor
Was wrapping into 4+ rows at narrow widths because the cluster's
grid column could shrink below the 3-icon cap. Set both min-width
and max-width to the 3-icon row width and justify-self:end on the
cluster so the icons stay glued to the right edge instead of
sliding toward the middle when the cluster is wider than its
content.
2026-06-11 22:28:48 +09:00
pewdiepie-archdaemon debd2cd386 Email reader: wire up emailreader container so wrap caps fire
The 600px / 380px breakpoints were @container docpane queries but
the email reader isn't inside a docpane container — they never
fired and the cluster wrapped to 3+ rows at narrow widths. Added
container-type:inline-size + container-name:emailreader on
.email-reader-header and switched the queries to that container,
so the 2-row cap now actually applies.
2026-06-11 22:25:09 +09:00
pewdiepie-archdaemon d95abaff1b Email reader: cap action cluster at 2 rows then overlay with shadow
Three-step shrink:
1. > 600px pane: cluster sits in col 2 as 1 row of 6
2. 380-600px pane: cluster capped at 3-icon width so wrapping
   stops at 3 + 3 (max 2 rows) — chips share width with the 2-row
   cluster instead of multiplying into 3+ rows
3. < 380px pane: cluster snaps to absolute overlay with left-edge
   box-shadow, still capped at 3-icon width so it's the same 2-row
   shape but floating above the truncated chips
2026-06-11 22:21:04 +09:00
pewdiepie-archdaemon 13086c3662 Email reader: 6-in-1-row default, wrap to 3+3 only when chip touches
Grid tracks now:
- col 1: minmax(60px, 250px) — chip natural width capped at 250px,
  with the 60px (4 char) floor enforced on From / To / Cc alike
- col 2: minmax(48px, 1fr) — takes the rest, shrinks first when
  the pane narrows

Removed the hard max-width on the action cluster so on wide panes
it stays as one row of 6. Once col 2 shrinks below the 1-row width,
flex-wrap kicks in and the icons re-stack to 3+3. Chips only start
to shrink past that point.
2026-06-11 22:18:37 +09:00
pewdiepie-archdaemon 5719e4db5f Email reader: lock cluster to 3+3 layout, shadow overlay at <380px
- Action cluster's max-width is calc(48*3 + 4*2) so the 6 icons
  always lay out as 3 top / 3 bottom by default.
- When the pane narrows the chips in col 1 shrink first (with 60px
  min so 4 chars + ellipsis stay visible).
- At <380px the cluster snaps to absolute overlay with a left-edge
  box-shadow so it reads as floating above the truncated chip.
2026-06-11 22:15:20 +09:00
pewdiepie-archdaemon 9ac3f40955 Email reader: icons wrap before chips shrink + 60px min chip width
Two-step shrink behavior:
1. As the pane narrows, the action cluster (max-width:50% of meta)
   wraps to a 2-row icon stack first
2. Then the recipient chip span starts overflow-scrolling, but
   keeps a 60px min-width (~4 chars) so the first chars of the
   sender/recipient name stay visible
2026-06-11 22:14:25 +09:00
pewdiepie-archdaemon 3a5c58da75 Email reader: To/Cc rows constrained to col 1 + cluster spans rows
Previously only the From row affected the action cluster's column
width — To/Cc detail rows spanned both columns and ignored the
cluster. Now:
- meta-details lives in col 1 only so the To/Cc chips shrink
  together with the From chip when the pane narrows
- action cluster spans rows 1 and 2 so its width is set by the
  widest col-1 content; a long To/Cc list triggers the wrap to a
  2-row icon stack just like a long From sender does
2026-06-11 22:11:47 +09:00
pewdiepie-archdaemon 7cf3402ef4 Email reader: grid layout so action cluster wraps before overlaying
Meta switched to CSS grid in undocked mode:
- row 1, col 1: From row (label + chip + chevron)
- row 1, col 2: action cluster
- row 2, span: To/Cc details

The cluster shrinks alongside the chip and flex-wraps into a 2-row
icon stack before crowding the chip. At very narrow pane widths
(< 380px via @container docpane) it snaps back to absolute overlay
so From: still fits.

Docked mode overrides meta back to flex column so the cluster
flows naturally last — under From, and under To/Cc when expanded.
2026-06-11 22:08:51 +09:00
pewdiepie-archdaemon 6066d0af02 Email reader: solid bg + gradient fade on action cluster overlay
Was rendering as a transparent ghost — From chip / sender text bled
through the gaps between icons. Added a left-fading gradient
backed by var(--bg) so the cluster reads as an opaque overlay
while chips poking out from underneath blend smoothly into its
left edge.
2026-06-11 22:06:58 +09:00
pewdiepie-archdaemon 7e029db44a Email reader: don't search-pivot from From/To/Cc chips + accent search icon
- Window-level recipient-chip click handler now bails if the chip
  is inside .email-reader-meta — the per-reader handler still
  toggles the expanded-address view on click.
- The from-sender (magnifying glass) search button SVG is now
  tinted with var(--accent-primary) so it stands out as a deliberate
  search action against the neutral Reply / Forward / etc icons.
2026-06-11 22:05:40 +09:00
pewdiepie-archdaemon f569b9394e Email reader docked: action cluster drops below To/Cc when expanded
Moved the action cluster out of the From row to a sibling of meta
inside .email-reader-meta. Undocked: cluster is absolute-positioned
top-right of the header so it overlays the From line as before.
Docked: cluster is in-flow at the bottom of the meta column, so it
sits below the From row when collapsed and below the To/Cc rows
when the user expands the recipient details via the chevron.
2026-06-11 22:04:34 +09:00
pewdiepie-archdaemon fce9942ae0 Chat: fix mode-tag breakage — toggleState wasn't in scope at those sites
The previous commit read toggleState.mode before it was declared
(send-time site near line 632) and outside its closure (assistant
finalize site near line 3426). Both threw ReferenceError / TDZ on
first send, which crashed the chat send + render pipeline.

Read fresh via Storage.loadToggleState() at each site, defaulting to
'chat' on any error. Mode-tag rendering otherwise unchanged.
2026-06-11 22:00:22 +09:00
pewdiepie-archdaemon 93ae65f99f Email reader undocked: wrap action cluster to 2 rows before overlay
Cluster is now in-flow with margin-left:auto and flex-wrap:wrap so
when the chip text grows long enough to crowd it, the buttons split
to a second row of icons before they have to cover the chip. The
absolute-overlay behavior kicks back in at very narrow pane widths
(<380px via @container docpane) so From: still fits on one row when
the pane is truly cramped.
2026-06-11 21:59:45 +09:00
pewdiepie-archdaemon f8d3890e6a Email reader undocked: nudge action cluster 1px down (-8px → -7px) 2026-06-11 21:58:09 +09:00
pewdiepie-archdaemon 85a11ad416 Email reader undocked: lift action cluster 2px more (-6px → -8px) 2026-06-11 21:56:20 +09:00
Rohithmatham12 9f47c5ff87 fix: quote kernels repair package spec 2026-06-11 14:56:35 +03:00
pewdiepie-archdaemon 2be0c5c892 Email reader docked: drop whole From row 4px + right-align icons
Pulled the From row's negative margin from -8 to -4 so the whole
row (From: label AND chip) sits 4px lower together. Action cluster
below now justifies flex-end so the icons sit at the right edge
of the row instead of left-aligned.
2026-06-11 20:44:47 +09:00
pewdiepie-archdaemon e0af7bd8a0 Chat: show Chat/Agent tag next to message timestamp
Sometimes the user lands in chat mode without realizing — surface the
mode the message went out on as a small uppercase pill right after the
timestamp in the role header.

- roleTimestamp(when, mode) gains an optional mode arg. Agent renders
  in accent; Chat renders in muted/neutral. Other values render
  nothing (back-compat for older history without the field).
- The three roleTimestamp call sites pass metadata?.mode through.
- chat.js writes mode into the user-message metadata at send time and
  into the assistant metadata when the active-stream render lands,
  reading toggleState.mode so research/agent overrides upstream still
  flow through correctly.

Historical messages from before this change just don't show the pill —
graceful fallback, no migration needed.
2026-06-11 20:44:18 +09:00
pewdiepie-archdaemon 1d1678214a Email reader: nudge undocked action cluster down 2px (-8px → -6px) 2026-06-11 20:43:41 +09:00
pewdiepie-archdaemon 06899c669c Email reader: lift undocked action cluster another 4px (-4px → -8px) 2026-06-11 20:41:00 +09:00
pewdiepie-archdaemon 05f05dd372 Email reader: shift From: label down 4px in docked mode 2026-06-11 20:40:33 +09:00
pewdiepie-archdaemon a195f4f194 Email reader: docked mode flows action cluster UNDER From row
When the modal is docked there's no room to overlay the actions on
the From line. Now:
- From row gets flex-wrap so the action cluster drops to its own
  row below the From label + chevron
- Action cluster goes position:static, flex-basis:100%, no gradient
  fade, no padding-left, left-aligned
- Whole From row pulled up 8px to claim back vertical space
- Header min-height drops back to 0 since buttons no longer
  overlap

Also bumped the gap from From to To/Cc details by 2px (-8 → -6).
2026-06-11 20:39:22 +09:00
pewdiepie-archdaemon 28caa40e68 Email reader: pull From label + actions up 2px more in docked mode 2026-06-11 20:36:24 +09:00
pewdiepie-archdaemon 6c1ce446f5 Email reader: lift action cluster 4px and From: label 2px on desktop 2026-06-11 20:34:45 +09:00
pewdiepie-archdaemon 729494a59b Email library: match magnifier color/opacity to other search fields
opacity 0.55 → 0.45 and explicit color:var(--fg), matching the
.cal-search-icon treatment so the email chip-bar magnifier reads at
the same muted intensity as the calendar search field.
2026-06-11 20:33:16 +09:00
pewdiepie-archdaemon df69bced42 Email reader: taller header to fit absolute-positioned action cluster
Bumped header min-height to 60px and padding-top to 8px so the
44px-tall action buttons (absolutely positioned inside the From
row) have room without overflowing the header. From row gets
min-height:44px on desktop so the buttons fit cleanly inside it.
Dropped the now-redundant negative margin nudges on the From row
and the strong label.
2026-06-11 20:33:02 +09:00
pewdiepie-archdaemon 12c8f9637f Email reader: search input up 1px, AI reply menu pared to Fast/Full
Search input gets position:relative;top:-1px so the placeholder text
sits 1px higher inside the chip bar.

AI reply choice popover: drop the '...' kebab and the 'Draft with
note' textarea row entirely. Replace the concentric-circle Full icon
with our standard accent dot (filled 6px circle in viewBox 24).
2026-06-11 20:31:04 +09:00
pewdiepie-archdaemon 7fe8a70032 Email reader: actions overlay chip instead of wrapping below when narrow
Pinned .email-reader-actions-inline to absolute top:0 right:0 of the
From row with a gradient fade. When the window narrows the cluster
stays on the From line and the recipient-chips span scrolls under
it, so users can swipe/drag to reveal recipients tucked behind the
buttons instead of seeing From: jump above the action row.
2026-06-11 20:29:24 +09:00
pewdiepie-archdaemon 2e8e097683 Revert "Email reader: AI reply becomes a split button (main + caret)"
This reverts commit 86965950ac.
2026-06-11 20:28:42 +09:00
pewdiepie-archdaemon 24dfd04964 Email reader: lift From: label 4px above the chip on desktop 2026-06-11 20:25:51 +09:00
pewdiepie-archdaemon 86965950ac Email reader: AI reply becomes a split button (main + caret)
Main button: open cached AI draft if one exists, otherwise generate
a fast draft inline. No more intermediate Fast/Full/Note menu.

Caret on the side opens a focused popover with just a textarea +
Generate button — the user types instructions (e.g. 'thank them and
confirm Tuesday at 2', 'decline politely') and submitting fires the
full-mode generation with those instructions as the noteHint.

- _aiReplySplitButtonHtml(data) centralizes the new HTML so all three
  reader render sites use the same markup.
- _showAiReplyChoice rewritten — drops the Fast/Full toggle row plus
  the kebab + 'Draft with note' two-step. Ctrl/Cmd+Enter submits.
- _handleAiReplyButton routes based on which inner button was clicked
  (caret → popover, main → run-or-open).
- The three reader event registrations now listen on .ai-reply-split
  so both inner buttons feed the same handler.
2026-06-11 20:24:19 +09:00
pewdiepie-archdaemon 79e9225c68 Email reader: From row up another 2px on desktop (-6px → -8px) 2026-06-11 20:24:17 +09:00
pewdiepie-archdaemon 1a3880347f Email reader: From row up another 2px on desktop (-4px → -6px) 2026-06-11 20:23:19 +09:00
pewdiepie-archdaemon 20968d5a87 Email reader: shift From row up 4px on desktop, +2px To/Cc gap
- Desktop (>= 769px): From row gets margin-top -4px so the whole
  From + action cluster sits 4px higher in the header.
- Mobile @media block untouched.
- To/Cc gap bumped 4px → 6px for slight breathing room.
2026-06-11 20:22:12 +09:00