* feat(opencode): add active-turn steering via native V2 prompt
Add OpenCode support for active-turn steering (PR #3394) using the
native V2 session prompt with delivery: steer. Implements
steerActiveTurn, pending steer echo correlation for multiple steers,
prompted event handling, and definitive vs ambiguous error handling.
Updates docs and SDK to 1.18.18 for typed V2 access.
* fix(opencode): use V1 prompt for steer so model sees it
V2 prompt was admitted to a separate inbox not visible to the V1
processor, so "How old is bigbird?" was shown inline but never in
the LLM context. Switch steer to session/prompt_async (V1) which
queues while busy and is included in the next LLM call's history.
Update tests to expect V1 and keep the timeline grouping.
* fix(opencode): honor steering permission contract
Admit the steer before denying permissions that block its delivery, matching the provider steering contract. Remove the abandoned V2 path and SDK upgrade because active-turn delivery uses the existing prompt endpoint.
* chore(opencode): preserve SDK patch metadata
---------
Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com>
* Add automatic plus branch maintenance workflow
* Build plus artifacts for desktop and CLI/server
* Document and summarize plus artifact workflow
* Document Apple signing and pin plus workflow actions
* Disable Linux plus desktop artifact
* Publish plus CLI packages to GitHub Packages
* Fix GitHub Packages publish paths
* Fix plus mise install summary package name
* Disable macOS x64 plus desktop artifact
* Tag plus npm packages as latest for mise
* fix(worktrees): respect selected local base ref
* chore(ci): remove fork-only plus workflow
* fix(worktrees): preserve exact branch picker refs
---------
Co-authored-by: Matt Cowger <1929548+mcowger@users.noreply.github.com>
* 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(server): patch OpenCode SDK unhandled rejection on stream abort
The SDK's SSE abort handler calls reader.cancel() without handling
its rejection. When Paseo aborts the event stream during normal
session close, that promise can reject and crash the daemon with an
unhandled rejection outside any Paseo-owned code path.
Patches both copies the SDK ships (dist/gen and dist/v2/gen, the
latter being what Paseo actually imports). Extends
postinstall-patches.mjs to support patch-package running from a
non-root cwd, since @opencode-ai/sdk lives in packages/server's own
node_modules rather than the hoisted root.
* fix(server): stop assuming OpenCode's default agent is "build"
OpenCode users can rename or delete any agent, including the built-in
"build"/"plan" defaults. Paseo was injecting a hardcoded "build"
agent in several places whenever no mode was explicitly requested:
- The protocol manifest declared defaultModeId: "build" for opencode,
which AgentManager.normalizeConfig applied to every session
(including internal metadata-generation sessions) before any
provider-level logic ran.
- OpenCode's own normalizeOpenCodeModeId defaulted an empty/"default"
modeId to "build" rather than omitting the agent field.
- Unattended child creates (e.g. subagents spawned by an unattended
parent) forced modeId: "build" to express unattendedness, even
though that's already carried by the auto_accept feature.
Now an unset mode stays unset end-to-end: the "agent" field is
omitted from OpenCode prompt/command calls entirely, letting OpenCode
fall back to its own configured default agent instead of Paseo
guessing one that may not exist.
* fix(server): validate agent create mode on the WebSocket session path
resolveAndValidateCreateAgentMode already rejects modes unknown to a
provider's discovered mode list, but it was only wired into the MCP
create path. App-created agents (create_agent_request) skipped it
entirely, so a client's remembered mode preference — which can go
stale when a user renames or deletes OpenCode agents — sailed through
to the provider and failed mid-turn with an opaque error instead of a
clear rejection at creation time.
resolveSessionCreateAgent now calls
providerSnapshotManager.resolveCreateConfig, matching the MCP path,
so an invalid mode now throws 'Invalid mode ... Available modes: ...'
immediately on create.
* chore: address review feedback on create-agent and postinstall script
- Document the cleanup-ordering constraint in resolveSessionCreateAgent:
mode validation runs after buildSessionConfig (cwd isn't known until
that completes), so a thrown validation error leaves any
worktree/workspace buildSessionConfig created for the caller to clean
up. session.ts already handles this for the worktree path; the
directory-only workspace path has a pre-existing gap, not introduced
by this validation.
- Log spawn errors from patch-package in postinstall-patches.mjs
(e.g. ENOENT if it's missing from PATH) instead of failing silently.
* fix(server): don't fabricate OpenCode modes when discovery finds none
fetchModesFromClient and mergeOpenCodeModes fell back to
DEFAULT_MODES ([build, plan]) whenever OpenCode discovery returned
nothing — e.g. for a freshly-created worktree whose OpenCode server
hasn't loaded the project config yet. That fabricated list let
create-time mode validation accept a stale 'plan' preference that the
provider then rejects at prompt time (Agent not found: 'plan').
Return an empty list instead: OpenCode users can rename or delete any
agent, so any hardcoded fallback risks validating a mode that doesn't
exist. DEFAULT_MODES is retained only for description enrichment and
sort ordering.
* fix(app): reconcile stale selected mode against discovered modes on create
The mode picker displays modeOptions[0] when the stored modeId isn't
in the discovered list (e.g. a globally-remembered 'plan' that a
workspace's OpenCode config no longer defines), but the create request
still submitted the raw stored modeId. Result: UI showed 'Build' while
the request sent 'plan', which the daemon then rejected.
Reconcile the selected mode against the discovered mode ids when
building the create config (both the workspace draft composer and the
workspace-setup dialog), so the submitted mode matches what the picker
shows — falling back to the first available mode when the stored one is
absent. Mirrors the existing resolveEffectiveModel reconciliation for
models.
* test(server): fix opencode mode tests after fallback change + rebase
- Replace 'available modes include build and plan' (which relied on the
removed [build, plan] discovery-failure fallback) with two tests:
one asserting discovered agents map to modes, one asserting empty
discovery yields no fabricated modes.
- Restore messageId fields in the four provider-subagent timeline
assertions. These were accidentally dropped during rebase conflict
resolution; the #2013 subagent code legitimately emits messageId, so
the expectations must include it.
* test(app): fix e2e seed helper using invalid opencode mode
createIdleAgent seeded an OpenCode agent with modeId
'bypassPermissions' — a Claude mode OpenCode never had. This worked
before only because the session create path silently coerced unknown
modes to 'build'. Now that create-time mode validation rejects modes
the provider doesn't define, use 'build' + auto_accept (OpenCode's
unattended full-access equivalent), matching the rewind-flow helper.
Fixes the e2e failures across archive-tab, command-center-host,
settings-toggle-tab-regression, workspace-agent-tab-rename,
workspace-pane-remount, workspace-navigation-regression, and
worktree-restore specs, which all seed via this helper.
* 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>
2026-07-13 11:15:40 +00:00
Matt CowgerGitHubgreptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
* fix(opencode): trust discovered modes instead of always injecting defaults
When OpenCode reports its available agents, respect that list exactly
rather than seeding from DEFAULT_MODES first. This means users who have
intentionally disabled modes (e.g. Plan) in their OpenCode config will
no longer see those modes surfaced in Paseo.
DEFAULT_MODES is still used as a fallback when discovery returns nothing
(e.g. OpenCode unreachable or no agents configured).
* test(opencode): update mode discovery expectations
* test(opencode): expect discovered custom modes only
* fix: daemon warns instead of crashing on missing OpenAI speech credentials
validateOpenAiCredentialRequirements was throwing an error when
OpenAI speech providers were configured without credentials,
causing the daemon to crash before it could start serving health
checks. Changed to log a warning instead — the daemon starts
successfully and reports speech services as unavailable.
Closes#1367
* chore: address Greptile review feedback
- Remove duplicate warning in initializeOpenAiSpeechServices when
all credentials are missing (already warned by validate)
- Strengthen test assertions: check getListenTarget() after start
- Wrap daemon start/stop in try/finally for proper cleanup on failure
* Add configurable service proxy
* Fix service proxy URL used when opening scripts with a public base URL
When a public proxy URL was configured, the View link was falling through
to direct connection logic and opening the wrong URL. Move the public URL
early-return before connection-type checks, and remove the now-dead
duplicate check further down.
* Add service proxy documentation
Covers config options, URL generation format, wildcard DNS setup,
and reverse proxy Host header requirements.
* Cap combined public service label and document hostname format
* Address service proxy review feedback
* Add configurable worktree root
Allow new Paseo worktrees to be created under a custom worktrees.root from config.json while preserving the existing PASEO_HOME/worktrees default. Thread the resolved root through create/list/archive/ownership flows, MCP/session paths, checkout metadata, schema, docs, and targeted tests.
* Address worktree root review feedback
Use the resolved Paseo worktree base when a custom PASEO_HOME is provided, and remove an unused worktreesRoot dependency from worktree list handling.
* Fix checkout worktree path test on Windows
Use platform-native paths in the custom PASEO_HOME regression test so Windows CI compares against the same resolved root shape as production code.
* Clarify optional worktrees config docs
---------
Co-authored-by: Mohamed Boudra <boudra.moha@gmail.com>