electron-builder fetches the Electron binary and its platform tools
(notarytool, winCodeSign, nsis, squirrel, AppImage) on every run.
Cache those per-platform so repeat releases skip the re-download.
Saves ~30-90s per job, including the macOS long pole.
Key includes pnpm-lock.yaml so a bump to electron/electron-builder
invalidates stale cached binaries; restore-keys falls back to the
latest per-platform cache in between lockfile changes.
Co-authored-by: Orca <help@stably.ai>
Pi's titlebar extension emits OSC 0 titles every 80ms during agent work
(`⠋ π - cwd`, `⠙ π - cwd`, …) and a trailing idle title on `agent_end`
(`π - cwd`). Node-pty on the main side batches output every 8ms, so the
renderer frequently receives multiple title updates in a single `pty:data`
chunk.
The pty-transport's data handler used `extractLastOscTitle`, which returns
only the final OSC title in a chunk. For fast agents (e.g. Pi with a small
local model) the whole working→idle cycle often lands in one IPC payload —
the intermediate working frames were silently dropped, and the worktree
card's `detectAgentStatusFromTitle` only ever saw the idle title.
Empirically on macOS: polling `runtimePaneTitlesByTabId` 20×/0.25s during
a multi-second Pi working window showed the stored title stuck at "Pi"
throughout, while a raw `ipcRenderer.on('pty:data')` listener captured
the working frames flowing through IPC correctly. After the fix, the same
polling captures "⠋ Pi" alongside "Pi".
- Add `extractAllOscTitles` in the shared agent-detection module and feed
every OSC title in the chunk through `applyObservedTerminalTitle` in
order, so the working→idle transition reaches the store and the agent
tracker.
- Keep `extractLastOscTitle` exported for the main-process stats tracker
and orca-runtime, which only care about the most recent title.
- Pin the regression with three focused tests: per-chunk spinner frames,
dispatcher-routed end-to-end, and the exact coalesced-chunk scenario
that used to swallow the working state.
PR #1053 fixed RC→RC by switching prerelease users to electron-updater's
native github provider with allowPrerelease=true. That silently broke
RC→stable: GitHubProvider.getLatestVersion() filters the atom feed by
channel, so when the running build's channel is "rc" any stable release
(channel=null) gets skipped — trapping the user on the RC channel.
Fix: keep the generic provider and resolve the newest tag ourselves by
parsing GitHub's /releases.atom (any channel, semver-newest strictly >
current version). For prerelease users we re-pin the feed to
/releases/download/<tag>/ before each check, which handles BOTH the
RC→newer-RC case from #1053 and the RC→stable case it broke. Stable
users keep the default /releases/latest/download/ feed untouched, and
the Shift-click RC opt-in path (enableIncludePrerelease) is unchanged.
Co-authored-by: Orca <help@stably.ai>
The action refuses to run unless GITHUB_EVENT_NAME=="pull_request",
so workflow_dispatch no-ops. Backfill was completed out-of-band via
a local script calling the REST labels endpoint; this one-off
workflow is no longer useful and is being deleted.
Co-authored-by: Orca <help@stably.ai>
A manually-dispatched workflow that fans out across all open PRs and
runs the size labeler against each. This is a one-time verification
of the labeler against the existing PR set; the workflow will be
removed in a follow-up after it runs.
Co-authored-by: Orca <help@stably.ai>
Adds a GitHub Actions workflow and config that labels every PR with
size/xs..size/xl based on files changed and lines added, so reviewers
can see at a glance how big a PR is. Lock files and generated/vendored
paths are excluded, and deletions aren't counted so refactors that
remove code aren't over-penalized.
Co-authored-by: Orca <help@stably.ai>
The CLI is compiled by tsc (not bundled) and launched via
ELECTRON_RUN_AS_NODE, which bypasses Electron's asar integration. After
#1090 introduced zod for envelope validation, the packaged CLI crashed
with MODULE_NOT_FOUND because zod was inside app.asar. Add it to
asarUnpack so require() can resolve it from app.asar.unpacked/node_modules.
Follow-up tracked in #1097 to add CI smoke-testing of the packaged CLI.
Co-authored-by: Orca <help@stably.ai>
* refactor(cli): split runtime-client.ts into runtime/ subsystem
Break the 413-line src/cli/runtime-client.ts into focused modules under
src/cli/runtime/:
- types.ts — RuntimeRpcSuccess/Failure, RuntimeClientError,
RuntimeRpcFailureError
- metadata.ts — readMetadata / tryReadMetadata /
getDefaultUserDataPath
- transport.ts — sendRequest: Unix-socket newline-framed JSON with
id and runtimeId verification and timeout handling
- status.ts — getCliStatus + buildCliStatusResponse +
isProcessRunning
- launch.ts — launchOrcaApp + macOS .app-bundle resolution +
ELECTRON_RUN_AS_NODE env handling
- client.ts — RuntimeClient class, now a thin composer
- index.ts — subsystem barrel
runtime-client.ts becomes a backward-compat re-export barrel so
src/cli/index.ts and the existing tests import the same symbols from
the same path. No behavior changes.
Motivation: the file had an eslint-disable max-lines override and
mixed five concerns (envelope types, wire transport, metadata I/O,
status aggregation, cross-platform app launch). Splitting them makes
each concern independently testable and unblocks adding schema
validation at the RPC boundary.
* feat(cli): validate runtime RPC envelope with Zod at decode boundary
Add RuntimeRpcEnvelopeSchema and apply it inside sendRequest so every
response frame is validated against the id/ok/result/error/_meta shape
before the CLI hands it to the caller. The payload (`result`) is left
as unknown — the TResult generic remains the caller's responsibility —
so only the envelope itself is the contract this schema enforces.
Motivation: the CLI and the Orca main runtime are separate processes
and can drift in version (older CLI vs newer app, or vice versa during
dev HMR). A malformed or partial frame used to risk mis-typed field
access downstream; it now surfaces as a single structured
`invalid_runtime_response` error.
Behavior:
- Well-formed success and failure frames continue to decode unchanged.
- Failure frames without `_meta` are accepted (the runtime may fail
before resolving its own runtimeId).
- Valid JSON that does not match the envelope shape now rejects with
`invalid_runtime_response`, matching the existing error code for
non-JSON frames.
Tests: adds a pure schema test file
(src/cli/runtime/envelope-schema.test.ts) covering accept/reject cases.
The existing integration tests in runtime-client.test.ts continue to
pass unchanged.
Maps .astro to Monaco's html language id, matching the existing
treatment of .vue and .svelte. This gives Astro files HTML-level
coloring instead of plain text. Proper SFC-aware highlighting
(frontmatter TS, template expressions) would require a Monarch
grammar — tracked separately.
Users were tempted to click "New passkey" on the Linear Security page
instead of "New API key". Bolded key terms, spelled out the exact button
to click, and loosened the dialog header spacing.
Also swapped the disconnect button's chain-Link icon for Unlink, since
the linked-chain icon read as "connect".
Use the existing getSuggestedCreatureName helper as the fallback seed in
getWorkspaceSeedName so blank submissions get a distinct, readable name
scoped to the selected repo (respecting nestWorkspaces) instead of
colliding on the "workspace" literal.
- Show SSH icon (Globe/WifiOff) beside worktree titles in jump palette
and WorktreeCard so remote state is visible at a glance.
- Replace inline add-repo flow in NewWorkspaceComposerCard with the
existing add-repo modal for a single entry point.
- When no SSH targets are configured, let users jump straight to SSH
settings from the add-repo dialog, and disable remote path until a
target is selected.