ClideKernel.of(context) is an illegal ancestor lookup inside
dispose(); both panes wrapped it in catch (_) and silently did
nothing. The terminal pane therefore never sent pane.close (backend
PTY + daemon pane leaked per closed pane) and the Claude pane never
removed its settings listener. Both now cache KernelServices in
didChangeDependencies and the swallow-everything helpers are gone.
New terminal_pane_test covers the close-on-dispose path; note in it
why the whole tree must unmount (harness Overlay keeps
initialEntries across rebuilds).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
_reap() flipped _dead without releasing the master fd, and close()
short-circuits on _dead — so every naturally-exited child leaked its
fd and pty device for the life of the app. The reader isolate sends
EOF only after leaving its poll loop, so releasing the fd inside
_reap() cannot race the reader. Regression test counts /dev/ptmx
entries in /proc/self/fd across a natural exit; verified to fail
against the unfixed code.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Commit fable-ous.md (13-reviewer multi-agent assessment of the whole
tree) and the ticket tree it produced: epic T-359 with 26 children
covering the dragon bugs (PTY fd leak, undrained claude stderr,
unauthenticated MCP HTTP, path-confinement gaps, dispose-path leaks,
SGR crash, a11y semantics), the medium scorpions, a dead-code sweep,
the systemic-pattern work, and split plans for app.dart and the claude
meta sidebar. Root causes appended to existing T-274, T-283 context,
and the parser split plan to T-123. One review claim (ColumnHat
duplicated in app.dart) was refuted during verification and is
annotated on T-385/T-394.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The detection/follow core for the live-tail sub-card, with the UI wiring
to follow. Claude Code runs every Bash tool itself and clide only sees the
final tool_result block — we can't mirror the running process, so instead
we detect a file-backed source the command follows and open our own
read-only follower on the same file.
- bash_tail_source.dart: detectBashTailSource() parses a Bash command for a
single, safe, file-backed source (tail/cat/less with one file arg, inside
the workspace via resolveUnderRoot). Returns null for a pipe-into-tail, a
redirect, two files, or a path outside the repo — the caller then shows a
"nothing to follow" note. bashHasTailIntent() gates WHEN the segment
appears: v1 triggers on `tail`/follow-flags only, so ordinary cat/ls/git
cards stay clean (cat/less remain detectable for later).
- file_tail_follower.dart: a polling, read-only `tail -f`-style follower
(no subprocess, no touching Claude's command) that emits the trailing
window then appended deltas, and re-reads from the top on truncation.
Tested: 19 parser cases (incl. the `git push | tail -25` and outside-
workspace null cases), the intent predicate, and the follower (initial
window / appended delta / missing file / rotation / start / stop).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Fleshed out the self-update story with grounded constraints, a blocking
prerequisite, decisions, and a phased breakdown:
- D-64 ("no auto-update checks without user action") is stricter than the
original "opt-in or gated" wording → the check must be explicitly
user-initiated every time (palette / About button), not a startup poll.
- POLICY.md grudging-allowance criteria apply to the explicit fetch.
- Hard prereq: no release channel exists (2 stale tags, no CI, no signed
artifacts) → recommended splitting a "release channel" sibling under T-46.
- Phases P0 prereq → P1 check+notify → P2 download+verify → P3 apply+relaunch
(tmux sessions survive, D-41) → P4 macOS/deltas.
Moved back to backlog pending the release-channel prerequisite.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A fan-out of N agents (Task/Agent) merged into one shared "Activity / N
steps" cluster — groupConversation folded an Agent spawn like any Bash/
Read call. Now an Agent spawn is a cluster boundary, rendering as its own
first-class collapsing card (reusing the existing sticky-agent path: folded
prompt T-263 + nested run T-264), while adjacent non-agent foldables keep
clustering into the normal Activity card.
Two changes:
- activity_cluster: a shared isAgentTool() predicate; _isFoldable returns
false for agent spawns at every level (incl. L3), so parallel agents
never merge. Only the grouping boundary changes; fold mechanics are
unchanged.
- conversation_view: harden resolveOwner. Its nearest-preceding-agent
fallback is safe with one agent but mis-routes under a parallel fan-out
(an unattributable item lands in whichever agent was emitted last —
a sibling's card). With >1 agent, drop the fallback so the item orphans
(rendered inline) instead of cross-attributed. The T-338 direct route
(parent_tool_use_id) still attributes interleaved items correctly.
Tests: two consecutive agents → two cards (not one cluster); agent breaks
a sibling cluster; agents first-class at L3; regression — consecutive
Bash still one cluster; interleaved parallel-agent runs route to their own
card; an unattributable item orphans instead of being swept into the last
agent.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ExitPlanMode arrives as a can_use_tool permission prompt and was approved
like any other tool — the control_response was sent but the tracked
SessionStatus.permissionMode never changed, so the mode indicator and
composer stayed on "plan" after the plan was accepted.
On approving an ExitPlanMode prompt, sync the tracked mode to 'default'
(the CLI performs the transition itself, so no set_permission_mode control
request is sent — we only mirror it). The change rides the existing
statusStream → claude_pane._status plumbing, so the permission-mode
control and status indicator update with no extra wiring. Deny, and any
non-ExitPlanMode tool, leave the mode untouched.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The chord matcher couldn't represent a bare or double-tapped modifier:
KeyChord.parse required a base key, so `shift shift` failed, and JetBrains
"Search Everywhere" (double-Shift) was unbindable.
Design decision: search-everywhere aliases clide's existing quick-open
finder (not a new overlay) — bound across all four presets per the user.
Changes:
- KeyChord: a bare modifier name (`shift`, `ctrl`, `cmd`, …) parses as a
modifier-free chord on that modifier's logical key, so parseSequence(
'shift shift') yields a two-chord double-tap. Adds KeyChord.bareModifier
and modifierForLogicalKey.
- ModifierTapTracker: headless, clock-injected double-tap detector. A bare
modifier never forms a single chord; an intervening key breaks the gesture.
- app.dart global handler feeds bare-modifier KeyDowns to the tracker and,
on a double-tap, resolves the 2-chord sequence via the new
KeymapService.resolveSequence. The existing single-chord path is untouched
(zero behavioural risk to normal keys).
- Presets: default/vim/vscode/jetbrains add `shift shift` → quickOpen.open.
jetbrains header updated (the gesture is now expressible).
Tests: bare-modifier parse/equality/round-trip; tracker window/reset/
different-modifier/consume; each shipped preset resolves double-Shift to
QuickOpenIntent.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Confirmed root cause of the sidebar failure: a desktop launch starts in
HOME, which isn't a git repo, so resolveWorkspaceRoot returns HOME and
the daemon's pql/git/files all target HOME. pql then finds a stale
~/.pql/pql.db (left from earlier HOME-workdir runs) and errors
"pql.db is from an earlier schema" — exactly what the sidebars showed.
A manual refresh worked only because by then the workspace had swapped
to the repo. (Verified directly: `cd $HOME && pql ticket list` reproduces
the schema error against ~/.pql/pql.db.)
Settings confirmed the user is in the picker path (no startupSticky on
any recent), so nothing auto-opens the repo at boot and the daemon sits
on HOME until the project is opened.
Fix: resolve the startup workspace before boot — prefer the launch CWD
when it's a git repo, else fall back to app.lastProject (the repo). The
daemon now points at the real workspace from its first request, so the
sidebars load immediately without depending on swap/refetch timing. The
ProjectOpened refetch and swap serialization from 2.3.x stay in place for
genuine mid-session project switches.
Pure resolveStartupWorkspace() helper is unit-tested; app boot green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
`make push-check` now runs a `security` step (ci/osv_scan.sh) that scans
pubspec.lock with osv-scanner and fails the push if any resolved
dependency has a known advisory. This is a hard, fail-closed gate on top
of `dart pub get`'s passive (non-failing) advisory print.
Replaces the old manual-review `security` no-op target. Slots in among
the instant fail-fast gates, before the coverage suite. Resolves the
osv-scanner binary from PATH, falling back to a brew prefix so the gate
works under the pre-push hook's leaner PATH; if absent it fails with an
install hint (brew install osv-scanner). Native deps (dugite,
tree-sitter, wasmtime) are vendored by SHA and reviewed separately on
bump (D-42), so they're out of scope for the lockfile scan.
Verified clean against the current lockfile (80 packages, no issues).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Reviewed every direct and transitive dependency against the GitHub
Advisory Database / OSV (Pub ecosystem). No advisory affects any
dependency at its current pin or upgrade target — the "N packages have
newer versions" noise is freshness, not security. (Consistent with
`dart pub get` printing no advisory warnings.)
Bumped the safe pins + their licenses.yaml entries in the same commit:
- ffi 2.1.3 -> 2.2.0
- jovial_svg 1.1.26 -> 1.1.30 (pulls jovial_misc 0.10.0 + xml 7.0.1)
- mocktail 1.0.4 -> 1.0.5
Held, with the reason recorded inline in pubspec.yaml:
- markdown 7.2.2: 7.3.1 requires Dart ^3.9.0 — defer to an SDK-floor bump
- alchemist 0.12.1: 0.13.0 disabled text anti-aliasing -> golden churn
- test 1.31.0: flutter_test SDK-locks the resolvable ceiling
make test green (incl. SVG/xml goldens — the xml 6->7 major didn't churn
rendering).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Patch release: ticket/decision sidebars load on first open (T-352), plus
the KWin frameless-chrome map fix (T-351) and the transient pql-failure
retry (T-350) that landed since 2.3.0.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
On a desktop launch the daemon's PqlClient boots with workDir set to the
launch CWD (e.g. HOME), not the repo — swapIpcServer only rewires it once
the project opens. The tickets and decisions panes fire their first pql
fetch before that swap, so pql runs in the wrong directory against a
stale/global pql.db and the pane errors (observed:
"ticket_deps.blocker_record_id missing — pql.db is from an earlier
schema"). A manual refresh worked because by then the workspace was open.
This is a wrong-workDir timing issue, not db-busy, so the T-350 retry
doesn't catch it. Both panes now re-fetch on ProjectOpened, which fires
after the IPC server swaps to the project workRoot.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
On KDE Plasma 6 / KWin 6 the frameless chrome still showed the native
title bar even with the decoration code compiled in. The KDE
server-decoration request ran on the GtkWidget "realize" signal, but
GTK's Wayland backend only creates the wl_surface on map — so at realize
gdk_wayland_window_get_wl_surface() was null and the request bailed,
leaving KWin (which defaults to server-side decorations on Wayland) to
draw its title bar.
Also connect the handler to "map", where the surface is live. The realize
pass still does the X11 gdk_window_set_decorations hint and bails harmlessly
on the Wayland part, so no duplicate decoration object is created.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The pql-backed sidebar panes fetch once on first build. If that fetch
fired too early — the planning DB still settling at startup, or a db-busy
SQLite lock under concurrent pql writes (pql exits 69) — the pane showed
"pql … failed" and stayed there until a manual refresh re-fired it.
Retry transient failures at the single chokepoint, PqlClient._run: on a
busy/locked signal (exit 69, or stderr mentioning database is locked /
busy) retry a few times with short backoff before throwing. Genuine
errors aren't busy, so they still surface immediately.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Cut the accumulated Unreleased entries under a dated 2.3.0 heading and
bump pubspec + licenses self.version. Minor bump: the batch adds features
(file references, task dock, deny-simplify, ticket pick-up, type-filter
chips, VS Code/JetBrains keymaps) alongside the fixes.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The frameless custom chrome (D-057) is gated on HAS_WAYLAND_CLIENT, which
was only defined when CMake's non-required wayland-client check happened
to find it. A build host/container without the Wayland client dev headers
(plausible on Bazzite/immutable distros that build in a distrobox) silently
compiled the decoration-suppression out, so the rebuilt app shipped the
compositor's native title bar (double title bar on KDE Plasma Wayland).
Make wayland-client a hard requirement: fail the configure with an
actionable message (Fedora wayland-devel / Debian libwayland-dev) rather
than drop a core feature. Fix the stale "xdg-decoration" comment — the
code uses the KDE server-decoration protocol.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The hook ran the full ~2min push-check on every push, even one touching
only docs, changelog, pql data, tests, or assets. Diff the pushed range
(from the hook's stdin) and run the full gate only when lib/ (app/runtime
source) or pubspec.* (deps/version) changed; otherwise run just the
instant decisions + changelog gates.
Other changes ride along with a lib change in practice, the full suite
stays available via `make push-check`, and the release CI runs it forced
on a tagged version. A state we can't classify (unfetched remote sha, new
branch) falls back to the full gate.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A desktop launcher gives the app a minimal PATH (e.g. /usr/bin:/bin) with
no ~/.local/bin, where pql installs — so _findOnPath('pql') returned null,
clide spawned the literal 'pql', and Process.start failed with ENOENT;
the pql pane errored. The PATH re-expansion that re-adds ~/.local/bin +
/usr/local/bin ran on macOS only; Linux GUI launches hit the same wall.
Extend it to Linux (homebrew dirs stay macOS-only). Extract the logic
into a pure expandToolPath() so the platform gating is unit-tested.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The two coverage passes shared fixed paths (coverage/lcov.info →
lcov.parallel.info → merge → rm -f), so a concurrent flutter test
--coverage — a second push gate, or a `make test` during a push — raced
and deleted this run's intermediate mid-merge, crashing merge_lcov with
FileNotFoundError.
Each pass now writes to a per-run mktemp dir via --coverage-path; the
merge runs from there and only the final result lands in coverage/lcov.info
via an atomic rename within coverage/. No shared intermediates, so
concurrent runs can't corrupt each other.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ClideCollapserCard and ConversationCard sat adjacent but used different
tokens for the same roles, so labels/summaries rendered 1-2px apart.
Standardise both on label = clideFontCaption (14), collapsed summary =
clideFontMeta (13): bump ConversationCard's label up from clideFontSmall,
bring the collapser's summary down from clideFontCaption. Goldens
regenerated for the affected card images.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A row of toggle chips below the filter box — one per pql ticket type,
ordered large→small (Initiative, Epic, Story, Task, Bug), each with its
TicketTypeColors dot + border. Single-click toggles a type; double-click
isolates it (chart-legend solo, fully reversible); disabling the last
enabled type snaps all back on so the list is never blank. ANDed with the
text filter; all on by default, nothing persisted.
One GestureDetector owns both onTap + onDoubleTap so Flutter disambiguates
single vs double. Wireframe updated + approved.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Bug / Ticket / Epic / Initiative toggle chips at the top of the tickets
panel, all on by default. Single-click toggles a type; double-click solos
it (chart-legend pattern), double-click again restores all; last-off
resets to all-on. Filed under the UI epic T-276 with a Frame0 wireframe.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Scope clarification: each per-agent card must pull that agent's full
nested run (prompt + prose/thinking/tool cards/results), correctly
attributed under parallel fan-out. Flags the resolveOwner nearest-lastAgent
fallback (conversation_view.dart:228) as a mis-routing hazard for
concurrent agents. Also pins that existing grouping is preserved: non-agent
foldables still cluster into the Activity card, intra-agent folding
(T-263/T-264/T-338) is reused not rebuilt.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Investigated whether spawned subagents get their own collapsing card.
They don't: groupConversation/_isFoldable (activity_cluster.dart) treats
Task/Agent tool-uses like any non-diff tool, so consecutive spawns merge
into one "Activity / N steps" cluster. T-263/T-264/T-338 only shaped what
renders INSIDE one agent card. Filed T-342 (under T-276) for the
complement: break distinct Agent spawns out into their own labelled cards.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The catch-all "dispatch threw" log omitted the request command, so a
handler exception couldn't be correlated to what caused it (PTY/IPC
audit item #26). Track the resolved cmd across the request handler and
include it in the error log.
The audit's other two items were already satisfied: errno/signal magic
numbers are centralized in PosixErrno + ffi/libc.dart, and the IPC
server already logs through the kernel Logger (no stderr.writeln left).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Persist the T-57 note append that a prior commit's stale export missed;
also carries a re-serialized row for an existing backlog ticket.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- T-45 cancelled: tmux detect/install gate is obsolete — D-77/D-78 moved
the Claude pane off tmux to the stream-json control protocol + --resume.
- T-57: noted it applies to both the left sidebar and right context-bar
rails, and that the left-most item opens by default.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- test: 1.30.0 → 1.31.0 (matches pubspec dev_dependencies)
- tree-sitter purpose: stale app/native/ path → native/linux-x64/
Surfaced by the T-25 audit and the 2026-05-14 security review. The
"phantom lints entry" that review also flagged is already gone.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A user-initiated denial (Deny & simplify) came back as an isError
tool_result and rendered as a prominent expanded-red "Bash · error"
block — pure noise, since the user chose it. It now folds to a muted,
collapsed "denied" card.
Built as a reusable filter rather than string-matching the note: DenyTool
carries a `quiet` flag, the session collects quiet denials' tool_use_ids,
and ConversationView renders any error whose id is in that set folded +
muted. Genuine tool failures (ids not in the set) keep the expanded-red
treatment. Adding future "expected error" cases is just adding ids.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
When a ticket is handed to a live Claude pane (T-327), advance it to
in_progress on the receiving side of the bus — gated on acceptance, so a
pick-up with no live session stays a quiet no-op and never mutates state.
Only a not-yet-started ticket (backlog/ready) transitions, so re-picking
up a review/done ticket doesn't drag it backwards. On success it publishes
(builtin.tickets, changed) so the sidebar refreshes.
The handler logic moves into a testable applyTicketPickUp() seam; the
sidebar button now carries the current status in the pick-up payload.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
In live stream-json sessions a sub-agent's spawning prompt is tagged
with parent_tool_use_id, not the transcript JSONL's isSidechain +
parentUuid. The parser ignored that field, so the prompt parsed as a
main-thread user turn and rendered as a blue "you" card above the
Activity Agent card instead of folding into it.
Carry parent_tool_use_id onto ConversationItem; its presence now marks
the item as a sidechain message. The sidechain fold resolves ownership
directly by tool-use id (no transcript-only uuid chain to walk), so the
prompt folds into its Agent card and the run nests under it as before.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Workspace file paths mentioned by Claude now linkify and open in the
editor: bare (lib/app.dart), with a line (lib/app.dart:42), backticked,
or as markdown links. Only paths that exist in the repo linkify — the
resolver gates on existence so prose (version numbers, "e.g.") stays
literal. Clicking maps to the editor.open verb, jumping to the line when
a :line suffix is present (D-6 parity).
ClideMarkdown gains resolveFileRef + onOpenFile hooks; conversation_view
resolves against the open project root + existsSync and dispatches over
IPC. Detection covers running prose, whole-content code spans, and link
hrefs.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Bug under the UI tracker epic (T-276). The sub-agent prompt leaks to the
top level as a blue 'you' UserMessage instead of folding into the Activity
Agent card (T-263 behaviour), because the fold keys off envelope
isSidechain/parentUuid and the spawning prompt's envelope arrives without
them resolving to the Agent tool_use.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Plan an epic to run clide locally against a repo on a remote machine over
SSH: execution remote (git, pql, claude, terminal, file I/O), UI + clipboard
local, bridged by SSH. Resolves Q-23.
Epic T-329 with stories T-330..T-336: Phase-0 governance spike (gates the
epic; decides the footprint model — no-install ssh-exec vs auto-pushed
agent — and resolves Q-23), model-independent backbone (transport seam,
ssh:// open scheme, Claude stdio-control remoting, image-paste bridge, UI),
and an execution-layer fork placeholder that expands after the spike.
Dependency chain wired via ticket blocks.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a clause to the preformatted deny-simplify note so Claude proceeds
silently with the simpler version instead of narrating the change.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The image fills the 94% viewer with a transparent letterbox, so taps on
the dimmed canvas beside the image hit the viewer and did nothing — only
the 6% margin dismissed. Add onTapUp that dismisses when the tap lands
outside the actual painted-image rect (computed from the RenderImage +
applyBoxFit, transformed for any zoom/pan). Double-tap reset, scroll
zoom, pan, Esc, and the close button are unchanged.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
AnimatedSwitcher cross-fades exiting + entering glyphs for 200ms; with a
fixed per-status ValueKey, flipping a status back (running -> success ->
running within the fade, e.g. two bound Claude panes) left two children
keyed 'running' in the Stack -> "Duplicate keys found" + a cascade of
follow-on framework errors. Make the indicator stateful and fold a
per-change sequence counter into the key, so each appearance is unique and
a same-status rebuild still doesn't re-animate. Regression test flips
status mid-cross-fade with real animations.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Hovering a ticket card reveals a person-simple-run icon; clicking it
fetches the full ticket (pql.tickets.show withContext), builds a "pick
this up and start" prompt, and publishes ('builtin.tickets','pick-up',
{id,prompt}) on the message bus. The Claude builtin subscribes and
injects it into the active session (primary, else first visible) as a
user turn — a quiet no-op when no session is live. Sidebar stays
decoupled from the orchestrator (bus-only). Prompt-builder test.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Settle the activity-card run-status size at 26 (clideIconHero) — a touch
larger than the 24 trial, which reads better in review.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude's TodoWrite checklist was invisible. Add a TaskItem/TaskStatus
model + a latest-wins parser (taskListFrom) that reads the most recent
TodoWrite tool call (it replaces the whole list each time), and a compact
display-only ClaudeTaskDock pinned between the conversation and the
composer: collapsed to "N tasks · M done" + the current in-progress item,
expandable to the full checklist with per-item status glyphs + a11y
labels. Hidden when there are no tasks. Parser + widget tests.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A fourth button on the permission card that denies the action with a
preformatted note: it's too complex for the permission system, retry in a
simpler/more granular form, and explicitly do NOT add a memory or change
permission settings (so Claude reformulates instead of fiddling with the
permission surface). A typed note is appended rather than discarded.
Addressable by number key (4 with remember, else 3); tooltip explains it.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
At size 12 the rotating logo-mark spinner on in-progress collapser cards
read as a static speck. Add a clideIconHero (24) control-geometry token
and use it for ClideStatusIndicator on the collapser — the spinner now
reads as motion at a glance; the success check / error cross share the
size so the card doesn't jump when the run settles. Only call site is the
collapser, so other status surfaces are untouched.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The tab strips — Claude session tabs (MultitabPane._TabStrip) and the
slot tab bar (ClideTabBar) — sat flush against the chrome above, reading
as cramped. Add a 1px top margin to both Containers so the pane surface
behind shows as a hairline gap, separating the tabBarBackground strip
from the chrome edge. Both are single-use widgets, so the margin applies
once per surface (no double-apply).
Regenerated the linux clide_tab_bar golden. (The macOS variant is now 1px
stale but is dormant on the linux gate; regenerate on macOS.)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Filed under UI epic T-276. The ClideTabBar
(lib/widgets/src/clide_tab_bar.dart) sits flush against the
chrome above it; add a 1px hairline of breathing room, applied
where it won't double up across the surfaces that embed a tab
bar. Changelog only — leaves concurrent lib/ work untouched.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Image cards, thumbnails, the lightbox, and `clide image show` rendered
via Image.file, whose FileImage keys Flutter's imageCache by (path,
scale) only — so overwriting a file at the same path handed back the
previously decoded frame (hit live re-exporting a wireframe PNG). Add
ClideFileImage, a FileImage that folds mtime + size into ==/hashCode so an
in-place change is a fresh cache key (miss → re-decode), and route the
five Image.file sites through it.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Records the T-7 -> T-317 merge on D-91's Relationship bullet (the
former Tier-5 canvas+graph epic folds into the unified canvas
epic; canvas pane T-322 + graph view T-323 consume the shared
renderer) and the D-91 index line. Plus the changelog for this
turn's board restructure: epic T-317, core engine T-318,
templates T-319/320/321, re-parented T-313/315/316, T-7 cancelled
as superseded, T-41 moved to T-276.
Governance + .pql/changelog only — leaves concurrent lib/ work
and CHANGELOG.md to the other worker on this branch.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The injected context block and the thinking / agent-prompt blocks
rendered as frameless `bare` cards, reading as unfinished `> context …`
rows next to the framed tool cards. Switch them to the bordered variant —
same panel border + left chevron + label as the surrounding cards — while
keeping the D-78 de-emphasis (muted accent, collapsed by default,
first-line summary; thinking gains a summary for parity). Adds a
conversation_card_meta golden.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>