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 T-325 and T-342 entries leaked commit-body detail into the changelog;
shorten to user-facing impact per the changelog-gate cap.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Wire the detection + follower core into the Bash tool card. A Bash card
with a follow intent (`tail -f …`) gains a "live tail" segment below the
result: an embedded read-only TerminalView fed by FileTailFollower on the
file the command follows, resolved against the open workspace.
Lazy lifecycle for free: the collapser builds its children only when
expanded (clide_collapser_card.dart), so _BashLiveTail starts the follower
in didChangeDependencies on expand and stops it in dispose on collapse —
no follower runs until the card is expanded. No resolvable file-backed
source → a muted "no independent source to follow" note, never an empty
terminal. The workspace root comes from kernel.project.current, so no new
plumbing through the conversation widget tree.
Tests: a tail Bash card surfaces the segment (+ the muted note when no
project/source); an ordinary `ls` card gets no segment; the segment only
builds on expand.
Co-Authored-By: Claude Opus 4.8 (1M context) <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>
Patch release: the daemon boots its pql/git/files workspace at the last
opened project instead of the launch directory (HOME) on a desktop
launch, so the ticket/decision sidebars load on first open instead of
erroring against a stale ~/.pql/pql.db (T-352). Also raises the toolchain
floor to Flutter 3.35 / Dart 3.9 and refreshes dependencies after a clean
CVE audit (T-353).
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>
Now that the SDK floor is Dart 3.9 (markdown 7.3.1 requires ^3.9.0), take
the bump. 7.3.0/7.3.1 are bug-fixes + perf with no breaking AST/Node
changes (we walk the parsed tree in our own renderer); only API-level
deprecations (LinkContext, BlockParser.standardBlockSyntaxes) we don't
use. licenses.yaml updated in the same commit; markdown goldens green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Raise the declared minimums in pubspec.yaml to what our deps already
require: Flutter >=3.35.0 / Dart >=3.9.0 (was 3.19.0 / 3.5.0). alchemist
0.12 needs Flutter 3.32; Dart 3.9 first ships in Flutter 3.35, so 3.35 is
the binding floor. Pin the exact build toolchain in .fvmrc (Flutter
3.44.1).
Moving to the Dart 3.9 language level switches `dart format` to the new
"tall" style and enables two new lints. This commit is the resulting
mechanical churn, isolated from any behaviour change:
- whole-tree `dart format` reformat (tall style)
- `dart fix` for unnecessary_underscores + use_null_aware_elements
No runtime behaviour change; `make test` green.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Keep the security gate out of the local pre-push path so dev machines
don't need osv-scanner installed. The `make security` target and
ci/osv_scan.sh stay for the CI PR-merge pipeline (and on-demand local
runs); only the push-check prerequisite is removed, with a NOTE in the
Makefile explaining where it runs instead.
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: the real fix for the ticket/decision sidebars failing on
first load — IPC-server swaps are now serialized so the repo workspace
bind always wins over the boot launch-CWD bind (T-352). Supersedes the
partial 2.3.1 re-fetch-on-open, which is kept for mid-session switches.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The 2.3.1 fix (re-fetch the pql sidebars on ProjectOpened) only helped
the picker-first path, where the project opens after the window is up.
With sticky-startup the project opens during boot, before the panes
mount and subscribe, so they never received the event — the sidebars
stayed broken.
Root cause is a race in the IPC-server lifecycle. The boot factory fires
swapIpcServer(launchCwd) with unawaited(); the project-open flow then
fires swapIpcServer(repo). Each swap stops the live server, binds a new
one, and reconnects the daemon client. Unserialized, the two interleave
and the late-finishing boot swap can clobber the repo bind, reconnecting
the client to the launch-CWD (HOME) socket. The daemon's PqlClient (and
git/files) then run against the wrong workspace, so the first
pql.tickets.list hits a stale/global pql.db and errors
("ticket_deps.blocker_record_id missing — pql.db is from an earlier
schema"). A manual refresh worked because by then things had settled.
Chain every swap on a serialization Future so they apply in call order;
the repo swap is issued last and therefore wins. Kept the pane re-fetch
from 2.3.1 — it still covers genuine mid-session project switches.
Verified app boot is unaffected (test/app_test.dart green).
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>
The ticket_idmap export was uncommitted working-tree churn that a rebase
DB-rebuild dropped, so pql could not resolve T-347 by id. Re-export the
mappings from the rebuilt DB.
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 external `timeout`/`setsid` wrapper is GNU coreutils and absent on
macOS. When `timeout` wasn't found, run_pass captured the negated
pipeline status (0) into rc and `exit $rc` exited 0 — so the entire core
suite was silently skipped at every push on macOS, while push-check went
green. Switch to dart test's built-in --timeout, the same portable hang
guard ci/test.sh already uses; the core dart passes previously had no
per-test timeout at all. Loses the process-group SIGKILL backstop, which
only fired for a wedged PTY child that ignored the in-Dart timeout.
Co-Authored-By: Claude <noreply@anthropic.com>
macOS had only 3 of the 8 platform goldens linux carries; the
conversation-card, collapser, and tool-collapser suites never had a
macOS baseline, and clide_tab_bar was stale after recent card/font
changes. Regenerated against current rendering so the suite passes on
macOS with full linux parity.
Co-Authored-By: Claude <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>
The T-339 pick-up test was the only importer of the ~450-line claude
extension.dart, pulling its (mostly UI-wiring, untestable) lines into
the coverage denominator and dropping the suite below the 95% floor.
Move applyTicketPickUp into its own ticket_pick_up.dart and the T-300
path resolver into a pure resolveWorkspaceFilePath() — both small, fully
covered, and imported by the tests instead of the whole extension. No
behavior change.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
dart format was missed on this file in the T-300 commit; the pre-push
gate's --set-exit-if-changed caught it.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Found by a docs/ staleness audit:
- architecture.md: Claude no longer runs under tmux — it's driven over
the stream-json control protocol with --resume (D-75/D-77/D-78); and
the IPC socket server is implemented, not "currently unimplemented".
- testing/README.md + claude-ui-workflow.md: drop the dissolved app/
two-package paths (D-56) — tests live at test/ and the web build at
build/web/.
- design/multitab-pane.md: the Claude pane spawns a stream-json session,
not a tmux one; ClaudeSessionRef carries the session id.
Frozen historical snapshots (initial-plan.md, the HISTORICAL pty docs,
dated spikes/audits) left as-is.
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>
Tell the git-commit skill and CLAUDE.md not to hand-stage .pql/changelog
— the pre-commit hook exports and stages it on every commit. The only
caveat: a ticket-only turn must make at least one commit to fire the hook.
Already documented in the pql skill.
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>
Add a "Tooling discipline" note to CLAUDE.md — run gates via the make
targets (e.g. make changelog-gate), not the ci/ scripts they wrap; the
Bash working dir is the repo root (no cd / git -C); one command per
invocation. Point the git-commit skill at make changelog-gate for the
60-word cap instead of naming the raw script.
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>