Skip to content

Release v2.8.0 - #61

Merged
Alex375 merged 27 commits into
mainfrom
dev
Oct 2, 2026
Merged

Alex375 merged 27 commits into
mainfrom
dev

Conversation

@Alex375

@Alex375 Alex375 commented Oct 2, 2026

Copy link
Copy Markdown
Owner

Release v2.8.0. Voir les commits de dev depuis la dernière release.

🤖 Generated with Claude Code

clousty8 and others added 27 commits September 30, 2026 09:30
…ra code unreachable (CRM 4423ba01)

The CLI (2.1.285) defers set_model on a per-session promise chain and acks it only
once applied, but answers get_settings at once. The actor sent the read-back right
behind set_model, so it reported the model being replaced and overwrote the pick —
the picker ran one click behind the thread (verified live: get_settings +2 ms with
the old model, set_model ack +215 ms).

- session: re-read settings on the set_model ACK; while a switch is in flight, drop
  stale read-backs and defer new ones (one read-back after the last ack); a remote
  link swap stops waiting for acks lost with the old link.
- assembler: a system/init during a pending switch no longer restores/announces the
  outgoing model.
- control: parse ultracodeRequested/ultracodeAvailable; an accepted-but-unavailable
  Ultra code is surfaced once as a control_error instead of silently snapping back.
- front: shownControls (shared by composer + Flight Deck card) trusts the live state
  only while the process runs — the placeholder's ultracode:false no longer hides a
  pick on a not-yet-spawned conversation, nor does an exited process's last state.
- setConvModel re-pushes when the live session runs another model than the record.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…was rejected (CRM 721b9821)

The MCP spec types `structuredContent` as an object, and Claude Code now
validates it: a bare array there made the client reject the whole
tools/call. `list_conversations` returns an array, so it was unusable from
every agent (in-process `flightdeck` server and voice bridge alike).

`tool_success` now sets `structuredContent` only when the value is an
object; arrays and scalars travel as text only, byte-identical to before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ions show the server's own plugins (CRM d22d1906)

- Scope badge: `liveBadge` now follows the live status. A disabled /
  disconnected / failed server keeps its scope label but drops the
  green/blue/violet colour that read as "on".
- Remote conversations: the on-disk inventory reads THIS Mac's ~/.claude, so
  it listed plugins the remote agent does not have. The plugins now come from
  the live session's own report: `system/init.plugins` (each turn) and the
  `reload_plugins` response, carried as `SessionStatePayload.loaded_plugins`.
  The `initialize` response has no plugin list (verified on claude 2.1.286).
  The CLI's internal `@builtin` plugins are dropped.
- Remote panel: read-only plugin list with a note naming the server, an
  "Ask now" button for a session that has not run a turn yet (bounded wait,
  failure surfaced), no local plugin-contribution boxes, and the session's own
  plugin MCP servers kept as a live bucket. The repository lens of a remote
  repo says where its plugins live instead of listing this Mac's.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Port the terminal's "prompt suggestions" to Flight Deck: after a turn, Claude
predicts the user's next message; it shows greyed out in the empty composer
behind a "⇥ Tab" badge, and Tab (or a click on the badge) fills it in.

Wire verified live against claude 2.1.286: opt-in via
initialize.promptSuggestions, top-level `prompt_suggestion` line 3-10 s after
`result`. The model stays silent unless the next step is obvious.
`set_prompt_suggestions_paused` is acked but IGNORED while its server gate is
off — sent anyway as best effort for off-screen composers.

- Rust: CliMessage::PromptSuggestion, dropped while a turn runs;
  SpawnFlags.prompt_suggestions → initialize; set_prompt_suggestions_paused
  IPC over the ControlQuery plumbing; SessionPromptSuggestionEvent.
- Front: in-memory store keyed by conv id, cleared on send / busy edge /
  rewind / delete; composer ghost + Tab (never steals the / menu or ⇧Tab),
  also in the Flight Deck reply modal; PromptSuggestionPauseHost pauses
  opted-in sessions whose composer is off screen (re-sent per new handle).
- Settings → Display → Composer: "Suggest my next message" (ON by default,
  read at spawn; off hides at once). Claude only.
- Spec: docs/claude-code-protocol.md §3.3.1. Bindings regenerated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…RM 3b57843c)

CLI 2.1.284 moved the `sonnet` alias to Sonnet 5.5, so the catalogue's "Sonnet 5" row
had been running Sonnet 5.5 under the wrong name, every spawn on the alias announced a
phantom "Sonnet 5 → Sonnet 5.5" model change (seed label vs resolved-id label), and
Sonnet 5 itself could no longer be picked. Same procedure as Opus 5 → 5.5 (078c5f2).

- Catalogue (models.ts, checked against the 2.1.286 registry — 21 models): the alias row
  reads "Sonnet 5.5" (`claude-sonnet-5-5`), Sonnet 5 gets a pinned row.
- Rust `model_label`: the `sonnet` arm reads "Sonnet 5.5"; labels test covers both ids.
- Spend: `claude-sonnet-5` priced (tier_2_10 — Sonnet 5.5 shares it, so the alias rate
  stands) and given Sonnet 4.6's chart slot, so its history keeps a price and a colour.
- Prefs: LEGACY_SEEN deliberately untouched (frozen record of pre-`seen` blobs);
  reconcileSeen lifts a Sonnet-5-era hide off the alias and hides the new pinned row.

The 1M window needs nothing: it comes from result.modelUsage, not the model name.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ls, sub-agents and plugins, never this Mac's (CRM 361385d0, d22d1906)

Follow-up of the adversarial review of ab1c73d.

- No more scan of this Mac for a remote repository: `list_extensions` read the
  Mac's ~/.claude and the SERVER's path on the Mac, where a missing file read
  as "nothing configured". The panel now uses only what the remote session
  reports: skills (`system/init.skills`, names), sub-agents (`initialize` /
  `reload_plugins` responses with descriptions — known from spawn — and
  `system/init.agents` names, which keep known descriptions) and plugins.
  New `SessionStatePayload.loaded_skills` / `loaded_agents`.
- Repository lens of a remote repo: a note saying where its extensions live,
  no Mac lists, no Codex tab (Codex never runs on a server).
- "Ask now": its state is keyed to the session asked and the answer always
  wins, so a late list no longer sits under a stale timeout error and a new
  session never inherits an old request. Pure + tested (`remoteExtensions.ts`).
- Flight Deck's own plugin settings (conversation / repository) still reach a
  remote repo's sessions: they are now listed there, each with a Clear.
- `InitMsg` doc no longer claims `plugins` is ignored.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…are perTaskStopAffordance (CRM f237e52e)

Since 2.1.278 the CLI only spares running background agents / workflows on an
`interrupt` when the client declared `perTaskStopAffordance` at `initialize`;
absent, it fails closed and the composer's Stop killed them too. Flight Deck
already renders a stop per background task (`stop_task`), so every conversation
session now declares it. The one-shot probes keep the bare initialize.

Live-verified on 2.1.286 (live_interrupt_spares_background_tasks, both cases):
declared → the agent survives Stop and stop_task stops each task; bare → the
agent is killed. Background shells survive Stop either way.

flightdeckd sessions: the first initialize wins, and the Mac's actor sends it
at spawn, so a Mac-created remote session is declared and stays so across
re-attaches. A phone-created one gets no initialize (unchanged behavior) until
a Mac attaches; the phone keeps stop_stream as its stop-everything.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… policy writes, visible Clear outcome, no Mac rules or Codex tab for a remote repo (CRM 361385d0)

- Policy writes run one at a time (`applyPolicyChange` chain): a plugin Clear
  and a server toggle made during one session round trip no longer start from
  the same snapshot, where the later one silently undid the earlier. A kept
  change is re-applied on the current state (the tool cache may have moved).
- A repository Clear is saved before the live sessions answer: the section
  stays up while it is out or has failed, so a refusal is never hidden by the
  list emptying.
- A Codex conversation in a remote repository no longer lands on the hidden
  Codex tab with false empties (and a Refresh that scanned this Mac): it says
  Codex can't run on the server.
- A remote conversation no longer reads Claude Code's permission rules from
  this Mac's files (which locked or allowed tools the server never decided):
  Claude Code's say is unknown there, and the banner says so.
- A reload_plugins ack refreshes plugins + sub-agents in one State and forgets
  the skills (no response carries them; the old list would contradict).
- Tests: session-level initialize/reload harvest, captured init fixture,
  malformed/empty skills & agents, serialized writes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Separator "Conversation compacted" + facts line (trigger · tokens before → after ·
  duration), live from system/compact_boundary and on reload from the transcript
  (a manual /compact's separator is placed under its command echo on both surfaces).
- Live "Compacting conversation…" working line with its own clock (thread + Flight Deck
  card), from system/status "compacting".
- A failed compaction (status compact_result:"failed" + compact_error) is an error notice.
- Context ring drops to post_tokens at the boundary; a model-call-free result (local
  slash command, all-zero usage) no longer zeroes it.
- Codex compaction (live + rollout, both dialects) uses the same separator.
- read_conversation surfaces the compaction as a system line.
- Live/disk fixtures captured from claude 2.1.286; protocol spec updated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…itor no longer spins forever; local Codex bodies kept; queued policy writes never resurrect (CRM 361385d0)

- Regression of 4535baf: "not readable here" reused the "still loading" value
  of `PermissionTarget.external`, so a remote conversation's per-tool MCP editor
  stayed on "Reading permission rules…" forever. Now `externalRules()` (pure,
  tested) gives an empty baseline plus `rulesUnknown`; the editor renders with a
  note, and "Default"'s tooltip says the server's rules are not visible.
- Body selection is a pure, tested `extensionsBody()`: the remote question
  first; a LOCAL Codex conversation keeps its Codex body whether or not Codex is
  detected (gating on detection sent it to Claude's inventory).
- A queued policy change is not kept when what it was for is gone: its
  conversation removed, or everything reset (`clearAllPolicy` epoch).
- Tests: what the second serialized write sends to the session, the tool cache
  kept across a round trip, no resurrection after removal/reset; the session
  reload test now seeds skills before asserting they are forgotten.
- Stale Rust docs on `apply_reload` / `set_loaded_agents` fixed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… body shown, Global keeps this Mac's baseline, reset voids queued writes (CRM 361385d0)

- A local Codex conversation shows its Codex body whether or not Codex is
  detected; its config snapshot is now read whenever that body shows (it needs
  no binary) instead of rendering a never-run query as "nothing configured".
  A settled "not detected" says what can't be read. Header refresh/spinner
  derive from the same body decision.
- A remote conversation's Global scope reads this Mac's rules again: Global
  also reaches this Mac's conversations, so its baseline (managed policy
  included) must not vanish because the current repository is remote.
- The remote tool-permission note says a server-side block still wins over
  Allow/Ask; the "unknown rules" Default wording no longer replaces Global's.
- A reset voids policy changes still QUEUED behind it (stamped when made), not
  only the one in flight. Test added.
- `externalRules` moved under its section; `normalizeServerName` gets its doc
  back.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…er judged by this Mac's rules; Global is read-only from a remote conversation (CRM 361385d0)

- Round 4 made a remote conversation's Global scope read this Mac's rules:
  those then locked and labelled the REMOTE session's servers and tools
  ("from Claude Code"), which the server's binary never reads. Now a remote
  session's rows are never judged by this Mac's files, at any scope; and Global
  is read-only from there (it also reaches this Mac's conversations, whose
  baseline — managed policy included — this panel doesn't show), with the
  reason under the scope picker (a disabled switch never shows its title).
  Pure + tested `ruleAccess()`.
- Codex not detected on this Mac: its switches are off (every change goes
  through the binary), and the notice says so.
- Header Refresh no longer queries the live MCP status without a session.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ead-only; a live Codex session lifts the "not detected" lock (CRM 361385d0)

- The Global read-only reason named a Settings path that doesn't exist and a
  remedy that can't work for a server only the remote host has. It now points
  to "This repository" (covers every conversation of that remote repository)
  and to the real Settings → Claude Code → Extensions for servers this Mac
  also has. The test checks the content, not the constant against itself.
- Codex detection is cached for the app's run: a live Codex session proves the
  binary is there, so it lifts the lock; the notice suggests a relaunch after
  installing Codex.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts:
#	src-tauri/src/supervisor/assembler.rs
…rnal (CRM c65020e2)

Since claude ~2.1.270 the run journal writes each agent's script label and
phase on its `started` line. The live view ignored them and zipped journal
ids with the wire's task_progress labels by index — labels the wire dedups
per phase — so agents sharing a label showed as raw ids, missing from their
step's count.

- Rust journal fold: one entry per agent() call (journal `key`), attempt-aware
  (retries and resumed re-executions reopen the call, stale attempts ignored),
  `failed` lines settle agents (id-less = failed before spawning, no transcript),
  exposes label/phase, `names_agents` (launched header) and `last_started`.
- Front: exact live tree from the journal (rows, counts, current phase by
  recency); legacy by-index path kept for older journals, stated approximate.
- One progress wording on every surface: delivered/total · N failed · N no result.
- Report shown only once the run is over and only for this execution
  (taskId, also parsed from the Workflow ack); shared-journal resumes stated.
- Settled runs never read as in progress; Flight Deck badge reads the task live.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…er a reload (CRM 9ab0edf7)

Since CLI 2.1.283 a SendMessage wake emits its own task_started under the
SendMessage's tool_use_id. With a cold registry (conversation reloaded or
session re-spawned between launch and wake) the task was keyed on that id,
which bgAgentIds never holds, so the woken agent read as foreground and the
AgentBar hid it.

Socle (assembler):
- BackgroundTask.woken_by = the main-thread SendMessage that started the
  current run (per run; a sub-agent waking its own agent never sets it);
  agent_id = task_id on a wake.
- Cold wake re-keyed onto its launching Agent from the CLI sidecar
  subagents/agent-<id>.meta.json (local sessions), so model, live drill-in
  and bgAgentIds line up as on a warm wake.
- No eager flip on the SendMessage tool_use: revival comes from the wake's
  task_started (any terminal status) or, for pre-2.1.283 binaries, the
  successful SendMessage result — only if the target was finished at send
  time and the wire had not reported the run (blocking resume, queued msg).

Front:
- isDetachedAgentTask (AgentBar, appControl), launchTask shared by the inline
  card and the clean-output fold (strict own-id match via launchAgentId),
  agentStreamKey for the drill-in's live key.
- Option A: a foreground card steps aside while its woken run is live (fold
  kept mounted), then comes back describing its own launch.
- Drill-in of a woken run: the waking message + post-wake turns only
  (SessionEntry.wakes keyed by SendMessage id).
- agentIdFromResult read "below" from the 2.1.286 ack; a success:false
  SendMessage is stored as an error; failure notice de-dup per run;
  taskEqual compares woken_by.

Fixture re-captured on 2.1.286; wake probe also logs sub-agent user lines.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts:
#	src/features/flightdeck/BackgroundTaskBadge.tsx
…(CRM dc57f77c)

Since CLI 2.1.284 Ultracode no longer forces xhigh and stays on at any effort.
Flight Deck tied it to the slider's top notch: it couldn't run at high/medium and
moving the slider switched it off silently.

- Slider = effort only; Ultracode = a button under it (composer + Flight Deck
  card). The chip shows the effort alone and turns violet while Ultracode runs;
  the full-screen blast still plays on activation.
- Core: SetUltracode(bool) sends the flag alone; SetEffortLevel re-asserts
  ultracode:true IN THE SAME apply_flag_settings while it's on — verified live on
  2.1.286 that an effortLevel sent alone still switches it off.
- get_settings.ultracodeAvailable surfaced on the session state: the button is
  disabled with the reason (model without xhigh / workflows off). A model that
  can't run it switches it off. Ultracode gets its own "Off → On" notice.
- MCP set_conversation_effort takes effort and/or ultracode; composer buttons
  gain an Ultracode setting (old effort:"ultracode" buttons read as xhigh + on).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts:
#	src-tauri/src/supervisor/assembler.rs
#	src/agent/appControl.ts
…le on background_tasks_changed (CRM 5f971fbe)

The CLI registers a task for FOREGROUND work too — a foreground Bash past ~2 s
(main thread AND inside a sub-agent) and a foreground sub-agent, flagged
is_backgrounded:false — plus ambient housekeeping. They were counted as
background work: phantom "Bash" rows, wrong "N in background" counts, and a
risk of a conversation stuck green with no "done" notification.

- protocol: parse is_backgrounded / owned_by_subagent / spawn_depth /
  skip_transcript / ambient, patch.is_backgrounded, and the
  system/background_tasks_changed level (was SystemMsg::Unknown).
- BackgroundTask gains backgrounded / ambient / owned_by_subagent.
- assembler: a task leaving the level is retired (Stopped) only if its own
  end event never follows (the level precedes the edges, verified live).
- agent_id from the temp tasks/<agentId>.output path; output_file:"" → none.
- front: one predicate isBackgroundActivity behind every count, bar, badge,
  green state, run clock and task_finished push; the CLI's live
  is_backgrounded folds a main-thread sub-agent into bgAgentIds.
- real 2.1.286 capture fixture (capture_tasks_live.jsonl).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts:
#	src-tauri/src/supervisor/assembler.rs
#	src-tauri/src/supervisor/codex/session.rs
#	src-tauri/src/supervisor/model.rs
#	src/agent/appControl.test.ts
#	src/agent/appControl.ts
#	src/agent/reminderSync.test.ts
#	src/features/conversation/AgentBar.tsx
#	src/features/conversation/noticeView.test.ts
#	src/ipc/bindings.ts
#	src/ipc/mock/scenario.ts
#	src/ipc/useGlobalSessionEvents.ts
#	src/store/backgroundAgentAck.test.ts
#	src/store/backgroundTasksStore.test.ts
#	src/store/backgroundTasksStore.ts
#	src/store/workflowLive.test.ts
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Alex375
Alex375 merged commit ef7c948 into main Oct 2, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants