* fix(workspaces): start pasted pull requests from their branch
Recognized pull request links now select their branch directly instead of
waiting for a separate confirmation. Ensure single-branch clones also record
the fetched branch so the new worktree can track it.
* fix(workspaces): keep pasted PR checkout target-safe
* fix(workspaces): make pasted PR resolution deterministic
* fix(workspaces): preserve explicit checkout selection
A recognized pull request selects itself only when its attachment is added. Once the user chooses a branch, later composer edits must not derive checkout state from existing attachments.
* fix(composer): ignore stale pull request lookups
A lookup may finish after the workspace target changes. Only apply its attachment and selection event when the host, working directory, client, and remote still match the target that started it.
* fix(workspaces): make checkout choices authoritative
Arm automatic pull request selection only when a new PR link is detected. An explicit picker choice cancels that pending selection, existing draft attachments never infer checkout state, and target changes suppress carried-over lookups.
* fix(workspaces): stabilize pull request auto-selection
Keep the first PR selected when one edit contains several links, and accept a completed lookup when only the transport client changed for the same host and checkout.
* fix(composer): release removed pull request lookups
Release each auto-attach invocation when its composer state is abandoned, while continuing to discard any stale response.
Expected rev-parse failures were logged like unexpected discovery errors after Git detection became fail-open. Keep ordinary non-Git results silent while retaining diagnostics for genuine process failures.
Keep service route choices independent of daemon transport and persist the selected route per host. Use the shared web overlay stack so menus, tooltips, and toasts layer predictably.
Track proxy route changes from the Git branch rather than the workspace title to avoid transient service health changes.
* fix: emit project.update on rename so empty projects update
The rename handler only re-emitted workspace descriptors, which left
empty projects (no workspaces yet) showing the stale name on the client.
* test(projects): cover renaming empty projects
---------
Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com>
* feat(pi): add 'max' thinking level support
Pi recently introduced a new 'max' thinking level beyond 'xhigh'.
This adds it to the type union, the UI options array, and the
runtime type guard so Paseo users can select it.
Changes:
- rpc-types.ts: add 'max' to PiThinkingLevel union
- agent.ts: add max entry to PI_THINKING_OPTIONS
- agent.ts: add 'max' to isPiThinkingLevel guard
* fix(pi): clarify xhigh description after adding max level
xhigh's 'Maximum reasoning' is now misleading since max is the true
maximum. Changed to 'Very deep reasoning' per review feedback.
* feat(providers): allow turning thinking off
Expose Off only for models that support disabled thinking while preserving Low as the default.
* fix(providers): reset unsupported thinking on model change
Keep the selected thinking option only when the new model advertises it; otherwise use that model's default and persist the runtime change.
* fix(providers): isolate custom model capabilities
Use strict manifest identity when reconciling thinking options so provider-prefixed custom models cannot inherit capabilities they do not advertise.
* fix(providers): clear thinking with default model
* fix(providers): validate disabled thinking support
* fix(providers): validate initial thinking config
* refactor(providers): centralize thinking capability
* fix(server): order config mutation events
* feat(files): edit workspace files on web
Keep source buffers synchronized with host file changes and require an explicit overwrite or reload when revisions diverge.
* feat(panels): surface and protect modified tabs
Expose tooltip and modification state through the generic panel boundary so tabs can show stable metadata and guard every close route consistently.
* fix(tests): use portable fake timeout handle
* fix(files): harden editor conflict handling
Preserve modified panel state across tab eviction, use precise revisions for optimistic writes, coalesce concurrent file watchers, and localize the editor interface.
* fix(files): close editor concurrency gaps
Coalesce clean reloads, preserve subscriber identities and file permissions, suspend pending saves during close confirmation, and carry precise revisions through file reads.
* test(files): expect read revision metadata
* starr
* fix(server): honor service port allocator contracts
* fix(server): pass workspace context to port scripts
* fix(server): cancel released service port plans
* test(server): support Windows port allocator fixtures
* docs(worktrees): clarify shell-less portScript execution
* fix(opencode): surface autonomous parent turns
OpenCode extensions can prompt an idle session without Paseo owning an active turn. Adopt exact-session activity while keeping child permissions unbound.
* refactor(opencode): centralize session ownership guard
Keep autonomous turn ownership in the shared exact-session check so all qualifying events use one source of truth.
* fix(opencode): serialize autonomous handoff
Abort and await provider-side autonomous work before starting a direct Paseo prompt so late output cannot leak into the new turn.
* fix(opencode): reject stale interrupted activity
Keep late output from an interrupted Paseo turn out of autonomous admission until a real user message establishes the next run.
* fix(opencode): fence interrupted turn events
Use provider abort settlement and terminal events as the interrupted-turn boundary so delayed canceled user messages cannot resurrect old work.
* fix(opencode): recover from failed aborts
* fix(opencode): preserve timed-out abort fence
* refactor(opencode): model provider turn lifecycle
* fix(opencode): recover stop fence after stream loss
Canonical provider message IDs and optimistic client IDs occupy different namespaces. Preserve both identities for deterministic reconciliation while retaining a dated content fallback for older daemon timelines.
Cached focused state was leaking into the sidebar before authoritative workspace hydration, while catch-up limits counted raw events instead of projected entries. Keep the focused cache fast, gate directory presentation on hydration, and preserve canonical cursors while paging projected history.
* fix: resume collected agents before pane actions
* fix(server): keep archived agents closed during pane actions
An archive could win while a collected agent was resuming, then lose when the provider runtime registered. Recheck persisted archive state after registration and close the resumed runtime before any mutation runs.
* fix(server): fence archived agents after shared resume
Protected pane actions could join a resume started by an ordinary loader and skip the archive fence. Recheck persisted lifecycle state for every protected caller so archive always wins before mutation.
* fix(server): release resources held by idle agents
Keep unarchived agents resumable while closing their provider runtimes after two minutes. Active agent schedules keep runtimes resident.
* fix(server): preserve resumable agent state
* fix(server): resume agents when listing commands
* fix(server): preserve collected agent interactions
Pi compact is a blocking LLM summarization job that often exceeds the
default 30s control-plane timeout on long sessions, causing a false UI
error while the real compact continues. Wait for the RPC response,
process exit, or session close instead.
Also cover the no-timeout lifecycle: null timeout still rejects on
close, and compact waits past 30s for a late success response.
Closes#1946
* fix(projects): allow non-git folders across mounts
Treat failed Git worktree discovery as non-Git so ordinary directories remain addable. Preserve the underlying diagnostic as a structured warning instead of failing project creation.
* fix(projects): preserve discovery warnings
Propagate checkout context through the remaining worktree discovery calls so fail-open classification retains its structured warning.
* fix(projects): detect when projects become Git repositories
Project identity was coupled to Git placement, while non-Git roots were dropped by session-scoped observation. Keep identity tied to the selected root and observe Git transitions daemon-wide so empty projects update without rehoming workspaces.
* fix(projects): preserve metadata across Git read failures
Refresh archived workspace facts before persistence and treat only confirmed non-repositories as non-Git so transient failures cannot rewrite stored project metadata.
* fix(projects): close project update races
* fix(projects): refresh checkout metadata when reopening folders
Persist worktree ownership separately from workspace kind and gate exact-root project creation on stable host identity. Refresh active and archived records so missed Git transitions cannot return stale checkout descriptors.
* test(projects): accept Windows aliases for repaired roots
* test(server): retry transient Windows cleanup locks
* fix(projects): propagate project metadata refreshes
Project-only Git transitions now fan out workspace updates for legacy clients. Explicit project creation refreshes stored kind, and equivalent cwd spellings reuse existing workspace records.
* fix(projects): refresh worktree source project kind
* fix(projects): preserve exact-folder runtime isolation
* fix(projects): preserve exact cwd across worktree lifecycle
* fix(projects): harden exact-folder worktree flows
* fix(projects): derive exact cwd from matched path identity
* fix(projects): preserve nested worktree lifecycle
* refactor(projects): centralize workspace placement
* test(e2e): verify isolated server ports
* fix(projects): preserve placement reshape compatibility
* fix(projects): validate created worktree placement
* fix(projects): preserve placement through workspace lifecycle
Archive and recovery were rediscovering or guessing checkout roots instead of consuming the persisted workspace placement. Make the record authoritative for exact cwd, backing worktree, and source repository, and classify stale paths before Git reconciliation.
* fix(worktrees): preserve source checkout root
Convert Git's common administrative directory back to the source checkout root when legacy archive placement is reconstructed.
* fix(worktrees): compare filesystem identities
Resolve discovered worktrees and teardown locations through the shared realpath-aware matcher so Windows short and long path spellings cannot split placement identity.
* fix(worktrees): centralize path containment
Route worktree ownership, listing, resolution, and deletion through the realpath-aware containment primitive so Windows path aliases cannot be filtered by an earlier raw prefix check.
* fix(worktrees): remove duplicate ownership discovery
* test(e2e): isolate daemon restart ownership
* fix(worktrees): make lifecycle operations transactional
* fix(workspaces): share git watches by cwd
* test(worktrees): make teardown proof portable
* fix(sync): integrate project updates with directory owner
* fix(workspaces): close reconciliation edge cases
* refactor(sync): remove duplicate project reconciliation
Keep workspace and project deltas behind the host directory transaction, with owner-boundary coverage for snapshot replay and queued full reconciliation.
* fix(sync): buffer project updates before hydration
Start the workspace transaction with the online connection epoch so project broadcasts cannot publish a partial directory before the authoritative snapshot commits.
* feat(sync): keep live data scoped and current
Only viewed chats receive live timeline rows, while directory state now uses one subscribed bootstrap followed by ordered deltas. Legacy clients and daemons retain their existing behavior through centralized compatibility gates.
* fix(sync): preserve selective delivery boundaries
Keep selective timeline capability app-owned, union viewed sets across shared sockets, and reconcile directory side effects from accepted state. Visibility and archive suppression now follow their existing authoritative boundaries.
* test(app): align browser fixtures with runtime contracts
* fix(sync): preserve mixed-client delivery guarantees
* fix(sync): finish paged history before advancing
* fix(sync): replay live deltas after refresh failures
* test(server): model socket capability lookup
* test(app): use platform shortcut for split-pane coverage
* fix(app): keep hidden timelines dormant
* test(app): normalize split-pane shortcut setup
* fix(app): preserve sync state across retries
* fix(app): preserve background sync state across races
* fix directory bootstrap reconciliation edge cases
* fix selective timeline compatibility races
* fix superseded directory sync races
* fix(sync): centralize directory replica ordering
Own agent and workspace refresh transactions in HostRuntime so reconnect epochs, buffered updates, and lifecycle invalidation share one ordering boundary. Route timeline metadata and mixed-capability stream delivery through their authoritative runtime sources.
* fix(app): keep timeline requests runtime-scoped
* fix(app): close directory bootstrap races
* refactor(forge): forge-neutral foundation (GitHub-only)
Decouple git-hosting from GitHub behind a neutral abstraction (issue #1616), GitHub-only for now; existing GitHub behaviour is unchanged.
- Forge manifest, neutral ForgeService contract, forge registry + resolver, and a client forge-module registry.
- GitHub code renamed to the neutral shape; PR/Issue attachment wording preserved.
- forge.search.response enums parse tolerantly (unknown kind/auth state degrade instead of breaking the client).
- createPullRequest reports typed CLI/auth errors instead of a generic message.
- forge-resolver host/remote caches are LRU-bounded.
- Forge host trust is explicit: only a known cloud host or a CLI-authenticated host is ever talked to; an unauthenticated GitHub Enterprise host fails resolution instead of routing to github.com.
- Docs: forge-providers guide, glossary and i18n forge-copy conventions, architecture and rpc-namespacing terminology.
- Vitest React Native mocks (unistyles, svg, linking, lucide) consolidated into shared aliased test-stubs.
* feat(forge): GitLab adapter, forge-aware UI, pipelines and approvals
GitLab adapter over the glab CLI on the neutral contracts: MR status, forge-aware UI, pipeline tree, and N-of-M approvals.
- threadIsResolved is part of the neutral timeline item.
- Pipeline load failures show an error instead of an empty section.
- Manual pipeline jobs render as pending.
- Fork/detached MR head pipelines are fetched by MR iid (glab ci get --merge-request).
* feat(forge): Gitea family adapter (Gitea, Forgejo, Codeberg)
One adapter over the tea CLI serving Gitea, Forgejo, and Codeberg on the neutral contracts.
- CI status aggregates commit statuses and Actions runs together.
- Gitea's terminal "warning" state maps to failure on server and client.
- Gitea Actions check details are reachable from the PR pane by workflowRunId.
* refactor(forge): localize compatibility handling
* test(forge): expect normalized GitLab facts
---------
Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com>
Pi and OMP share only the JSONL child-process transport while retaining provider-owned launch, RPC, runtime, session, history, and permission behavior. Removes captured fixtures in favor of typed harnesses and real-provider coverage.
Closes#2006Closes#2060
ACP setup and out-of-prompt notifications do not define a turn lifecycle. Treating them as autonomous turns could complete the active run while its prompt was still streaming.
* fix(sessions): reimport archived sessions in their workspace
Archived agent records were treated as active imports, hiding their provider sessions permanently. Workspace-originated imports also discarded their workspace identity and created a duplicate workspace.
* fix(sessions): validate archived session restores
Restore archived imports under their existing Paseo agent identity, reject stale workspace ownership, and gate workspace targeting when the host cannot honor it.
* fix(sessions): roll back failed archived imports
If provider resume or history hydration fails, close any partial runtime, re-archive the provider session, and restore the original stored agent record.
* fix(sessions): validate restored import ownership
* fix(sessions): serialize concurrent restores
* fix(sessions): harden archived import recovery
* fix(sessions): validate archived import placement
* refactor(sessions): centralize provider session imports
Keep workspace placement rollback and stored-agent activation behind their existing owners so Session remains the wire boundary.
* feat(app): add fileView preference for changes panel
* feat(app): add buildDiffTree util for changed-files tree
* feat(app): add changed-files tree directory row
* feat(app): changed-files tree view mode in changes panel (#117)
* feat(protocol): add checkout.commits.list RPC + commitsList feature flag
* feat(server): list branch commits ahead of base with on-remote flags
* feat(server): handle checkout.commits.list RPC and advertise capability
* feat(client): checkout.commits.list method + useCommitsQuery hook
* feat(app): per-commit inline view with local-vs-remote markers (#117)
* feat(protocol,server): per-commit file diff RPC (checkout.commits.file_diff)
* feat(app): open per-commit file diff on click (#117)
* refactor: surface baseRef + commits loading/error, drop dead depth field
* fix(app): flip commit local/remote dot — local hollow, remote filled
* feat(app): list/tree view for expanded commit file list (#117)
* fix(app): syntax-highlight per-commit file diff to match Changes view
* feat(app): draggable resize between commits and diff sections
* refactor(app): dedupe wrap-text helpers into diff-highlighted-text
* fix(app): clean up commits resize drag on unmount + a11y label
* fix(app): collapse commits section by default
* fix(app): render per-commit file diff with the shared Changes line renderer
* perf(app): memoize shared diff line row; drop redundant DiffLineView wrapper
* refactor(app): extract shared DiffFileBody; render commit file diff through it
* fix(app): hide inline-comment affordance in per-commit diffs (no reviewActions)
* feat(app): move commits to a resizable bottom drawer in the Changes panel
* feat(review): commitSha scoping for per-commit review drafts + attachment
* feat(app): per-commit inline comments wired through to the composer (#117)
* refactor(app): own commit file-diff open state in CommitFileList (drop reset effect)
* refactor(app): colocate diff-render cluster under git/diff-file-body/
* feat(app): add diff tab target kind (working/commit diff tabs)
* feat(app): useDiffFiles hook unifying working + commit diff targets
* feat(app): diff tab panel rendering working/commit diffs
* feat(app): open a commit diff tab on commit click; drop per-commit drawer/file list
* feat(app): open/scroll working diff tab on changed-file click
* fix(app): keep commit diff tabs ephemeral; align working diff whitespace
* feat(app): collapsible file sections in the diff tab, collapsed by default
* feat(app): make the on-remote commit dot more subtle
Dims the filled green remote dot (row + legend) to ~0.55 opacity so the
local-only ring stays the state that draws the eye.
* Reshape commit diffs around the existing Changes view
* Fix diff tab migration complexity after rebase
* Address diff tab review findings
* Clean up diff tab review interfaces
* Collapse commit diffs into the existing view
* Load commits when expanded
---------
Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com>
* fix(app): restore missing workspaces from History
Workspace and agent archival are separate lifecycles. Carry restore intent from History so closed agents can reopen archived workspaces without changing ordinary navigation.
* fix(app): wait for workspace hydration before restore
* fix(app): preserve History agent unarchive
* fix(app): reopen archived History agents outside active directory
History entries are not merged into the active session maps. Carry the row archive state through explicit restore intent so live workspaces still reopen without broadening ordinary navigation.
* fix(app): ignore stale History archive state for active agents
A cached History row can outlive a successful reopen. When the workspace exists, live session state now wins so an active agent is not interrupted by another refresh.
* fix(app): reopen every selected archived History agent
History entries without workspace IDs returned before restoration, and a second archived agent sharing an in-flight workspace restore was dropped. Preserve both agent-only and deferred reopen intent.
* fix(app): require explicit workspace recovery
* fix: preserve workspace recovery contracts
* fix: preserve workspace recovery compatibility
* fix: preserve recovered workspace session state
* fix: preserve terminal navigation timing
* fix(server): preserve successful workspace recovery
* fix: preserve workspace recovery intent
* feat(providers): remove custom providers from settings
Add a destructive removal flow so mistaken custom providers can be deleted from config.json instead of only disabled.
* test(app): cover provider removal with e2e
Move provider removal coverage out of mocked component tests and into the real Settings flow.
* fix(providers): keep removal live after config updates
* fix(settings): show daemon update failures
React Native web ignores Alert.alert, so failed remote updates reset to an enabled button without any user-visible explanation. Keep updater progress and failure as explicit rendered state, including the daemon's error, and cover the real browser-to-daemon failure path.
* test(settings): harden daemon update regression
* fix(settings): disable Desktop-managed daemon updates
Desktop-bundled daemons advertised npm self-update even though the install-origin checks always rejected it. Report Desktop ownership to clients, render actionable guidance, and refuse stale requests before touching npm.
Adding or cloning a project now registers it and opens workspace setup
instead of creating a workspace implicitly. Keep Add Project independently
mounted from Search so closing one cannot control the other.
* fix(server): create autonomous turns for spontaneous ACP session updates
When an ACP-based provider handles background-agent completion
notifications, the resulting spontaneous session/update messages have no
active foreground turn to attach to. Mirror the Claude provider's
autonomous-turn mechanism so these updates are recorded in Paseo's
timeline.
- Start an autonomous turn when a sessionUpdate arrives with no active
foreground turn
- Tag timeline events with the autonomous turn id
- Complete the autonomous turn after a timeout, or before a new
foreground turn starts
* Fix ACP autonomous event scoping
---------
Co-authored-by: zab <b13022010527@gmail.com>
Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com>
* fix(chat): allow failed turns to be forked
Failed turns can end in Paseo-generated timeline items without provider
message IDs. Anchor forks to canonical timeline positions while retaining
legacy boundaries for compatibility.
Place the fork summary before the new prompt and delimit it as structured
chat history.
* fix(chat): tighten fork boundary handling
* feat(subagents): archive finished children and show native names
Keep native provider sessions intact while letting users clear completed children from the track. Persist dismissed provider child IDs so history replay does not restore them.
* fix(subagents): cover persistence and naming edge cases
* fix(subagents): preserve active descendants and native names
* fix(subagents): retain dismissed timelines and trim paths
* fix(subagents): retain history across hydration
* test(subagents): expect normalized native descriptions
* fix(subagents): separate hidden rows from retained history
* fix(subagents): preserve restored hidden tabs safely
* fix(subagents): integrate archive with run state
* test(codex): expect normalized child name
* fix(subagents): retain dismissed tabs on reload
* fix(subagents): hide finished native agents locally
Keep the header action presentation-only so it does not mutate agent lifecycle or expand the runtime protocol.
* fix(subagents): humanize native agent names
* fix(subagents): preserve names in Codex history
* fix(subagents): retain hidden rows across reloads
* fix(server): render image paths with spaces
Raw spaces in local Markdown image destinations made the renderer treat provider images as text. Emit encoded file URIs for spaced paths so the client parses and resolves them as images.
* fix(server): encode all absolute image paths
Provider image paths without spaces could still contain URI-significant characters such as fragment or query markers. Route every absolute local path through the encoded file URI boundary.
* fix(server): encode network image paths
Windows network-share paths bypassed the absolute local path handling. Normalize UNC and extended UNC paths before encoding them as file URIs.
* fix(app): preserve network image paths
Host-based file URIs were decoded as relative paths. Restore the UNC prefix so provider images on network shares resolve through the file RPC correctly.
* fix(server): preserve double-slash POSIX image paths
Classify only backslash-prefixed paths as Windows network paths so POSIX double-leading-slash paths retain their filesystem semantics.
* fix(server): prevent hidden Codex subagents and stuck turns
Codex can announce native children only through its mirrored lifecycle stream, while rejected interrupts previously looked like successful local cancellation. Preserve those child announcements and keep manager state active until the provider acknowledges cancellation.
* fix(server): block actions after rejected cancellation
A provider can accept a turn before publishing the turn ID needed to interrupt it. Keep that interval non-cancelable, and prevent reload, replacement, or rewind from proceeding without an acknowledged cancellation.
* fix(server): surface rejected agent cancellations
Replacement prompts and Stop requests could appear accepted after the provider kept ownership of the active turn. Complete replacement cancellation before detaching the stream, and return cancellation failures through the client response.
* fix(server): handle turn completion during cancellation
* fix: finish cancellation lifecycle handling
* fix(server): close remaining cancellation races
* fix(server): settle autonomous cancellations
* fix: honor cancellation failures at call sites
* refactor(server): centralize agent run state
* fix(server): keep pending runs isolated from stale events
* fix: surface remaining cancellation failures
* fix(server): narrow cancellation error handling
* fix(pi): complete locally handled prompts
Slash commands the Pi CLI handles without starting a model turn previously
left the Paseo turn hanging until interrupt. Parse the optional
agentInvoked correlation from prompt acknowledgements, surface
command_output/notify output as timeline content, and complete the turn
locally when no agent turn will start. Older Pi binaries without the
correlation are detected via a getState compatibility probe.
* review: guard command output without an active turn, simplify delegates
- Drop late-arriving command_output when no turn is active instead of
emitting an orphaned timeline item with turnId undefined
- Remove redundant 'text' in event check (type is already narrowed)
- Inline recordNoTurnNotification delegate
* refactor(pi): consolidate local prompt state
---------
Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com>