-
released this
2026-06-17 16:23:15 +00:00 | 316 commits to main since this release- fix(code-mode): make packaged code mode work via on-demand engine provisioning
Packaged builds could never run code mode: the Claude/Codex ACP adapters are
spawned as separatenode <entry>processes resolved at runtime, but esbuild
can't inline a dynamic spawn target and Forge strips the workspace node_modules,
so every release threwCannot find module '@agentclientprotocol/...'. Dev
worked only because of the pnpm symlink.Rather than bundle the ~400 MB of native engines (one claude + one codex binary
per OS), provision them on demand:- forge.config.cjs: stage the two ACP adapters + their JS dependency closure into
.package/acp/node_modules (npm-style nested layout, native engines skipped),
exempt .package from the node_modules ignore rule, and only sign/notarize when
APPLE_ID is set so unsigned local/CI builds can package. - agents.ts: resolve the adapter from the staged location first (node_modules
fallback in dev); provision the pinned engine and point the adapter at it via
CLAUDE_CODE_EXECUTABLE / CODEX_PATH. No dependence on a user's global install. - engine-provisioner.ts: ensureEngine() downloads the per-platform engine package
from npm AT THE EXACT VERSION THE ADAPTER WAS BUILT AGAINST, verifies its sha512
integrity, extracts atomically into ~/.rowboat/engines///, and
caches it. Version-pinning keeps the ACP handshake compatible. - engine-manifest.ts + scripts/gen-engine-manifest.mjs: committed manifest of
tarball URLs + integrity for all platforms, regenerated from the adapters'
pinned versions on a bump.
Verified on macOS arm64: both engines provision and run, and both adapters
complete the ACP initialize handshake from the packaged .app against the
provisioned engines. Installer drops from ~790 MB to 390 MB.- feat(code-mode): explicit per-agent Enable in Settings; no silent chat download
Code mode now requires the user to explicitly enable an agent before use, instead
of silently downloading a ~200 MB engine on the first chat message.- Settings → Code Mode: each agent shows "Not enabled" + an Enable button that
downloads its engine with a live progress indicator (download % → verify →
install), then flips to "Engine ready". Driven by a new codeMode:provisionEngine
IPC call + a codeMode:engineProgress push channel. The section now states the
prerequisite explicitly: the agent must be installed (Enable) and logged in
(claude login / codex login — code mode reuses that saved credential). - Chat path no longer auto-downloads: getProvisionedEnginePath() returns the
enabled engine or throws a clear "enable it in Settings → Code Mode" error, so
there's never a surprise mid-conversation download. getAgentLaunchSpec is sync
again. - Agent status:
installednow means "engine provisioned" (downloaded), driving
the Enable/Ready state; the new-session dialog shows "Enable in Settings" and
disables un-enabled agents. Dropped the dead PATH-probing for a global CLI.
Verified: empty cache -> status installed=false and the chat path throws the
enable-in-Settings error (no download); core, renderer, and main typecheck/build;
no new lint errors.-
fix(code-mode): show only percentage during engine download in Settings
-
feat(code-mode): prune superseded engine versions after install
After a successful provision, remove any other version dirs (and their .meta) for
that agent so old ~200 MB engines don't accumulate across version bumps. Best-effort;
never fails a good install. Verified: a planted stale version dir + meta are both
removed after provisioning the current version.- fix(code-mode): keep showing engine download % after reopening Settings
Provisioning state lived in the row component, which unmounts when the Settings
dialog closes — so reopening mid-download showed the Enable button again even though
the download was still running in the main process. Move provisioning state to a
module-level store with one persistent listener on codeMode:engineProgress, so a row
remounting (dialog reopened) reflects the live % and resolves to Ready on completion.- fix(code-mode): flip Enable row straight to Ready after install (no Enable flash)
On successful provision the in-flight flag was cleared before the async status
refresh completed, so the row briefly (or until reopen) showed the Enable button
again. Await the status refresh before clearing the flag so it transitions directly
to Ready.- fix(code-mode): optimistically show Ready right after Enable completes
Awaiting the status refresh wasn't enough — setStatus re-renders the parent
separately from the row, leaving a window where the in-flight flag was cleared but
the status prop was stale, so the row flashed/stuck on the Enable button until
reopen. Track just-enabled agents in a module-level set and treat them as installed
immediately; loadStatus still syncs the real status in the background.- fix(code-mode): graft login-shell PATH + add startup deadline
#1 (the gh/git "command not found" in packaged builds): GUI/Finder launches inherit
launchd's stripped PATH (/usr/bin:/bin:...), so tools the engine spawns — gh, git,
rg, bash — fail even though they work from a terminal (e.g. Homebrew's
/opt/homebrew/bin/gh). Probe the user's login-shell PATH and graft it onto the
engine's env before spawn (shell-env.ts; no-op on Windows / probe failure).#2: add a 60s startup deadline (initialize / session create+load) so a wedged engine
fails with a clear, stderr-enriched error instead of an infinite "(pending...)".
Overridable via ROWBOAT_ACP_STARTUP_TIMEOUT_MS. Manager now disposes the client on
startup failure so the spawned adapter doesn't leak.Verified: getAgentLaunchSpec's env.PATH now includes /opt/homebrew/bin (where gh
lives); core builds; no new lint errors.- chore(code-mode): comment out signing/notarization for local builds
Revert to the explicit comment-out approach for osxSign/osxNotarize: uncomment them
(with APPLE_ID/APPLE_PASSWORD/APPLE_TEAM_ID) for a signed release build.- chore(code-mode): keep signing/notarization active in committed config
The repo's forge.config ships with osxSign/osxNotarize enabled (release-ready).
Developers comment them out locally for unsigned test builds and don't commit that.- chore: approve workspace build scripts so packaging runs non-interactively
The allowBuilds entries were left as "set this to true or false" placeholders, so
pnpm install/ the pre-build deps check aborted with ERR_PNPM_IGNORED_BUILDS and
npm run packagefailed. Set them to true (and add node-pty, used by the code-mode
embedded terminal) so build scripts are approved and packaging works without a manual
pnpm approve-builds.Downloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
0 downloads