Repository navigation
Conversation
…CRM d1ce0aa6) A prompt that launches background work produces several `result`s: the main answer, then one follow-up turn the CLI starts on its own per background task that reports back (verified live, claude 2.1.283). Each follow-up restamped the turn clock — the live counter restarted — and printed its own short footer. - agent/runClock.ts: a RUN opens on the user's send, owns the background tasks first seen while it is the latest run, absorbs the follow-up turns they trigger, and ends when nothing of it runs any more. - Thread: one timing line per run, under its latest result — main-answer time, then a live green "Background task running · 1m 12s" counted from the Enter, then "46s total" once the work is done. The working indicator, the sidebar row and the "Conversation ended" band read the run clock too. - result.duration_api_ms is a cumulative per-session counter (restored across --resume): the assembler now reports each turn's own delta, unknown on the first turn of a resumed process. - fmtDuration no longer prints "1m 60s". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… system tray (CRM 29ff1ebd) A restyle of the existing title bar, same controls as before: - The bar sits flush with the app (same ground, a hairline under it). - View tabs are plain text; ONE underline sits under the current tab and slides to the next one (useTabUnderline in kit.tsx, observer-driven, no per-render layout). - Title-bar buttons lose their frame: open = lit glyph + a dot underneath that grows in and out. Scoped to .wf-titlebar — the sidebar and Flight Deck keep the framed look. - Voice session / mic / notification sound / Caffeinate share one pill (SystemTray), each still a one-click toggle, lit white when on and grey when off. Caffeinate gets a chevron to pick Light / Hard. Replaces VoiceToggle, SoundToggle and CaffeinateToggle. - The stream / worktree / TOSSE task chips drop their frame when they sit in the bar. - New Motion pref "Animate the title bar" (titleBarAnimations, ON by default); the OS reduce-motion setting always wins. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ch older versions The side panel now drags to a width of its own (286–560px, persisted in `tosse:editor` like `treeWidth`). The splitter travels inside the animated slot so it slides in with the panel; the rendered width is capped by the room left beside the conversation and the editor/terminal region, so a wide stored panel never pushes the composer under its floor — it springs back when the room returns. The docking test now measures the panel's FLOOR rather than a fixed 340, so a narrower window docks a narrow panel instead of floating a wide one. The artifact tile was empty because the wire changed under us: the `Artifact` tool no longer sends `favicon` (an emoji) but `icon` (a WORD — "sparkle", "report", "code"). Checked against the transcripts on disk: `favicon` alone up to 2026-09-14, both during a short overlap, `icon` alone from 2026-09-20. Both are read now and a word is resolved back to a pictograph in `artifactIcon.ts`. Emoji rather than a kit glyph because the vocabulary is open — a 70-glyph UI set has nothing for "recipe", "calendar" or "map", so most artifacts would land back on the generic fallback — and a conversation mixing both wires renders as one list. An artifact's version history is now reachable: the "vN" badge expands into a row per publish (its real number, from the ack's "(Version N)" suffix, else its position), and a row scrolls the thread to the card that published it. That card is the ONLY place an older version's contents still exist — claude.ai serves the latest, and each republish overwrites the same temp file — so nothing fabricates a per-version link. Opening an artifact preview now puts the side panel away and brings it back when the preview closes (pref `artifactHidesSidePanel`, ON). Transient: `convPanelOpen` keeps the user's own answer, so an artifact never OPENS a panel that was closed, and asking for the panel outranks the preview. Also: the composer popover passes `multiFile` through (a page published with sibling files was previewed locally and rendered stripped of its stylesheet), and shows real version numbers and failed publishes. New `?demo=artifacts` scenario — two artifacts, one republished twice, both wires — for visual checks. Verified: tsc clean, 2285/2285 vitest, `pnpm build` green, and all four behaviours driven end to end in the browser mock (resize + both clamps, the conversation floor with the editor open, the version jump flashing the right card, the panel hiding and returning — docked and floating). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…e, one generic mark
The icon-wire fix covered page artifacts, but a Claude Design canvas still showed
the blank tile: verified over all 16 `Artifact` calls of a real Design
conversation, NOT ONE carries `icon` or `favicon` — the tool's own contract says
`icon` is "ignored on an Artifact created from an Artifact type". There was
nothing in the input to resolve.
Its third source is its TYPE's name ("Design" → 🎨), run through the same table
so a future type needs no code. A type nobody named stays faceless rather than
guessing.
The fallback itself was also inconsistent: 🎨 hard-coded on four surfaces, the
kit glyph on the fifth — and 🎨 is exactly what a real Design artifact resolves
to, so "we were told nothing" and "this is a design" were indistinguishable.
<ArtifactFace> is now the one rendering, drawing the kit's `artifact` mark when
there is no emoji. It carries no size class on purpose: `.wf-ico.sm` would tie
the per-tile rules on specificity and leave the winner to stylesheet order.
Verified: tsc clean, 2289/2289 vitest, `pnpm build` green; in the browser mock
the Design demo now shows 🎨 in both the thread cards and the panel, and each
tile's generic-mark rule measured at its own size (17/14/15/30px, muted).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…text section The swap read as two shoves because it WAS two. Measured in the browser: the panel left on `340px→0` at 135ms/ease-out while the artifact arrived on `0→578px` at 190ms/ease-in — opposite curves, different clocks. The conversation's right edge reversed direction mid-flight and overshot its destination by ~200px before settling. `slidePlan` now takes an optional timing, and both halves of a hand-off pass SWAP_TIMING (the entrance's: the arrival sets the pace). Which side needs the override is not symmetric, and the asymmetry is the whole subtlety: - the panel LEAVING and the artifact LEAVING would each pick the short exit; - the panel RETURNING already picks exactly SWAP_TIMING, so it needs nothing.⚠️ The first attempt detected the hand-off by diffing a ref during render, like `docksChanged`. It silently answered false on the one render that mattered, and the panel went on leaving at 135ms — the measurement caught it, the code review would not have. Both sides now read STATE: the panel reads `convPanelPreempted` (true for as long as it is put away), and the side region reads it through `useFrozenWhile`, since the preemption is lifted in the very `set()` that dismisses the artifact. Verified in the browser mock, sampling the composer's right edge every frame: 0 direction reversals and 0 overshoot in both directions (was 1 and ~200px), and both animations now report 190ms / cubic-bezier(0.32,0.72,0,1). Also: the side panel gains a CONTEXT section — the fill bar, "29.8k / 1M", and the same popover the composer's ring and the Flight Deck meter open (plan usage + « Compact context »), through the same backend-aware hook. It appears once there is a token count, and withholds the bar until the window is known (end of turn) rather than drawing a fill from a guess. Verified: tsc clean, 2293/2293 vitest, `pnpm build` green. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…CRM 2c0ba2b7) - Remove the 1 Hz TickEvent thread left over from the scaffold: nothing listened to it, it only woke the app 86,400 times a day. - Run the "Thinking…" accrual ticker only while a session is busy, with a final sweep that seals the open spells when the last one goes idle. - Ambient machine health: probe with `ssh … true` (new `machine_reachability`) instead of the full server diagnosis (a dozen server-side commands, two of them Node.js start-ups) — same ssh options, timeout and failure classification, shared with `diagnose`. - Never probe a machine a live session is attached to: its ssh link already proves reachability; file the attached link as the verdict instead, and record "reachable" on the link's attach edge. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…try deck
Design B, chosen from the four proposals: the panel becomes a sheet lifted off
the window (inset 8px, rounded, shadowed) whose sections are ISLANDS rather
than rows ruled apart. The title and its chord share one pill in the title
bar's tray voice; counts sit in soft capsules; artifacts are a hairline list;
the session footer is the last island, pinned. Same elements as before — only
the look moved. The drag splitter goes `quiet` (no rule at rest, accent on
hover): a standing line in the gap beside a self-framed sheet was a third edge.
SIDE_PANEL_MIN_PX 286 → 296 to count the sheet's insets.
Telemetry deck (`conversationTelemetry`, OFF by default, Settings → Display →
Thread): Alexandre wanted a loud, "Palantir-like" mode for the fun of watching
an agent work — gauges, counters, things that move — on one condition: that it
means something. So NOTHING on it moves on its own; every instrument reads a
real signal (telemetry.ts):
- a context gauge (the plain panel's bar, same popover), needle with overshoot,
a sweep circling it only while a turn is in flight;
- the run's clock (live, then frozen on the run's length) + a status lamp that
names what the agent is doing, in priority order: awaiting permission >
retrying > the tool running > streaming > thinking > background ops;
- one rolling counter per tool family (read/edit/shell/search/agent/web) with
their failures;
- calls per 5 s over two minutes — ARRIVALS only, so a conversation reloaded
from disk is not drawn as one giant spike at load time;
- files touched, turns, API-equivalent cost, model time, background ops,
sub-agents; and a feed of the latest calls (running / ok / error).
Numbers are memoised on the store references that move when a call lands, not
on streamed tokens; the timers are a 1 Hz clock mounted only while a run is
live and the 5 s bucket; motion is CSS on transform/opacity and stops under
the OS reduce-motion setting. The popover behind the gauge and the bar is now
one component (ContextUsageMenu).
Verified in the browser mock on the background and workflow demos: counts
match the calls, the lamp reads "background ops" with Bg ops = 1 while the
background task runs, the clock ticks then freezes on the run's length.
tsc clean, 2492/2492 vitest, `pnpm build` green.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…CRM 2c0ba2b7) The CRM's edge ends an idle SSE stream every ~12 s, and every reconnection owed a (throttled) refetch — a sweep of the TOSSE queries every 60 s for as long as the window stayed visible. Only a real outage (the channel left `live`) can hide changes worth refetching; a recycle hides ~200 ms. The proper fix — a CRM keepalive under the edge's 12 s idle timeout — is being shipped in CRM_max. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e for remote agents (CRM 2c0ba2b7) - ssh keepalive 5 s → 10 s per remote conversation (a cut is noticed in ~30 s instead of ~15 s — decided 28/09): a third of the radio wakeups at rest. - Reconnect backoff: 1 s doubling to 30 s for the first 10 attempts of an outage, then up to 5 min — a long outage no longer forks ssh every 30 s per conversation forever. Cut short by the new `reconnect_remote_sessions` (fired on `online`, window focus/visibility while a link is down) and by a send during the outage. - Caffeinate (Light) only counts LOCAL agents: a remote agent keeps working on its server under flightdeckd while the Mac sleeps, and reattaches with replay on wake. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… come and go (CRM 01393dfa) The floating side panel now sits at the top right, only as tall as what it holds, and grows or shrinks with a height transition when a TOSSE task, a goal, todos or an artifact arrive or leave; past the window's bottom it caps and scrolls. Pref sidePanelFitContent (ON) — off restores the full-height column. Heights are read and written in a ResizeObserver (before paint, never through React state); only a CONTENT change animates — first placement, window resize and width drags follow instantly (fitHeightStep, tested). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ed needles, an oscilloscope
Alexandre wanted the deck "more live": timers down to the millisecond, a timer
per tool, gauges that move fast while the agent runs. All of it still reads a
real signal (the rule the deck exists under), now at 60 fps:
- the run clock and a STATE timer in ms — how long the agent has been in its
current state, from the store's own stamps where it has one (the running
call's start, the thinking spell, the moment it blocked on the user);
- an IN-FLIGHT board: every running call with its own ms timer and a latency
bar against the median of ITS family in this conversation (median at a
third, amber when slower, red past 3×; no median yet → a stripe that only
says "running", never a fake fill); the feed then shows each call's frozen
duration — all from `toolStartedAt`/`toolDurations`, which the store
already measured live and never stamps on replayed history;
- four eased gauges: streaming rate (≈ tok/s, estimated from characters and
labelled so), calls per minute, calls in parallel, turn load (this turn
against the median turn — "—" before any turn has completed);
- an oscilloscope of the streaming rate over 15 s;
- the histogram at one bar a second over the last minute.
Cost: ONE requestAnimationFrame loop writes straight into DOM nodes (no React
render per frame) and reads the store with getState(). It runs while the run
is live and until the needles settle, then stops itself — measured: 0 frames
over 4 s once idle, ~30 fps in headless Chromium while busy. Reduce-motion →
a 1 Hz tick, no easing.
Found and fixed by measuring in the browser:
- a closing histogram bucket lost its count: `setDone(p => closeBucket(p,
liveRef.current))` read a ref inside an updater. One `{done, live}` state,
closed by a single pure transition.
- the loop stopped during background work although the run was still live,
freezing its clock. `live` now follows the run itself.
- `liveInFlight`: a session that dies mid-call never delivers the result, so
its call would count up forever and keep the loop awake; nothing runs →
nothing in flight. The lamp reads a running call and streaming text as the
facts they are, even before the session reports itself busy.
tsc clean, 2514/2514 vitest, `pnpm build` green.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… fixed in the CRM CRM_max bd6705f (keepalive 10 s) + a8456e5 (server.timeout(req, 0) on /api/v1/sse): production shows no more stream endings. Correct the comments that blamed the Railway edge. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…call time up front
Alexandre's round of feedback on the live deck:
- COMPACT: the deck fits a 13-inch MacBook Pro — measured at 519px (was ~780)
in a 1440×820 window, the panel's footer still in view. One line of key
figures, the six family counters on one row, the oscilloscope and the
histogram as two thin strips side by side with their labels, a 4-line feed.
- COST and AVG CALL promoted to the key-figures line (with CALLS and MODEL);
each family counter now shows its own average call time.
- HISTOGRAM: every tick re-animated every bar ("all the peaks go down and up").
Bars were keyed by POSITION, so a tick handed each DOM bar its neighbour's
value. They are now keyed by the second they count (histogramBars): a tick
only moves them left, and only the live bar has a height transition —
measured: 0 closed bars with a transition.
- IN FLIGHT: most calls finish in well under a second, so the board flickered
rows in and out too fast to read. It is now a LONG CALLS board: a call joins
it once it has run 40 s (LONG_CALL_MS, Alexandre's figure), and the board is
hidden while none qualifies. Visibility is toggled by the frame loop through
a data attribute React never writes, so a re-render cannot undo it. Every
call still counts on the gauges, the counters and the feed.
- COST OF A JOKE: off (the default), the deck is not mounted — measured: 0
frames and 0 timers over 4 s idle. On, the loop is capped at 30 fps, pauses
while the window is hidden, stops once settled; the histogram's 1 s tick
stops once its minute has emptied.
tsc clean, 2516/2516 vitest, `pnpm build` green.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… pause without a key (CRM 2c0ba2b7) - Window-preserving silence gate: while Silero heard no speech in the last 16 scored steps a fire is impossible, so mel + embedding + classifier are skipped; ~2.2 s of raw audio is kept and the window is backfilled when speech starts. Decisions are bit-for-bit identical to the previous engine (frozen as a test-only reference: all phrases, 6 scenarios, 3 callback sizes, gated/ungated). Silence: 15.9 → 2.27 ms CPU per audio second. - Mic callbacks reuse their buffers and hand the worker one batch per 80 ms step (~94 → 12.5 wakeups/s); the worker blocks on one channel (no 100 ms poll) and runs at UTILITY QoS; a lost mic stops it with a reason. - Incremental mel NOT done: the mel model floors at 80 dB below the max of its whole input, so streaming it changes the features (pinned by a test). - Bug: without an OpenAI key the wake word is PAUSED (mic off, choice kept) at boot, on config change and when the key is cleared; resumed when a key is saved. Switching it (and "Record false triggers") OFF is never blocked. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… pause (CRM 2c0ba2b7) The window-preserving silence gate backfilled up to 17 embeddings at speech onset (17-22 ms on a P-core, unmeasured on E-cores) — the one change that needs a real microphone to validate, and none is available. The engine is back to origin/dev's per-step pipeline: mel + embedding + classifier on every 80 ms step (only `CHUNK` became `pub`, for the capture batcher). Removed: the gate, its raw-audio ring, backfill / recompute-skipped-score / self-disable paths, the frozen reference engine and every test, bench and constant that only existed for them. Kept: mic batching + buffer reuse, the blocking worker wait + lost-mic stop, UTILITY QoS, the no-OpenAI-key pause and never-block-OFF toggles. Comments now say what is true: the VAD vetoes fires, it does not gate work; there is no silence-based battery guard. New test: batching per step changes no decision (fires and debug candidates, bit-identical scores) vs per-callback feeding. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…M 01393dfa) With both side bars open, the thread text and the composer ran edge to edge with 26px to spare. The reading column now keeps a responsive margin (--cv-gutter: up to 56px, back to 26px only as the pane nears its floor, so the composer still gets its 500px there), and its cap is a setting: Display > Thread > Conversation width, 560-1080px in 40px steps, 760 by default (was a fixed 840). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The deck's context gauge said how full the window is, not what fills it. The state now carries the fill's breakdown (`context_usage`: cache read / cache write / fresh input, plus the call's output) from the same root call that sets `context_tokens` — live (message_start + message_delta, then the result's last iteration), cold from the transcript, and from Codex's `last` usage (cached tokens counted INSIDE input there, not on top). Each turn_result carries what the turn consumed (`result.usage`). The deck shows both as two stacked bars under one legend (Cached · Caching · Input · Output): the last call, and the session total over the turns the app watched finish. Codex reports no per-turn usage, so its session row reads "—" rather than a made-up zero. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…matic margin (CRM 01393dfa) Per Alexandre: the app keeps today's look by default. sidePanelFitContent now defaults OFF (full-height column) and conversationWidth to 840 — the column's historical width. The responsive --cv-gutter is gone (back to the fixed 26px); narrowing the width setting is what buys the margin. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Brings the energy-audit work (machine_reachability, attachedMachineIds, reconnect_remote_sessions, the SSE and wake-word fixes) the side panel's upcoming Machine widget builds on. - bindings.ts: dev dropped TickEvent, this branch added TokenUsage — both kept (regenerated from the merged Rust, identical). - machineHealth.test.ts: dev's new neutral SessionStatePayload gains the branch's `context_usage` field. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…50f55614) A review row raised while background work still runs (the re-alert on background Bash finish edge) now keeps its blue and gets the green bg row's violet wash on its right end. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The conversation panel becomes a set of widgets the user switches on and
off, reorders and folds, from a Customize view in the panel itself (presets,
drag-to-reorder cards, a "collapsible sections" switch, reset). Everything
applies as you go; the layout persists in localStorage (tosse:sidepanel),
repaired against the catalogue on load. A widget switched off is never
mounted, and gives its old surface back (header chip, composer chip, todo
bar). Sections fold with a grid-row height animation and unmount their body
once folded; the telemetry deck folds to its head.
New widgets, each reading a real signal ("—" when unknown):
- Stats: average turn, files touched, calls, and the session's TOTAL tokens
— the latest result.modelUsage (main loop + every sub-agent + workflow
agents), seeded on reload from the transcript's last cost-state line.
Fixes the deck's cost, which summed a cumulative figure.
- Git status: branch, sync with its upstream (incl. a gone upstream),
staged / modified / untracked / conflicts; read-only git calls now pass
--no-optional-locks, and git views refresh at each turn end.
- Plan usage: 5-hour / weekly / model windows with reset times, read from
the shared cache (no new poll, no Keychain read on mount).
- Linked conversations: the conversations this one messaged or created,
with live status and jumps to the matching message.
- Machine (bottom row): this Mac by name (new local_machine_name IPC) or the
paired server with its reachability and link state.
Settings: the telemetry switch now drives its widget; a new "Conversation
panel widgets" row opens the Customize view.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d, fallbacks From the multi-agent review of the widget stack: - History replays in ONE store commit (applyItems): one set per item made every subscriber re-derive per item, and the Stats / Linked widgets turned opening a long conversation quadratic. - The panel-closed summary line stands in for the goal and the todos each on its own: with the Todo widget off, an active /goal was shown nowhere. - Customize: the card is its own dnd-kit activator, so Space / Enter on a switch toggles it instead of starting a keyboard drag; drag and drop animations follow the panel-animations switch; presets are aria-pressed buttons, not a radiogroup without arrow keys. - Closing the panel leaves the Customize view; folding the telemetry deck from the keyboard keeps focus; no empty footer island; "every section is switched off" wording. - Stats goes two by two at the panel's narrowest; its no-record tips name a rewind or an early fork among the causes. - The git fs refresh matches the real paths FSEvents reports (/private/tmp, case-insensitive APFS). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ight # Conflicts: # src/features/conversation/ConversationSidePanel.module.css # src/features/conversation/ConversationSidePanel.tsx # src/features/settings/SettingsPanel.tsx # src/store/display.ts
… Thread split into cards (CRM f065d069) - The panel starts on Essentials (task, goal, todos, artifacts, stream). Standard is now task, goal, todos, artifacts, linked, stats, git + the three bottom rows. - A stored layout still on the untouched v1 default (everything but telemetry) moves to Essentials once (layout v2); a layout the user chose keeps its visibility. - Settings: the telemetry deck switch is gone (it is a panel widget, chosen in Customize). Display → Thread splits its 13-row card into Reading / Navigation & controls / Side panel / Artifacts; Appearance splits the workflow toggles into their own Workflows card. Search index follows. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.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.
Release v2.7.0. Voir les commits de dev depuis la dernière release.
🤖 Generated with Claude Code