test / unit + widget + golden + a11y (push) Failing after 28s
test / integration_test (xvfb) (push) Has been skipped
test / bundle smoke (xvfb 5s) (push) Has been skipped
test / daemon subprocess + web WASM smoke (push) Has been skipped
The IsolateClient and KernelServices now share the same DaemonBus.
Previously, backend events (pane.output, git.changed) went to a
separate bus that widgets couldn't see.
ClaudePane._spawnWhenReady waits for ProjectOpened before sending
pane.spawn, preventing "No project active" errors.
Recents loaded before runApp so the welcome screen shows them.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
macOS cmsghdr uses socklen_t (4 bytes) for cmsg_len, not size_t
(8 bytes like Linux). The Dart FFI struct was reading at wrong offsets
causing SCM_RIGHTS fd transfer to fail. Added CmsghdrDarwin with
Uint32 cmsg_len alongside the existing Linux layout.
SOL_SOCKET is 0xffff on macOS (was hardcoded to 1 for Linux).
Now platform-detected.
Switched from ad-hoc to Apple Development signing with team ID.
Removed app sandbox from entitlements — proper signing makes it
unnecessary. All SBPL hacks eliminated.
PtySession.spawn() runs recvFd in a child isolate to avoid blocking
the backend isolate's event loop.
Terminal testmode test now passes: pane.spawn via backend isolate
successfully forks and execs the shell.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
test / unit + widget + golden + a11y (push) Failing after 28s
test / integration_test (xvfb) (push) Has been skipped
test / bundle smoke (xvfb 5s) (push) Has been skipped
test / daemon subprocess + web WASM smoke (push) Has been skipped
PtySession.spawn() now runs recvFd in a child isolate via
Isolate.spawn so the blocking FFI call doesn't stall the backend
isolate's event loop.
Terminal testmode test spawns a real backend isolate, opens a project,
and sends pane.spawn via IPC — the exact same path the full app uses.
Currently fails: ptyc successfully starts but its fork+execvp is
blocked by the macOS sandbox ("Operation not permitted"). The SBPL
allows /bin/zsh exec from the app process, but ptyc's child process
may not inherit the exec permission, or the PTYC_SOCK_FD is not
inherited by the ptyc child (Dart Process.start fd inheritance on
macOS).
IsolateClient.events getter exposed for test access.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
test / unit + widget + golden + a11y (push) Failing after 31s
test / integration_test (xvfb) (push) Has been skipped
test / bundle smoke (xvfb 5s) (push) Has been skipped
test / daemon subprocess + web WASM smoke (push) Has been skipped
PtySession.spawn() uses synchronous FFI calls (socketpair, recvFd via
SCM_RIGHTS) that block the merged UI/platform thread on macOS. The
test correctly identifies this — PTY must move to the backend isolate.
Three tests added (echo, shell, write-to-child) that will run on
Linux where threads are separate. macOS skips with a diagnostic.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sends a valid JSON request to ptyc via stdin, verifies it parses the
request (exit 2 = syscall failed, not exit 1 = bad request). Full PTY
setup needs socketpair/SCM_RIGHTS which only PtySession provides.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
test / unit + widget + golden + a11y (push) Failing after 30s
test / integration_test (xvfb) (push) Has been skipped
test / bundle smoke (xvfb 5s) (push) Has been skipped
test / daemon subprocess + web WASM smoke (push) Has been skipped
Dropdown width 380 → 480 to prevent RenderFlex overflow on recent
project rows. "Close Workspace" → "Close Project". Keyboard shortcuts
show ⌘ on macOS instead of Ctrl.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Backend isolate now boots in two phases: resolve toolchain on spawn
(binary availability only), initialize services on project.open. The
dispatcher stays empty until a project activates — IPC requests before
that return "No project active".
Scheduler ticker only runs while a project is open. Fires an immediate
first cycle on ProjectOpened so sidebar panels refresh without waiting
for the next interval. Stops on ProjectClosed.
Renamed workspace → project throughout backend messages
(project.validate, project.open, project.ready), callbacks
(onProjectOpen, onValidateProject), and methods
(openProject, validateProject, resolveProject).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The merged UI/platform thread on macOS (Flutter 3.41) freezes on any
synchronous work — file I/O, Process.run, even isolate spawning during
early frames. No timing workaround (Timer, addPostFrameCallback,
Future.delayed) was reliable.
Fix: spawn a backend isolate that owns the DaemonDispatcher, GitClient,
PqlClient, FilesService, EditorRegistry, and Toolchain resolution. The
main isolate stays free for rendering. Communication uses SendPort with
the existing IPC message protocol (IpcRequest/IpcResponse/IpcEvent) —
zero new serialization.
New files:
backend.dart — spawns isolate, manages SendPort/ReceivePort
backend_entry.dart — isolate entry point, boots all services
isolate_client.dart — replaces InProcessClient for production
Toolchain now exposes resolveToolchainPaths() as a top-level function
with self-contained PATH expansion (no module-level state that would
prevent isolate message passing).
ClideTestApp gains boot-sequence tests: compute(), Isolate.run(),
sequential Process.run, and the full resolve+exec chain.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Teaches Claude when and how to use make run-testmode, which
category to run for a given change, how to interpret output,
and the pattern for adding new test cases.
Co-Authored-By: Claude <noreply@anthropic.com>
Six improvements to the testmode harness:
1. Shell passthrough tests use the resolved shell instead of
hardcoded /bin/zsh.
2. Exit code reflects test results (non-zero on any failure).
3. JSON summary line for machine-readable parsing.
4. IPC round-trip smoke (ping, version, unknown-cmd, encode/decode).
5. Extension lifecycle smoke (register + activate files, diff,
git, terminal; theme loading for all four bundled themes).
6. Test categories via CLIDE_TESTMODE dart-define (toolchain, ipc,
extensions, all). Makefile exposes TESTMODE_CATEGORY variable.
Also switches main.dart from bool.fromEnvironment to
String.fromEnvironment so category values other than "true" work.
Co-Authored-By: Claude <noreply@anthropic.com>
Replaces the transparent-background icons in the macOS asset
catalog with the black-circle variants from assets/logo/. The
64px size is downscaled from the 128px source since the master
set doesn't include that size.
Co-Authored-By: Claude <noreply@anthropic.com>
The package name is clide — the binary, bundle identifier, and
GTK application ID should match. Also aligns the macOS test host
paths and bundle identifiers.
Co-Authored-By: Claude <noreply@anthropic.com>
All six test/build scripts assumed a nested app/ package that
doesn't exist — the Flutter package lives at the repo root.
Removed every `cd app` and phantom path, consolidated the
redundant dart/flutter analyze passes in test.sh, and scoped
test_core.sh to core subsystem dirs so it no longer overlaps
with the full flutter test run.
Co-Authored-By: Claude <noreply@anthropic.com>
The hooks under .pql/hooks/ are installed locally by pql init —
they're runtime scaffolding, not source. The original block at
lines 49-51 already covers .pql/* with the pql-plan.json
negation; the second block was redundant.
Co-Authored-By: Claude <noreply@anthropic.com>
test / unit + widget + golden + a11y (push) Failing after 29s
test / integration_test (xvfb) (push) Has been skipped
test / bundle smoke (xvfb 5s) (push) Has been skipped
test / daemon subprocess + web WASM smoke (push) Has been skipped
The project switcher dropdown's "Open Local Project" action now uses
the native directory picker (same as the welcome screen). Shows "No
git repo found" dialog when the selected directory is not a git
repository.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
DebugProfile.entitlements gitignored (machine-specific sandbox paths).
native/dugite/ gitignored (downloaded at build time).
Linux runner: add pickDirectory handler using GtkFileChooserDialog
in the existing clide/window method channel.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
macOS sandbox blocks Homebrew git execution (symlinks resolve to Cellar
paths that SBPL cannot match). Bundled dugite-native — the same
relocatable Git distribution GitHub Desktop ships.
make dugite-fetch downloads the platform tarball to native/dugite/.
Toolchain checks the bundled binary first, sets GIT_EXEC_PATH and
GIT_TEMPLATE_DIR automatically. native/dugite/ is gitignored (57 MB
compressed).
Decision D-59 in tooling.md, dependency entry in licenses.yaml
(GPL-2.0 for the git binary, MIT for dugite-native build scripts).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Standalone test harness activated via CLIDE_TESTMODE=true dart-define.
Runs a table of existence checks and exec tests against all external
binaries (git, pql, tmux, ptyc, zsh), including zsh-passthrough and
env variants. Results printed to stdout and shown in a minimal UI.
Auto-exits after 15 seconds.
make run-testmode launches it with a 60-second kill timer and pipes
output to /tmp/clide-testmode.log.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Toolchain centralizes binary resolution — replaces five ad-hoc
mechanisms (expandedPath, _resolveGit, _resolve, _resolvePtyc,
_existsOnPath). Resolves via Future.delayed after runApp to avoid
blocking the merged UI/platform thread on macOS.
GitClient wraps all git operations with a typed API. Every subprocess
call goes through _run() using toolchain.git + toolchain.gitEnv.
Replaces free functions in operations.dart.
Native directory picker: NSOpenPanel on macOS (method channel in
AppDelegate), GtkFileChooserDialog on Linux. Falls back to text-input
dialog on web or MissingPluginException. Shows "No git repo found"
dialog when the selected directory is not a git repository.
PqlClient and pane commands updated to use Toolchain. ToolCheck
replaced by Toolchain.missing/allOk. All IPC handlers now catch
GitException to prevent unhandled exceptions on the merged thread.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
OS-detecting Makefile (make run works on macOS/Linux/Windows), 1280x720
default window in MainMenu.xib, squared app icons, sandbox with scoped
SBPL exceptions for subprocess execution, _DARWIN_C_SOURCE for ptyc
compilation, expanded PATH merging Homebrew and ~/.local/bin for GUI
apps, native traffic dots skipped on macOS (titlebar owns them).
DebugProfile.entitlements is gitignored (machine-specific SBPL paths);
a template with __HOMEDIR__/__PROJECTS__/__SHELL__ placeholders is
committed.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
test / unit + widget + golden + a11y (push) Failing after 26s
test / bundle smoke (xvfb 5s) (push) Has been skipped
test / integration_test (xvfb) (push) Has been skipped
test / daemon subprocess + web WASM smoke (push) Has been skipped
Pql skill: ticket show flags updated to reflect --with-context
replacing --with-decision and --with-children.
Co-Authored-By: Claude <noreply@anthropic.com>
test / unit + widget + golden + a11y (push) Failing after 26s
test / integration_test (xvfb) (push) Has been skipped
test / bundle smoke (xvfb 5s) (push) Has been skipped
test / daemon subprocess + web WASM smoke (push) Has been skipped
Replaces the N+1 parent-chain walk (one IPC call per ancestor, one
per decision ref) with a single pql ticket show --with-context call.
pql now returns ancestors and decisions arrays inline.
Updates PqlClient.ticketShow to accept withContext/withChildren flags,
removes the obsolete withDecision flag.
Co-Authored-By: Claude <noreply@anthropic.com>
test / unit + widget + golden + a11y (push) Failing after 35s
test / integration_test (xvfb) (push) Has been skipped
test / bundle smoke (xvfb 5s) (push) Has been skipped
test / daemon subprocess + web WASM smoke (push) Has been skipped
Theme-ui skill: document Phosphor Icons section with codepoint CSV
reference, icon lookup workflow, and bold/fill weight usage.
Pql skill: update ticket status command to reflect batch ID support
and removed state machine enforcement.
Changelog: scheduler service, auto-refresh, ClideAccordion, status
buttons, per-status ticket sections, codepoint CSV.
Co-Authored-By: Claude <noreply@anthropic.com>
Decisions: file-change subscription for decisions/*.md plus 1-minute
scheduler tick. Tickets: 1-minute scheduler tick plus changed-event
subscription from status button clicks. PQL markdown tab: file-change
subscription for *.md files. All panels get a manual refresh button.
Accordion sections use pin/focus logic: manually toggled sections are
pinned and stay open; the focused item's section auto-opens; unpinned
sections without focus auto-collapse. Both decisions and tickets views
use ClideAccordion with this pattern.
Ticket sidebar split into six status sections (IN PROGRESS, REVIEW,
READY, BACKLOG, DONE, CANCELLED) matching pql's actual statuses.
Status changes scroll the ticket into its new section.
Co-Authored-By: Claude <noreply@anthropic.com>
Status buttons in the detail view now call pql.tickets.status IPC,
publish a changed event to refresh the sidebar list, and reload the
detail. Disabled for the current status. IPC handler accepts ids as
a list for batch transitions. PqlClient.ticketSetStatus takes
List<String> and joins with comma per pql CLI contract.
Co-Authored-By: Claude <noreply@anthropic.com>
ClideAccordion — shared accordion section with optional leading widget,
replaces private _AccordionSection in tickets and decisions views.
Phosphor arrowClockwise icon (0xe036) for refresh buttons. Full
codepoint reference CSV (1512 glyphs) at assets/fonts/phosphor/ for
icon lookup without external tools.
Co-Authored-By: Claude <noreply@anthropic.com>
Tiered Timer.periodic instances (1min, 10min, 15min, 1hr, midnight)
running on a dedicated Dart isolate. Tick messages sent back to the
main isolate via SendPort and emitted as SchedulerTick events on the
DaemonBus. Extensions subscribe with events.on<SchedulerTick>() and
filter by tier.
Co-Authored-By: Claude <noreply@anthropic.com>
test / unit + widget + golden + a11y (push) Failing after 33s
test / integration_test (xvfb) (push) Has been skipped
test / bundle smoke (xvfb 5s) (push) Has been skipped
test / daemon subprocess + web WASM smoke (push) Has been skipped
Search tab defaults to ranked text search via pql search — debounced
300ms, scored results with visual score bar. DSL toggle switches to
raw PQL query mode for SQL-like queries. Clicking a search result
opens it in the markdown context viewer.
Adds pql.search IPC command and PqlClient.search method. Controller
gains SearchMode enum and search() method alongside existing runQuery.
Co-Authored-By: Claude <noreply@anthropic.com>
Search (PQL DSL query) is now the default left tab; Markdown (filtered
to .md files) on the right. Clicking a markdown file publishes on
the message bus; the markdown extension activates the context panel
viewer and re-publishes on a load channel after the frame so the
viewer is guaranteed to be mounted. Viewer subscribes to load channel
and editor buffer events, publishes focus for sidebar highlighting.
Co-Authored-By: Claude <noreply@anthropic.com>
Register files.read command for reading file content by relative path.
Remove top padding on context panel container and mainAxisSize.min
from ClidePaneChrome so the header sits flush and the pane fills
available height. Context panel max raised from 420px to 1000px.
Co-Authored-By: Claude <noreply@anthropic.com>
Each ClideCodeBlock and EditorView created its own TreeSitterService,
each allocating a WASM engine, store, parser, and cursor via FFI.
When widgets were disposed, multiple instances freeing the same
underlying native resources caused double-free corruption on startup.
Single shared instance for the app lifetime. Also fixes overlapping
tree-sitter spans that caused duplicated text in code blocks — spans
are now clipped to avoid re-emitting already-rendered characters.
Co-Authored-By: Claude <noreply@anthropic.com>
All sidebar and detail panes use clideFontSmall/clideFontBadge/
clideFontCaption instead of hardcoded sizes — single place to tune.
Decision detail view subscribes to the message bus for selection
events (same pattern as ticket controller) and publishes focus after
loading. Both decisions and tickets sidebar views subscribe to the
focus channel, expand the accordion section, highlight the active
card, and scroll it into view.
Clickable DQRT links wired in decision detail, ticket detail, and
markdown viewer via onRecordTap. Ticket descriptions now render
through ClideMarkdown instead of plain text.
Co-Authored-By: Claude <noreply@anthropic.com>
Ctrl+Plus/Minus/0 text zoom (5% steps, 60%–200%) via MediaQuery
textScaler. App-wide clideLineHeight (1.25) applied in DefaultTextStyle.
Context panel drag resize was inverted — dragging left shrank the
panel instead of growing it. Negate delta for right-anchored slots.
Default sidebar widened from 240px to 400px, context panel from 280px
to 420px (both at their previous maximums).
Co-Authored-By: Claude <noreply@anthropic.com>
Inline grouping collapses consecutive inline nodes (strong, em, code,
a, del) into a single RichText widget instead of rendering each as a
separate block — fixes tight list items like `builtin.git` appearing
on its own line. HTML entity unescaping moved from pre-parse (useless)
to post-AST extraction where the markdown package actually introduces
the entities. Explicit Josefin Sans Light font family and 1.25 line
height on all RichText spans. Body text bumped to 16px; inline code
uses clideFontMono for visual weight parity.
Adds onRecordTap callback — markdown links matching [DQRT]-\d+ render
as tappable WidgetSpans with hover underline. New typography constants
clideFontSmall (12), clideFontBadge (11), clideLineHeight (1.25).
Co-Authored-By: Claude <noreply@anthropic.com>
More vertical breathing room between paragraphs (8→12), list
items (2→6), headings (increased top/bottom). Tighter horizontal
indent on lists (16→8) and blockquotes (12→8). Added HTML entity
unescaping (quot, amp, lt, gt, apos) before parsing.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Both tickets and decisions extensions now uncontribute and
re-contribute the detail tab on every selection, passing the
selected ID via initialId. This guarantees the view loads
immediately — no first-click miss from the widget not being
built when the message fires.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New pql.decisions.read IPC verb returns the full markdown section
body. Decision detail view now shows: title card, full decision
text (rationale, cost, cross-references), and clickable ref cards
for cross-reference navigation.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Clicking a parent ticket in the tree publishes
builtin.tickets/selection — loads that ticket in the detail view.
Clicking a decision ref publishes builtin.decisions/selection —
switches context panel to the decision detail. Both show hover
highlight. Enables full cross-reference navigation without
leaving the context panel.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Detail controller publishes builtin.tickets/focus with the loaded
ticket ID after every load. Ticket list subscribes and highlights
the matching card with selected background and accent border.
Works regardless of what triggered the detail load — sidebar
click, parent tree navigation, or future command palette.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Extension listens to its own selection channel and activates the
detail tab in the context panel — fixes the chicken-and-egg where
the controller only subscribes after the widget builds. Registration
order in main.dart now determines sidebar icon rail order: tickets
first, then decisions, files, git, pql, problems.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Icons now declared on TabContribution via the icon field — the
hardcoded switch in _BottomRail is a fallback only. All sidebar
and context extensions set their Phosphor icon explicitly.
PanelRegistry supports setTabOrder(slot, List<String>) — tabs
render in the order specified by project.layout.sidebar.order /
context.order in settings.yaml. Falls back to registration order.
Priority field removed from all contributions.
Context tabs are static again — persist with their last content,
selection just loads new data and switches focus. No spawn/despawn.
Tickets sidebar priority set to -200 (leftmost, default open).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Two flow fixes:
1. First click now works — extension passes initialId to the
detail view constructor, which loads immediately in
didChangeDependencies. No second click needed.
2. Tab despawns when user navigates away — extension listens to
PanelRegistry changes, despawns detail tab when it's no longer
the active context panel tab.
Each selection re-creates the tab with a fresh initialId so the
view always matches the selection. Applied to both tickets and
decisions.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Context panel tabs are no longer static. Extensions spawn them
dynamically when relevant and despawn on deactivate:
- Tickets: detail tab spawns on builtin.tickets/selection
- Decisions: detail tab spawns on builtin.decisions/selection
- Backlinks: spawns when editor opens a file
- Markdown viewer: spawns when editor opens a .md file
- Graph: removed from static context (will be command-spawnable)
The icon rail only shows what's active — no empty tabs sitting
there waiting for content.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>