Commit Graph

2617 Commits

Author SHA1 Message Date
Mohamed Boudra
76b9f89f68 fix: tolerate beta release creation races v0.1.60-beta.1 2026-04-20 20:41:24 +07:00
github-actions[bot]
970bf828b3 fix: update lockfile signatures and Nix hash 2026-04-20 13:40:07 +00:00
Mohamed Boudra
dfc814147a feat: add beta release channel 2026-04-20 20:38:56 +07:00
Mohamed Boudra
831d990ef7 fix(release): avoid notes sync create races v0.1.60-rc.3 2026-04-20 19:37:46 +07:00
Mohamed Boudra
e09fd41adc fix(release): patch existing release notes by id 2026-04-20 19:33:39 +07:00
github-actions[bot]
8d32167826 fix: update lockfile signatures and Nix hash 2026-04-20 12:29:27 +00:00
Mohamed Boudra
1cfae98bf5 chore(release): cut 0.1.60-rc.3 2026-04-20 19:28:23 +07:00
Mohamed Boudra
4cbfe95473 fix(server): treat pi aborts as cancellations 2026-04-20 19:02:37 +07:00
Mohamed Boudra
242f61937a fix(app): stabilize terminal creation handler 2026-04-20 19:02:34 +07:00
Mohamed Boudra
d913c4a9b7 fix(app): isolate bottom sheet modal scopes 2026-04-20 19:02:31 +07:00
Mohamed Boudra
2cd296e38f Fix workspace shortcut navigation 2026-04-20 18:06:09 +07:00
Mohamed Boudra
95c1d1fe0f Fix workspace composer focus routing 2026-04-20 17:41:00 +07:00
Mohamed Boudra
33ac657fed fix(app): treat workspace diff stats as authoritative 2026-04-20 17:40:11 +07:00
Mohamed Boudra
067125bd4f Fix composer safe-area ownership 2026-04-20 17:35:20 +07:00
Mohamed Boudra
93095aa1d2 Fix dictation readiness after app refresh 2026-04-20 17:23:17 +07:00
Mohamed Boudra
ac45f23213 Fix mobile sidebar regressions and workspace e2e 2026-04-20 16:38:12 +07:00
github-actions[bot]
b91749a316 fix: update lockfile signatures and Nix hash 2026-04-20 09:15:24 +00:00
Mohamed Boudra
a6423f7f0a Improve workspace navigation and render isolation 2026-04-20 16:14:22 +07:00
Mohamed Boudra
403fb03c97 feat(app): retain workspace screens on sidebar switch 2026-04-20 12:55:58 +07:00
Mohamed Boudra
f8411d121e Separate explorer checkout from panel state 2026-04-20 12:40:39 +07:00
Mohamed Boudra
9ea75afd37 Fix welcome screen unistyles leak 2026-04-20 12:40:30 +07:00
Mohamed Boudra
006894274e fix(desktop): patch React DevTools manifest for Electron compatibility 2026-04-20 11:16:21 +07:00
Mohamed Boudra
951fadc104 fix(mcp): accept null in list_models output schema 2026-04-20 11:06:21 +07:00
Mohamed Boudra
8600f183b1 feat(sidebar): restore PR state color, swap badge order, brighten checks on hover
- PR icon color reflects merge state (open/merged/closed) via the
  existing getWorkspacePrIconColor helper.
- PR badge is rendered before the failed-checks badge in the workspace
  row.
- Hovering the PR badge swaps the GitPullRequest icon for ExternalLink
  in place (same size, no layout shift) and removes the trailing arrow.
- Hovering the checks row in the workspace hover card brightens the
  icon and "Checks" label to foreground.
2026-04-20 10:57:27 +07:00
Mohamed Boudra
002946d4dd fix(sidebar): prevent text selection when dragging project/workspace rows
The drag handle was attached only to the left sub-view of each row, so
grabbing the right half initiated no drag, and pointerdown on the branch
or project title raced the browser's text-selection start before
dnd-kit's activation threshold — often producing a text selection
instead of a drag.

Move dragHandleProps to the outer row wrapper, add userSelect: none to
the row styles, and tighten PointerSensor activation distance.
2026-04-20 10:49:46 +07:00
Mohamed Boudra
fb02bc8795 fix(workspace): collapse header loading skeleton to a single bar
The header now shows only one row of text, so drop the second skeleton
and widen the primary bar to match.
2026-04-20 10:46:23 +07:00
Mohamed Boudra
53baa16bee refactor(checkout-diff): rely solely on subscription for data
Drop the one-shot getCheckoutDiff query and use skipToken; the
subscribe_checkout_diff flow populates the cache on subscribe response
and updates. Derive isLoading from the presence of cached payload and
remove the now-unused isError/error fields from git-diff-pane.
2026-04-20 10:45:59 +07:00
Mohamed Boudra
67eddbd6a9 perf(explorer-sidebar): memoize animation context value
Stabilize animateToOpen/animateToClose with useCallback and wrap the
provider value in useMemo so consumers don't re-render on every parent
re-render.
2026-04-20 10:45:55 +07:00
Mohamed Boudra
044546ae0c perf(explorer-sidebar): skip PR queries when sidebar is closed
Thread isOpen down to SidebarContent so usePrPaneData stays disabled
until the user actually opens the sidebar.
2026-04-20 10:45:51 +07:00
Mohamed Boudra
bd748b6edc perf(workspace): gate side effects on stack route focus
Pass useIsFocused through as isRouteFocused rather than short-circuiting
the whole tree. Terminals query/subscription, checkout diff, providers
snapshot, keybindings, tab reconciliation, focused-agent writes, and
sidebar rendering all no-op when the route is in the stack but not
focused, so a hidden workspace screen no longer drives background work.
2026-04-20 10:45:48 +07:00
Mohamed Boudra
427664dfa7 fix(app): drop getId from workspace stack route
Expo Router maps getId to React Navigation getId, which reorders an
already-mounted workspace screen on Android native-stack/Fabric. Keep
workspace identity/retention outside the route-level API and leave a
comment warning against re-adding it.
2026-04-20 10:45:02 +07:00
Mohamed Boudra
a0169bf7f4 feat(app): export isDev platform flag and enable runtime metrics in dev
Adds a shared isDev constant alongside isWeb/isNative and wires daemon
clients to collect runtime metrics (10s interval) only in development.
2026-04-20 10:44:57 +07:00
Mohamed Boudra
79968ee02d feat(daemon-client): add opt-in runtime metrics collector
Aggregates inbound message counts, bytes, handler timings, and
agent_stream breakdowns over a rolling window and flushes via logger.
Gated on runtimeMetricsIntervalMs config; disabled by default.
2026-04-20 10:44:43 +07:00
Mohamed Boudra
afe0eaab5b Set APP_VARIANT=development in app startup scripts 2026-04-20 09:07:34 +07:00
Mohamed Boudra
04465f124c Add dev mock load-test provider 2026-04-20 00:38:10 +07:00
Mohamed Boudra
86b83c3366 Fix workspace diff stat watch refresh 2026-04-20 00:36:54 +07:00
github-actions[bot]
4a5dd986e1 fix: update lockfile signatures and Nix hash 2026-04-19 16:23:48 +00:00
Mohamed Boudra
64065061c5 chore(release): cut 0.1.60-rc.2 v0.1.60-rc.2 2026-04-19 23:21:12 +07:00
Mohamed Boudra
7b9636a22d fix(server): bypass diff cache on working-tree watch refresh
CheckoutDiffManager.refreshTarget was calling workspaceGitService.getCheckoutDiff
without forcing a cache bypass, so watch-fired refreshes within the 15s consumer
TTL returned the pre-mutation cached diff — fingerprint matched, no
checkout_diff_update was emitted, and the sidebar diff appeared frozen while an
agent edited files. Route watch-fired refreshes through the service with
{ force: true, reason: "working-tree-watch" } so they always recompute.
2026-04-19 23:19:41 +07:00
Mohamed Boudra
8165de7b06 feat(server): replay pi tool calls in streamHistory for resume
Pi's streamHistory only emitted text, so resuming a session lost tool
calls, tool results, and bash executions from the replayed timeline.
Iterate session.messages to also emit running/completed/failed tool_call
items and bashExecution shell calls, and tag user messages with a stable
messageId so hydrateTimelineFromLegacyProviderHistory can dedupe.

Cover it with a real OpenRouter-backed e2e test that runs a bash tool
call, resumes via PiDirectAgentClient.resumeSession, and asserts the
replayed timeline contains the user message, assistant message, and
completed shell tool_call with the expected output.
2026-04-19 23:17:40 +07:00
Mohamed Boudra
75f83b0b9b Merge refactor/session-store-identity into main 2026-04-19 22:36:10 +07:00
Mohamed Boudra
badec6f587 Merge orchestrate/notif-routing-presence into main 2026-04-19 22:35:37 +07:00
Mohamed Boudra
5a2708653c feat(server,app): redesign git/GitHub refresh architecture with server authority
Centralizes refresh orchestration in WorkspaceGitService and GitHubService:
server coalesces, deduplicates, and throttles git/GitHub reads; clients peek
snapshots (cold reads fall through to a one-shot fetch) and never drive
refreshes. Introduces a two-TTL model (consumer vs internal), force-emit
bypass so fingerprint-matched refreshes still propagate, notifyGitMutation
wiring at ~13 action handlers, adaptive GitHub polling based on check state,
and checkout_status_update / prStatus push-to-cache wire messages. Fixes the
stale diff-stat bug and the inverted base-branch diff direction, and flips
next-action affordances promptly after commit / PR merge.
2026-04-19 22:35:26 +07:00
Mohamed Boudra
06b3fc2ec6 fix(server,app,desktop): route in-app notifications by presence cascade
Replaces the per-client stale/visibility policy with one shared
presence cascade so a backgrounded Firefox tab can no longer steal
in-app notifications from an active Electron desktop window.

Server (`agent-attention-policy.ts`): exports `PRESENCE_THRESHOLD_MS`
(3 min) and `computeNotificationPlan({ allStates, agentId, reason,
nowMs })` returning `{ inAppRecipientIndex, shouldPush }`. Cascade:
focus suppression requires presence; otherwise the most-recent
present client wins (lower-index tiebreak); push fires only when no
client is present, and never on `error`. `broadcastAgentAttention`
calls the policy once per event.

Electron (`daemon-manager.ts`, `idle.ts`): registers
`desktop_get_system_idle_time` returning `powerMonitor
.getSystemIdleTime() * 1000`. Renderer wrapper
`getDesktopSystemIdleTimeMs()` is best-effort: rejected IPC, null,
NaN, Infinity, or negative values return null without throwing.

Hook (`use-client-activity.ts`): Electron-only effect polls every 5s
and updates `lastActivityAtRef` only forward, so OS-wide activity
keeps a backgrounded Electron window present while in-window events
still update immediately.

`ClientHeartbeatMessageSchema` is unchanged; old/new clients and
daemons remain wire-compatible.

Tests: 52 focused tests across policy unit, dispatch, e2e, hook,
desktop wrapper, and permissions. Phase-3 dispatch test +
Phase-5 stale-poll test verified by mutation (breaking the focus
check / the `>` guard makes the exact regression fail).
2026-04-19 21:48:39 +07:00
Mohamed Boudra
bd1fb311ea refactor(app): reshape session store reads around narrow hook surface
Eliminate sidebar re-render cascades by fixing both sides of the
subscription contract:

- Session-store writes preserve identity: setWorkspaces, mergeWorkspaces,
  removeWorkspace, and patchWorkspaceScripts return the previous Map/entry
  reference when content is unchanged.
- HostRuntimeController.updateSnapshot only notifies when a patched field
  actually changed; idle probe ticks no longer replace the snapshot.
- New canonical hook surface in stores/session-store-hooks.ts
  (useWorkspace, useWorkspaceFields, useWorkspaceStructure,
  useWorkspaceKeys, useResolveWorkspaceIdByCwd,
  useWorkspaceStatusesForBadges, useWorkspaceExecutionAuthority,
  useRecommendedProjectPaths, useHasWorkspaces). These are the only
  place to subscribe to workspaces.
- 15 greedy subscribers migrated to the hook surface. The sidebar is now
  driven by useWorkspaceStructure for identity/ordering; each row
  hydrates its own descriptor via useWorkspaceFields, so a workspace
  update re-renders only its row. Archive-redirect callbacks switched to
  event-time useSessionStore.getState().
- Deleted dead code: use-session-directory.ts, workspace-fetch-debug.ts,
  and the unused SidebarProjectEntry aggregates (activeCount,
  totalWorkspaces, aggregated statusBucket).

No user-visible behavior change. Targeted tests green (79 tests across
host-runtime, session-store, session-store-hooks, sidebar list, sidebar
row model, sidebar shortcuts, workspace source of truth).
2026-04-19 20:19:45 +07:00
Mohamed Boudra
8991d34f78 fix(app): allow collapsing the parent folder of a selected file (#500)
The file explorer had a useEffect that re-enforced expansion of every
ancestor of `selectedEntryPath` whenever `expandedPaths` changed. As a
result, the moment a user collapsed the parent folder of a file they
had just opened, the effect re-added that folder to the expanded set
and the folder appeared stuck open.

Selection and expansion are orthogonal: clicking a file should not
dictate that its parent folder stays open forever. There is also no
current caller that sets `selectedEntryPath` from outside the tree, so
the reveal-on-external-selection use case the effect was designed for
is unused. Delete the effect and its two now-dead helpers. If a future
"Reveal in Explorer" action is introduced, it can expand ancestors at
the call site.

Adds an E2E regression test that reproduces the original scenario:
expand a folder, open an image, collapse the parent folder, assert
children are hidden. Also asserts an unrelated sibling folder still
expands after the image is open, guarding against any future regression
that makes the bug global.
2026-04-19 16:49:09 +08:00
Mohamed Boudra
128d6668ae fix(server): update PR status test for new normalized fields
normalizeCheckoutPrStatusPayload always emits the full wire shape now
(number, repoOwner, repoName, isDraft, checks, checksStatus,
reviewDecision) — the workspace-git-watch test's toEqual assertion
still had the pre-PR-pane shape and was failing.

Update the expected object to match the actual wire contract.
2026-04-19 15:11:37 +07:00
Mohamed Boudra
d9d6509880 fix(test): resolve Metro .web.ts variants in vitest
message-input.tsx imports ./composer-height-mirror, which only exists
as .web.ts / .native.ts / .d.ts. Metro picks the right variant at build
time, but vitest was using Vite's default extension list and failing to
resolve the import — breaking app tests in CI.

Prepend `.web.*` variants to `resolve.extensions` in both the root and
app vitest configs so test runs (which already alias react-native →
react-native-web) pick the web implementation, matching what Metro
does for the web bundle.
2026-04-19 15:11:37 +07:00
Mohamed Boudra
2d9cbb0453 fix(server): resolve remote-only branches in switcher checkout
Branch switcher listed remote-only branches as if they were local, then
threw "Branch not found" when clicked because the checkout path only
verified `refs/heads/<name>`. Explicit `origin/<name>` input went the
other way — verify passed, but checkout produced a detached HEAD.

Split the concerns into three layers:

- Enumerate: `listBranchSuggestions` returns provenance (`hasLocal`,
  `hasRemote`) so the wire payload no longer loses origin-only info.
  Fields are optional on `branchDetails` for backward compat.
- Resolve: new `resolveBranchCheckout` normalizes `origin/<name>` →
  `<name>`, verifies explicit `refs/heads/` and `refs/remotes/origin/`
  paths (no tag-DWIM), returns a tagged
  `{ local | remote-only | not-found }` result. Policy (local wins,
  origin fallback) lives here.
- Act: `checkoutExistingBranch` no longer does implicit DWIM. Local →
  `git checkout <name>`. Remote-only → `git checkout -b <name> --track
  origin/<name>`. Not-found → throws the existing
  `Branch not found: <name>` string. Response carries optional
  `source: "local" | "remote"`.

`validateBranch` now routes through the same resolver so both paths
agree on what a branch is.

Also fixes a related stale-base diff bug: worktrees created off
`origin/main` could show phantom "added" commits when the local `main`
lagged. `resolveBestComparisonBaseRef` is now origin-first for
diff/status. Merge still uses the "most-ahead" helper so unpublished
local commits aren't lost. `doesGitRefExist` tightened to only swallow
exit 1 (missing ref), propagating other git failures.
2026-04-19 14:26:52 +07:00
Mohamed Boudra
e373c33108 feat(app,server): add pull request pane to the workspace sidebar
Introduce a PR tab in the explorer sidebar that shows status checks,
reviews, and the merged timeline for the current branch's pull
request. Extend checkout PR status with number, draft flag, repo
identity, and per-check workflow/duration; add a new
pull_request_timeline request/response pair backed by a GraphQL
query; enrich the workspace git snapshot to carry the fields through
to the client; and extend the checkout-git-actions store so timeline
queries are invalidated alongside status when mutations land.
2026-04-19 14:26:52 +07:00