* feat(cli): connect daemons to Hub through browser approval
Let interactive setup complete through a short-lived browser authorization while preserving --token for automation and existing integrations.
* ci: build server before CLI tests
* fix(cli): keep Hub approval polling within expiry
Bound both response headers and body consumption to the original authorization lifetime so stalled responses remain retryable without extending approval. Run the CLI test helper through Node and the resolved tsx entry for cross-platform behavior.
* fix(cli): bound Hub registration startup
Fail a stalled authorization start within a fixed timeout without retrying the non-idempotent request. Declare the response validator as a direct CLI runtime dependency.
* fix(cli): restrict Hub activation URLs
* fix(cli): harden Hub approval transport
* fix(pairing): keep terminal QR codes scannable
Prompt framing could wrap dense QR codes and alter long pairing links. Print pairing instructions directly, add the standard quiet zone, and suppress codes that cannot fit without auto-wrapping.
* fix(pairing): contain terminal QR background
* feat(desktop): open existing agents from links
Register a stable agent deep link and route it through the existing Desktop window. Add a matching CLI command that resolves the local server and activates the requested agent without creating or messaging it.
* fix(desktop): recover agent link delivery
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): 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
* feat: clone GitHub repo into a workspace
Add an end-to-end "clone a GitHub repo and register it as a Paseo
workspace" flow: a new workspace.github.clone RPC, daemon handler,
client method, CLI `paseo clone` command, and a GitHub-repo mode in
the project picker modal. Gated behind the workspaceGithubClone
server capability flag.
- protocol: workspace.github.clone request/response schemas + feature flag
- server: handleWorkspaceGithubCloneRequest, normalizeCloneRepository
- client: DaemonClient.cloneGithubWorkspace
- cli: `paseo clone <repo> --dir <path> [--protocol https|ssh]`
- app: GitHub-repo mode, clone-protocol picker, error surfacing
Review fixes:
- CLI clone now checks the workspaceGithubClone capability and fails
fast with a clear "update the host" error instead of hanging for the
full request timeout against an older daemon.
- Replace the duplicated client-side URL-detection regex (app + CLI)
with a shared isCompleteGitRemote() in @getpaseo/protocol/git-remote,
backed by parseGitRemoteLocation so clients classify remotes
identically to the daemon (fixes confusing errors for git://, ftp://,
file:// inputs).
- Add git-remote.test.ts covering the shared classifier.
* Fix GitHub clone failure handling
---------
Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com>
* Fix macOS CLI daemon relaunch path
* test(cli): mock helper existence in daemon launch test
* fix(desktop): launch packaged CLI through Helper
The packaged macOS CLI shim entered through the main app executable, so daemon supervision inherited app lifecycle behavior and surfaced Dock icons. Make Helper the required macOS CLI runtime, keep daemon relaunches on process.execPath, and cover cold bundled CLI daemon starts in release smoke.
---------
Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com>
* fix(daemon): log stop reasons and client identity
Record websocket client identity, process memory/uptime, and shutdown reasons across CLI, desktop, supervisor, and worker paths so daemon drops can be traced from the triggering client to worker termination.
* fix(daemon): keep shutdown diagnostics in sync
Test drift: supervisor and relay tests still asserted the old log text and metadata shape after shutdown diagnostics started logging structured reasons and relay connection ids. Update those assertions to the new diagnostic contract.
Also centralize client lifecycle reason normalization and derive desktop daemon stop reasons from one tuple so future changes cannot silently drift.
* fix(client): wait longer for session responses
* fix(client): default RPC waits to sixty seconds
* fix(app): preserve detached stream scroll on delayed history
Code drift: longer client RPC waits let delayed timeline responses arrive after a user scroll-away, so web stream anchoring must not reattach on transient scroll-top resets.
Restore the 15s connect deadline and leave app initialization slack above the default 60s session RPC wait.
* fix(client): keep helper waits within caller deadlines
Review fix: the 60s default session RPC wait leaked into wait previews and waitForAgentUpsert helper fetches. Bound those helper RPCs to the caller deadline or a short best-effort preview timeout, and allow small scroll ranges to reattach at bottom.
* fix(client): respect caller timeout budgets
* fix(cli): keep diagnostic probes responsive
* Refactor daemon client request options
* Preserve daemon client legacy overloads
* Serve the web client from the daemon
Keep the bundled browser UI opt-in and exclude it from desktop packaging so desktop builds do not ship a duplicate renderer.
* Escape daemon web UI bootstrap hint
* Fix bundled web UI dist path
* Remove a worktree when its last workspace is archived
Archiving is now workspace-centric: the UI always archives a workspace,
and a worktree's directory is removed only when its last referencing
workspace is archived (derived from ownership + a single reference
count). The "remove the worktree from disk?" prompt is gone; archiving
warns only when the workspace is dirty or has unpushed commits.
MCP archive_worktree and the CLI keep the explicit lower-level behavior:
archive every workspace backing the directory, then remove it.
Auto-archive-after-merge and create-agent auto-archive respect the
reference count like any other workspace archival.
The policy now lives in two modules - a server archive service and a
client archive hook - with the reference-count check in exactly one
place. The deleteWorktreeFromDisk request field is retained but ignored
for wire back-compat.
* Tidy archive-policy internals and close test gaps
Follow-up polish on the archive-policy consolidation; no behavior change.
Structure: the server archive service is renamed to reflect that it now
owns all archive policy (the file and its types no longer say "worktree"
where they mean "archive"); the client archive input derives the
workspace kind from the canonical type instead of re-listing it; the
not-found target is typed string|null instead of an empty-string
sentinel; a redundant workspace-update emit and the ambiguous
worktrees-root naming are cleaned up. Wire, SDK, and keybinding names are
deliberately left unchanged for back-compat.
Tests: re-home the archiving-state lifecycle and per-workspace snapshot
assertions; pin worktree-kind acceptance through archive_workspace, the
ignored deleteWorktreeFromDisk field, and three-workspace archive-all;
add a Playwright spec for the dirty/unpushed worktree archive flow (the
warning gates it, confirming removes the directory) and the bulk
remove-project confirm branch.
* Fix the hanging worktree-archive risk-warning e2e spec
The spec added in the previous commit hung deterministically, locally and
in CI. Two test-only bugs, no product change.
The archive click opens a synchronous window.confirm(); the spec
registered a passive dialog waiter but only dismissed the dialog after
awaiting the click, so the click never resolved (Playwright won't settle
a click while a dialog is open) - a circular wait. Answer the dialog
inline via page.once("dialog", ...) before the click resolves, matching
the proven worktree-archive spec.
The seed also committed on a never-pushed branch, so aheadOfOrigin was
null and the "1 unpushed commit" warning never appeared. Push the branch
to set its upstream before the local commit, so it reports exactly one
unpushed commit.
Verified: the spec now passes in ~6s (was a 45s timeout); both the
dismiss-gates and accept-removes paths run.