Commit Graph
225 Commits
Author SHA1 Message Date
jpmschweitzerandClaude Fable 5 75fc2719a0 cache the kernel ref so dispose() can actually clean up (T-366)
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>
2026-06-12 00:24:27 +02:00
jpmschweitzerandClaude Fable 5 466383671d close the PTY master fd when the child exits naturally (T-360)
_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>
2026-06-12 00:18:47 +02:00
jpmschweitzerandClaude Fable 5 3ed90fc318 file the 2026-06-11 Fable review under epic T-359
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>
2026-06-12 00:13:52 +02:00
jpmschweitzerandClaude Opus 4.8 1e24f0022d close out T-325 in the ticket board
Persist the live-tail story's done transition (ticket-DB sweep only).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-11 19:17:09 +02:00
jpmschweitzerandClaude Opus 4.8 898a0316e5 claude: Bash live-tail detection + read-only file follower (T-325, core)
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>
2026-06-11 17:12:53 +02:00
jpmschweitzerandClaude Opus 4.8 d43ddfed9c pql: refine T-47 (clide self-update) and return it to the backlog
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>
2026-06-11 15:33:36 +02:00
jpmschweitzerandClaude Opus 4.8 4c33a85bf0 claude: give each spawned subagent its own collapsing card (T-342)
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>
2026-06-11 14:57:21 +02:00
jpmschweitzerandClaude Opus 4.8 ce200765cc claude: accepting ExitPlanMode exits plan mode in the panel (T-337)
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>
2026-06-11 14:34:50 +02:00
jpmschweitzerandClaude Opus 4.8 430189d714 keymap: support bare-modifier double-tap chords; double-Shift → quick-open (T-341)
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>
2026-06-11 13:26:54 +02:00
jpmschweitzerandClaude Opus 4.8 fc4021e98b main: boot the daemon at the last project, not HOME (T-352)
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>
2026-06-11 12:32:18 +02:00
jpmschweitzerandClaude Opus 4.8 34ce01cbf1 ci: add osv-scanner supply-chain gate to push-check (T-353)
`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>
2026-06-11 09:06:22 +02:00
jpmschweitzerandClaude Opus 4.8 1238802f54 deps: CVE audit + refresh safe pins, document held ones (T-353)
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>
2026-06-11 08:58:54 +02:00
jpmschweitzerandClaude Opus 4.8 138872e990 release v2.3.1
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>
2026-06-10 20:40:09 +02:00
jpmschweitzerandClaude Opus 4.8 a0501b4a0a pql: refetch ticket + decision sidebars when the workspace opens (T-352)
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>
2026-06-10 20:38:44 +02:00
jpmschweitzerandClaude Opus 4.8 7cea13c5c0 linux: request no-decorations on map, not just realize (T-351)
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>
2026-06-10 20:24:50 +02:00
jpmschweitzerandClaude Opus 4.8 9a8175903b pql: retry transient db-busy so sidebar panes don't stick (T-350)
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>
2026-06-10 20:20:36 +02:00
jpmschweitzerandClaude Opus 4.8 b648523a1a release v2.3.0
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>
2026-06-10 19:51:35 +02:00
jpmschweitzerandClaude Opus 4.8 16dc628fee linux: require wayland-client so frameless chrome can't be dropped (T-349)
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>
2026-06-10 19:46:25 +02:00
jpmschweitzerandClaude Opus 4.8 b7e0835b74 pre-push: skip the test suite unless lib/ or pubspec changed (T-348)
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>
2026-06-10 19:22:12 +02:00
jpmschweitzerandClaude Opus 4.8 36f4561ca1 expand PATH on Linux so desktop-launched clide finds pql (T-347)
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>
2026-06-10 19:22:12 +02:00
jpmschweitzerandClaude Opus 4.8 b441b9d3dc make the coverage harness concurrency-safe (T-345)
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>
2026-06-10 18:35:02 +02:00
jpmschweitzerandClaude Opus 4.8 fb0179d493 align card font sizes across the conversation stream (T-344)
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>
2026-06-10 18:15:56 +02:00
jpmschweitzerandClaude Opus 4.8 75cf14f1cb tickets panel: per-type filter chips (T-343)
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>
2026-06-10 18:13:04 +02:00
jpmschweitzerandClaude Opus 4.8 91b7dbef4d tickets: file T-343 — ticket-panel type filter chips
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>
2026-06-10 17:54:40 +02:00
jpmschweitzerandClaude Opus 4.8 4a9f57b14a tickets: expand T-342 — route nested runs to the right per-agent card
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>
2026-06-10 17:29:25 +02:00
jpmschweitzerandClaude Opus 4.8 bc7ee3b88c tickets: file T-342 — per-subagent activity cards
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>
2026-06-10 17:27:35 +02:00
jpmschweitzerandClaude Opus 4.8 3134a0ac52 tickets: backlog relevance sweep (sub-T-100)
Swept the 19 backlog tickets with ids below T-100 for relevance against
the current codebase + governance.

Cancelled (obsolete):
- T-26 web-tree-sitter — contradicts the desktop-first guardrail
- T-60 workspace trust prompt — premature; third-party ext loading unshipped
- T-40 PRs tab — unscoped, no extension, data path undecided

Annotated (stale text / mixed state, work still valid):
- T-25, T-27 — app/ path prefix stale post-D-56
- T-8 — mixed Tier-6 completion (theme-picker done, settings-ui stub)
- T-55 — split: tmux persistence done, OS tray still a stub
- T-41 — likely superseded by canvas epic (T-317/D-91)
- T-67 — reframe from one-time audit to coverage ratchet
- T-81 — T-79/T-80 done, #21 obsolete, ~7 items remain

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-10 17:18:11 +02:00
jpmschweitzerandClaude Opus 4.8 66d3d024ca log the failing command on a dispatch error (T-80)
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>
2026-06-10 16:59:09 +02:00
jpmschweitzerandClaude Opus 4.8 8fef818d97 tickets: flush pql changelog export (T-57 notes)
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>
2026-06-10 16:48:52 +02:00
jpmschweitzerandClaude Opus 4.8 848f1a4dab tickets: cancel T-45 (obsolete), add notes to T-57
- 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>
2026-06-10 16:45:46 +02:00
jpmschweitzerandClaude Opus 4.8 30df42c789 fix licenses.yaml drift vs pubspec
- 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>
2026-06-10 16:44:48 +02:00
jpmschweitzerandClaude Opus 4.8 3b23da052e fold the Deny & simplify denial instead of a red error (T-340)
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>
2026-06-10 16:29:30 +02:00
jpmschweitzerandClaude Opus 4.8 a948bc8a1f pick-up sets the ticket to in_progress on accept (T-339)
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>
2026-06-10 16:18:16 +02:00
jpmschweitzerandClaude Opus 4.8 dea3e70e49 fold sub-agent prompts via parent_tool_use_id (T-338)
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>
2026-06-10 16:03:50 +02:00
jpmschweitzerandClaude Opus 4.8 026e331146 clickable file references in the Claude conversation (T-300)
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>
2026-06-10 15:55:53 +02:00
jpmschweitzerandClaude Opus 4.8 984bf0cfaf file T-338: agent prompt renders as a 'you' card instead of folding into the Activity Agent card
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>
2026-06-10 15:48:43 +02:00
jpmschweitzerandClaude Opus 4.8 c6fa384972 file SSH-remote workspaces epic (T-329) with phased stories
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>
2026-06-10 15:29:00 +02:00
jpmschweitzerandClaude Opus 4.8 ec88944896 Deny & simplify note: tell Claude not to narrate the retry (T-328)
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>
2026-06-10 15:19:15 +02:00
jpmschweitzerandClaude Opus 4.8 597b2f7622 dismiss the lightbox on a tap outside the image (T-309)
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>
2026-06-10 15:18:00 +02:00
jpmschweitzerandClaude Opus 4.8 9607124c2b fix ClideStatusIndicator duplicate-key crash on rapid status flips (T-326)
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>
2026-06-10 15:00:58 +02:00
jpmschweitzerandClaude Opus 4.8 3097d5f63b hand a ticket to Claude from the sidebar (T-327)
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>
2026-06-10 14:52:27 +02:00
jpmschweitzerandClaude Opus 4.8 aa6f112164 bump run-status spinner to 26 (T-304)
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>
2026-06-10 14:40:52 +02:00
jpmschweitzerandClaude Opus 4.8 4f632d3cdd dock Claude's task list above the composer (T-308)
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>
2026-06-10 14:31:35 +02:00
jpmschweitzerandClaude Opus 4.8 2c8e9f2821 add 'Deny & simplify' permission option (T-311)
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>
2026-06-10 14:14:00 +02:00
jpmschweitzerandClaude Opus 4.8 01445c4fae enlarge the activity-card run-status spinner (T-304)
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>
2026-06-10 14:05:17 +02:00
jpmschweitzerandClaude Opus 4.8 3dd770c0a6 add 1px breathing room above tab strips (T-324)
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>
2026-06-10 13:36:35 +02:00
jpmschweitzerandClaude Opus 4.8 ba968223fe file T-324: 1px margin above the tab strip (cramped tabs)
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>
2026-06-10 13:26:18 +02:00
jpmschweitzerandClaude Opus 4.8 a879238102 fix image stale-render on in-place overwrite (T-312)
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>
2026-06-10 13:25:58 +02:00
jpmschweitzerandClaude Opus 4.8 1194527ad5 T-317: merge canvas work into one drawing-card epic (D-91 follow-up)
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>
2026-06-10 13:25:04 +02:00
jpmschweitzerandClaude Opus 4.8 7a98cbae4b frame the context / thinking / agent-prompt meta cards (T-306)
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>
2026-06-10 13:16:41 +02:00