Commit graph

1751 commits

Author SHA1 Message Date
arkml
a6572689b2
Update Readme (#644) 2026-06-24 23:47:13 +05:30
gagan
6dbaa618e7
feat(onboarding): add Code Mode setup step (#643)
* feat(onboarding): add Code Mode setup step

Adds a new onboarding step (3, between Connect and Done; Completion moves
to 4) shown in both Rowboat and BYOK paths. It informs the user up front
that Code Mode needs Claude Code and/or Codex installed and signed in
locally (claude login / codex login), then offers a master 'Enable code
mode' toggle that reveals per-agent toggles.

Downloads do NOT block onboarding: on Continue, selected-but-not-yet-
installed engines are provisioned fire-and-forget in the main process,
and their live % surfaces in Settings -> Code Mode. Approval policy is
left at the default ('ask'); users adjust it later in Settings. The step
is skippable like Connect Accounts.

To make an onboarding-started download show its progress in Settings, the
module-level provisioning store (startProvisioning/useProvisioning) is
lifted out of settings-dialog.tsx into lib/code-mode-provisioning.ts and
shared by both.

* feat(onboarding): simplify Code Mode agent rows and refine copy

- Show just the agent name (Claude Code / Codex) with a toggle and a
  green check when ready; drop the per-row download/sign-in clutter
- Value-led description: use your existing Claude Code or Codex
  subscription inside Rowboat, signed in locally via the terminal
2026-06-24 17:30:34 +05:30
gagan
8b76c54295
fix(byok): decouple chat model picker from config.models (#642)
* fix(onboarding): BYOK saved entire model catalog as assistant models

testAndSaveActiveProvider persisted the provider's full fetched catalog
into config.models. That field is the user's curated assistant-model
list (rendered as one row per entry in Settings > Models), so every
available model showed up as a separate assistant-model dropdown. Seed
it with just the selected model; users add more from Settings.

* feat(byok): decouple chat model picker from config.models

BYOK config.models was doing double duty: it both seeded the in-chat
model picker AND was rendered as a per-entry dropdown stack in Settings.
That coupling forced a tradeoff between a clean Settings UI and full
model choice in chat, and baked a stale catalog snapshot into config.

Decouple them so BYOK matches the signed-in experience:
- Chat picker (signed-out) now lists the full live provider catalog from
  models:list, filtered to providers the user has a key/baseURL for, with
  the saved default model leading. No longer limited to config.models, so
  newly released models appear without re-saving.
- Settings assistant model collapses to a single default-model dropdown
  (removed the .map() stack + add/remove). config.models is now just the
  one default; save/load/delete logic is unchanged.
2026-06-24 16:33:40 +05:30
gagan
caa80f7c07
fix(onboarding): inline completion checkmark & widen indicator gap (#641)
- Remove the circular background and pulsing ring behind the completion
  checkmark; place the tick inline to the right of the "You're All Set!"
  heading
- Increase spacing between the step indicator and step content
2026-06-24 15:42:31 +05:30
gagan
aa347c9047
fix(onboarding): center step connector line & refresh welcome layout (#640)
* fix(onboarding): center step connector line with circles

The connector line was vertically centered against the circle+label
column, landing below the circle's center. Absolutely position the
label below the circle so the row height equals just the circle and
items-center aligns the line to the circle's center.

* feat(onboarding): refresh welcome layout & indicator spacing

- Place logo inline to the right of the Welcome heading
- Move the tagline badge below the heading with more breathing room
- Add space between the step indicator and step content
2026-06-24 15:35:22 +05:30
Arjun
7e1acedfcf remove recents from new chat 2026-06-24 12:01:10 +05:30
PRAKHAR PANDEY
1bfda94f48
fix: suppress notification spam on app re-open (#623)
* fix: suppress notification spam on app re-open

- Add background_task notification category (default ON) so users can
  toggle off background-task pings via Settings → Notifications
- Route notify-user builtin through notifyIfEnabled gate so the
  category toggle takes effect
- Add 60s startup grace period: background-task notifications fired
  within 60s of launch are suppressed, killing the reopen flood where
  all queued agents complete at once
- Suppress new_email notifications for emails older than 5 min so
  Gmail's startup backlog replay doesn't surface day-old mail

Fixes both issues reported by Ramnique.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix: skip automatic chat_completion ping for background task agents

Background task runs were triggering "Response ready / Your agent
finished responding" on every completion. Skip the automatic
chat_completion notification when finalState.runUseCase ===
'background_task_agent' — background tasks notify explicitly via
notify-user when they have something worth surfacing.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix: correct notification deeplinks and skip internal agent pings

- runtime.ts: also skip chat_completion ping for knowledge_sync
  useCase (agent_notes_agent was opening notes view on click)
- sync_gmail.ts: new_email notification now links to specific
  email thread (rowboat://open?type=email&threadId=...)
- App.tsx: add email case to parseDeepLink, parse threadId param,
  wire threadId through applyViewState, update viewStatesEqual

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix: distinguish background-agent notifications from auto knowledge-sync

Per team clarification, two background types are handled differently:
- knowledge_sync (auto knowledge-graph generation): never notifies;
  skips the generic chat_completion ping entirely.
- background_task_agent (user-configured agents): notifies via its
  own notify-user path, gated behind the toggleable "Background
  agents" category, deep-linking to the background-tasks page.

- runtime.ts: skip the generic chat_completion completion ping for
  both knowledge_sync and background_task_agent (the latter notifies
  via notify-user, so the generic ping would duplicate it).
- builtin-tools.ts: notify-user branches on getCurrentUseCase() —
  background agents route through notifyIfEnabled('background_task')
  with a bg-tasks deeplink default; chat agents notify directly.
- App.tsx: add the bg-tasks deeplink target (ViewState, parseDeepLink,
  applyViewState, currentViewState).
- settings-dialog.tsx: rename the category label to "Background agents".
- runner.ts: wrap the background-task run in withUseCase so tools see
  the correct use-case context.

* fix: route coding-session notifications through notifyIfEnabled

Code-mode status-tracker was calling notificationService.notify() directly,
bypassing the user's notification-category toggles. Routed both calls
through notifyIfEnabled() with correct categories:
- needs-you state → agent_permission
- idle after 30s  → chat_completion

Removed now-redundant container/INotificationService plumbing.

* fix: fall back to persisted run useCase when ALS context is missing in notify-user

AsyncLocalStorage does not propagate across the background-task agent's
async generator — getCurrentUseCase() returns undefined inside notify-user,
causing the background_task_agent branch to be skipped and the Background
agents toggle to be ignored.

Fix: load persisted useCase from run record via fetchRun(ctx.runId) when
ALS is falsy. Lazy dynamic import() avoids the known module-init cycle.
Background-agent notifications now correctly respect the toggle and only
fire when the app is in the background, with deep link to the bg-tasks page.

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 01:36:06 +05:30
Harshvardhan Vatsa
c0b38d46d3
Fix/GitHub workflow (#638)
* fixed workflow

* fix(forge): hoist staged ACP node_modules to stay under Windows MAX_PATH

The Squirrel/nuget Windows maker failed with 'path too long': stageAcpAdapters
rebuilt the ACP dependency closure by always nesting each dep under its parent,
producing 5-level chains (codex-acp -> open -> wsl-utils -> is-wsl ->
is-inside-container -> is-docker) whose paths hit ~260 chars on the CI runner and
blew past Windows' MAX_PATH (nuget.exe ignores long-path settings).

Hoist every package to the top-level node_modules npm-style, nesting only on a
genuine version conflict. Deepest staged path drops 177 -> 114 chars (worst-case
CI absolute ~197, well under 260). Add verifyAcpStaging() which asserts every
dependency edge resolves, in the staged tree, to the same version as the source
pnpm tree, failing the build loudly instead of shipping a broken installer.
2026-06-23 23:25:19 +05:30
PRAKHAR PANDEY
812ed9222c
Merge pull request #633 from prakhar1605/fix/filter-chat-models
Filter non-chat models from BYOK model picker
2026-06-23 18:18:00 +05:30
gagan
6ba6f494c1
fix(google-docs): move Add Google Doc into Knowledge Quick actions (#635)
Place the action in the files-view "Quick actions" row (next to New note)
instead of the header, where it sat after the dev↔drive merge. Widen
QuickAction's icon type to accept the custom GoogleDriveIcon component.
2026-06-23 03:20:17 +05:30
arkml
be81ffb27b
Drive (#583)
* add drive sync up and down

* add drive button

* google doc icon

* icon changes

* show error state with retry in google doc picker

* feat(google-docs): import and sync down as Markdown, record remote revision

* feat(google-docs): structure-preserving sync up with remote-conflict guard

* feat(google-docs): overwrite-confirm on sync conflict and last-synced indicator

* feat(google-docs): store linked docs as .docx, edit in docx editor, sync via Drive

* feat(google-docs): offer BYOK connect in picker so signed-in users can grant Drive/Docs scopes

* fix(google-docs): request full drive scope so .docx sync-up can write back

* fix(google-docs): search all drives in doc picker, log result count

* feat(google-docs): import native Docs AND uploaded .docx files from Drive

* chore(google-docs): drop dev-only test file

* feat(google-docs): use Google Picker + drive.file scope instead of full-drive listing

* fix(google-oauth): request offline access so BYOK tokens refresh

BYOK never requested access_type=offline/prompt=consent so no refresh token was issued and tokens died after ~1h; also stop handing back expired tokens and extend the connect timeout to 10m.

* feat(google-docs): pick docs via system-browser Google Picker

Runs the Picker in the user's real browser (it 403s inside Electron), sets appId so the drive.file grant attaches to the picked file, and downloads + opens the selected doc.

* feat(google-docs): managed OAuth-redirect Picker (no API key, no BYOK) (#620)

* feat(google-docs): managed OAuth-redirect Picker (no API key, no BYOK)

Adds the managed (rowboat-mode) Google Docs picker via Google's trigger_onepick
flow. The Rowboat backend runs a standalone drive.file OAuth with the company
client, renders the Picker inside the browser consent screen, and deep-links the
selection back; the desktop downloads the picked doc with the fresh drive.file
token the backend returns. No Picker API key, appId, or BYOK credentials on the
desktop.

- core: importGoogleDocWithToken downloads a picked doc with an explicit token;
  fetch/metadata helpers take an optional Drive client and share writeDocxAndLink.
  claimPickedFilesViaBackend claims the parked file ids + token from the api.
- main: google-picker-managed.ts opens the backend start URL and resolves on the
  rowboat://oauth/google/picker/done deep link; deeplink.ts routes that completion.
- ipc: google-docs:pickViaManaged.
- renderer: the picker dialog gates on Rowboat sign-in (the picker grants
  drive.file per-file, so no pre-existing connection or scope is required).

Backend contract: rowboatlabs/rowboatx-backend#7
(GET /oauth/google/picker/{start,callback}, POST /v1/google-oauth/claim-picked).

* chore(google-docs): remove the dead API-key/system-browser Picker

The managed picker replaced the only consumer (the picker dialog), so the
experimental API-key Picker is now unused. Removes:
- main: google-docs:openPicker handler (system-browser loopback Picker)
- shared: google-docs:openPicker + google-docs:getAccessToken IPC schemas
- core: getGoogleAccessToken (token plumbing for the client-side Picker)
- renderer: lib/google-picker.ts (Picker JS SDK loader)

Kept GoogleClientIdModal / google-credentials-store — still used by the
general BYOK Google connect in onboarding, connectors, and settings.

---------

Co-authored-by: Gagancreates <gaganp000999@gmail.com>
2026-06-23 03:13:58 +05:30
gagan
a12bf4837b
feat(voice): audio-reactive waveform while recording (no live transcript) (#634)
* feat(voice): show audio-reactive waveform instead of live transcript

When recording, the chat input now displays only a live waveform that
accumulates from the left and grows to full width, with bar heights
driven by real mic amplitude. The transcribed words are still captured
and submitted, just not shown while recording. New bars animate in and
flow smoothly at ~16 updates/sec.

* feat(voice): auto-gain waveform bar heights to track voice dynamics

Normalize each frame's amplitude against a running peak (instant attack,
slow release) at capture time and map it with a near-linear curve, so bar
heights accurately reflect how loud/soft the voice is regardless of mic
gain — replacing the old fixed-gain sqrt curve that saturated near max.
2026-06-23 02:40:56 +05:30
Arjun
de7d6b7a10 assistant notes below each note 2026-06-22 22:35:54 +05:30
Prakhar Pandey
1368d84bac fix(onboarding): filter non-chat models from provider list using models.dev 2026-06-22 12:49:48 +05:30
PRAKHAR PANDEY
6040c54807
Merge pull request #631 from prakhar1605/feat/byok-multiple-keys
Feat/Add multiple provider keys in BYOK onboarding (task 5)
2026-06-22 12:09:05 +05:30
Prakhar Pandey
30373765e7 Merge remote-tracking branch 'upstream/dev' into feat/byok-multiple-keys 2026-06-22 12:03:40 +05:30
PRAKHAR PANDEY
51ca8778b5
Merge pull request #629 from prakhar1605/feat/byok-onboarding-simplify
Simplify BYOK onboarding to provider + key (tasks 4 & 6)
2026-06-22 11:59:55 +05:30
gagan
45188e7c1c
feat(code-mode): per-session model + effort, and keep output on nav (#632)
Two improvements to the Code section:

- Fix: leaving the Code section and returning no longer drops the open
  session's output. The selected session id is persisted to localStorage
  (mirroring the terminal-height pattern) and restored on remount, so the
  right-hand chat pane re-binds instead of falling back to the empty state.

- Feature: choose the coding agent's model and reasoning effort per session.
  Choices are discovered live from the engine (the same list `/model` shows)
  via a new `codeMode:listModelOptions` IPC, cached per agent — never
  hardcoded, so they track whatever the provider currently offers. Claude
  exposes model + effort as separate axes (with explicit Opus/Sonnet/Haiku
  alias rows surfaced for clarity); Codex folds effort into the model id and
  reports no separate effort. Selections persist on the CodeSession and are
  re-applied to the ACP session each turn (best-effort), editable from both
  the new-session dialog and the session header.
2026-06-21 21:08:49 +05:30
Arjun
c8d801a123 add toolkits to the new chat for ease of discovery 2026-06-20 03:02:41 +05:30
Arjun
a0429fc037 email reply all and first name signoff 2026-06-20 02:32:08 +05:30
Arjun
f848d235d8 fix file diffs 2026-06-20 00:02:29 +05:30
Ramnique Singh
f65f7e8fc8 feat(billing): consume plan variant catalog
Fetch the public billing catalog during account config load and use durable plan IDs from /v1/me for display, analytics, and upgrade/manage labels.

Renderer billing surfaces now resolve plan display data from the catalog and show Unknown when the backend returns an unmapped plan ID.
2026-06-19 16:52:22 +05:30
Arjun
aa8dfb74ad minor ui fixes and default model to claude 2026-06-19 16:24:29 +05:30
Arjun
dfd4075e0e filter out random contacts 2026-06-19 14:59:45 +05:30
Arjun
851c3be69f gmail contacts should use light mode 2026-06-19 14:45:21 +05:30
Prakhar Pandey
2fb0e7402a feat(onboarding): allow adding multiple provider keys in BYOK 2026-06-19 12:47:35 +05:30
Arjun
811ae22bb1 knowledge to brain 2026-06-19 11:59:56 +05:30
gagan
1f8ac2cf34
feat(bg-tasks): coding-from-meetings — auto-implement coding action items (#630)
* feat(bg-tasks): coding-from-meetings — auto-implement coding action items

A background-task flavor that watches for meeting notes, scans them for
actionable coding items, and autonomously implements them in isolated git
worktrees, summarizing results in the task's index.md.

- Emit `meeting.notes_ready` when Fireflies/Granola first write a meeting note
- Add optional `projectId` to BackgroundTask (pins a coding task to a repo)
- New `launch-code-task` builtin tool: per group of items, create a
  worktree-isolated, yolo, direct code session, wrap the prompt in an
  autonomous scaffold, run async, and finalize a per-session row in index.md
- Group code sessions under their meeting heading in index.md
- Summary from the code agent's `## Summary` section; file counts from
  `git diff` vs the worktree fork point (counts committed work, not just dirty)
- Guardrails: self-heal projectId across runs, cap launches per run, and bar
  the bg-task agent from managing/spawning tasks
- UI: "View available templates" -> Coding-from-meetings preset (repo picker,
  prefilled trigger + instructions)

See plan.md for the full design.

* let the copilot able to configure a coding background agent

* Delete plan.md

---------

Co-authored-by: Arjun <6592213+arkml@users.noreply.github.com>
2026-06-19 11:26:43 +05:30
Prakhar Pandey
36da053b8d Merge remote-tracking branch 'upstream/dev' into feat/byok-onboarding-simplify
# Conflicts:
#	apps/x/apps/main/src/ipc.ts
#	apps/x/packages/core/src/models/models.ts
#	apps/x/packages/shared/src/ipc.ts
2026-06-19 01:37:25 +05:30
Prakhar Pandey
92b95f659e feat(onboarding): simplify BYOK to provider + key, fetch models from key 2026-06-19 01:12:53 +05:30
gagan
2f926f8dc0
fix(copilot): make Copilot aware of native Slack and query selected channels (#627)
When Slack is connected natively (desktop/cURL auth, not Composio), the Copilot now routes Slack requests to the native slack skill instead of composio-integration, surfaces the user's selected channels in the system prompt, and steers catch-up queries to 'agent-slack message list --oldest' rather than unreads/search (which return empty under desktop-imported auth). Instruction cache is invalidated on slack:setConfig and knowledgeSources:upsert so changes take effect.
2026-06-18 11:53:56 -07:00
Harshvardhan Vatsa
c38ddef93f
feat: compose new email with contact autocomplete and AI drafting (#616)
* feat: compose new email with contact autocomplete and AI drafting

- Add a compose-new-email box to the email view with a recipient field
  that autocompletes from Gmail contacts (keyboard navigation, match
  highlighting, avatar chips)
- Build contact indices in core: gmail_sent_contacts syncs the SENT
  label via the Gmail API for full coverage of people you've emailed,
  with gmail_contacts as an instant local-snapshot fallback; both are
  pre-warmed at startup so the first keystroke is instant
- Add generateOneShot() one-shot text generation for the composer's
  "write with AI", resolving to the active default model/provider
- Add getAccountName() (parsed from a recent SENT message's From
  header, no extra OAuth scope) so AI drafts sign off with the real name
- New IPC channels: gmail:searchContacts, gmail:getAccountName,
  llm:generate, llm:getDefaultModel

* feat: attachments, undo/redo, and unified compose for new emails

- Merge ComposeNewBox into ComposeBox via a new 'new' mode, memoizing the
  component so inbox sync ticks no longer jank the open composer.
- Add file attachments: stage files in the renderer (25MB cap), pass raw
  base64 over IPC, and build a multipart/mixed MIME on send.
- Add undo/redo buttons to the compose toolbar.
- Single Write/Edit AI bar that generates a draft, then iteratively rewrites
  it; drop the hardcoded Gemini Flash model and use the default Copilot model.
- Suppress inbox reloads while the compose-new modal is open.
- Log llm:generate provider/model/output for debugging.

* fix: remove redundant Subject placeholder in composer

The subject row already has a 'Subject' gutter label, so the input's
placeholder repeated the word — an empty field read 'Subject' twice.
Drop the placeholder to match the To/Cc/Bcc fields.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 00:14:00 +05:30
gagan
3fe7f307ab
fix(code-mode): use System32 bsdtar to extract engines on Windows (#626)
Enabling Claude/Codex in Settings -> Code Mode failed on Windows with
"tar (child): Cannot connect to C: resolve failed / gzip: stdin:
unexpected end of file". PATH `tar` resolves to a GNU tar (Git/MSYS2)
that misreads the absolute archive path "C:\...\engine.tgz" as a remote
host:path spec.

Pin extraction to the bsdtar shipped in System32, which handles
drive-letter paths natively, with a relative-path fallback if it is
absent. macOS/Linux behavior is unchanged.
2026-06-18 02:03:21 +05:30
arkml
79162ebc69
feat: ship Slack as a knowledge source, hardened for production (#596)
* index slack and add to home page

* filter only useful slack messages in homr

* feat: bundle agent-slack CLI and route all calls through shared executor

Pins agent-slack@0.9.3, bundles it next to main.cjs (replaces the startup npm install -g), adds a structured-result executor with bundled/global/PATH resolution, a slack:cliStatus IPC probe, and a PATH shim so the Copilot skill keeps working.

* feat: surface Slack failures and add cross-OS auth fallbacks

Classify agent-slack errors (not_authed/rate_limited/network/bad_channel), persist per-source sync status with rate-limit backoff, and expose it via slack:knowledgeStatus. Fix the Settings Enable bounce-back with actionable copy, a browser-paste (parse-curl) fallback, and a Windows quit-Slack-and-import button; add home-feed empty/error states.

* feat: rank Slack home feed deterministically by recency

Drop the per-load LLM ranker (cost/latency/model dependency) in favor of a stronger deterministic filter + recency ordering. The filter now removes system messages, emoji/reaction-only posts, bare greetings/acks, and empty bodies, with a durable-signal escape hatch. Expand tests to one describe per noise class plus ordering/cap/volume coverage.

* fix: hide Slack knowledge Save button once saved

Only show the Save button when the channel list or enabled toggle differs from the last-persisted config, so it disappears after a successful save and reappears when a new channel is entered.

---------

Co-authored-by: Gagancreates <gaganp000999@gmail.com>
2026-06-17 12:52:27 -07:00
gagan
2ddec07712
Code mode: make packaged builds work via managed engine provisioning (#625)
* 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 separate `node <entry>` processes resolved at runtime, but esbuild
can't inline a dynamic spawn target and Forge strips the workspace node_modules,
so every release threw `Cannot 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/<agent>/<version>/, 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: `installed` now 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 package` failed. 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`.
2026-06-17 21:53:15 +05:30
Gagan
8ce24ebb33 Revert "fix(code-mode): make packaged code mode work and drop ~460MB bundled engines (#614)"
This reverts commit 33c15cfbd9.
2026-06-16 23:29:46 -07:00
arkml
ed8f6f7246
Last modified (#624)
* order chats by recency
2026-06-17 10:21:24 +05:30
gagan
33c15cfbd9
fix(code-mode): make packaged code mode work and drop ~460MB bundled engines (#614)
* fix(code-mode): ship ACP adapters in packaged builds

Code mode spawns the Claude/Codex ACP adapters as separate `node <entry>`
processes resolved at runtime, so each must exist as a real file on disk.
esbuild can't inline them (dynamic require.resolve + spawn target), and Forge's
`ignore: /node_modules/` rule strips the workspace node_modules — so packaged
builds threw `Cannot find module '@agentclientprotocol/claude-agent-acp'` and
code mode was broken in every release. Dev worked only because the pnpm symlink
was present.

Stage the two adapters and their full production dependency closure into
.package/acp/node_modules during generateAssets, reconstructing an npm-style
nested layout: nest on version conflict (claude and codex keep their own
@agentclientprotocol/sdk; the @openai/codex launcher keeps its platform binary)
and skip platform-optional deps not installed for the build OS, so each OS ships
its own native binary. Exempt .package from the node_modules ignore rule, and
make the adapter resolver check the staged location first, falling back to
node_modules in dev.

Resolve dependency directories by walking node_modules directly rather than
require.resolve(`${pkg}/package.json`): the latter throws for packages whose
`exports` map doesn't expose package.json (e.g. @anthropic-ai/claude-agent-sdk),
which would silently drop them and their subtrees from the staged closure.

* fix(code-mode): drive agents from local install, drop bundled engines

Skip the platform-native engine packages (~230 MB each) when staging the ACP adapters and point each adapter at the user's local claude/codex via CLAUDE_CODE_EXECUTABLE / CODEX_PATH, erroring clearly when neither is installed. The codex resolver mirrors claude's login-shell probe so nvm/fnm installs resolve on macOS/Linux. Shrinks each installer ~460 MB.

* fix(code-mode): surface agent startup failures instead of hanging forever

- 60s deadline on adapter initialize / session create+load: an engine that
  launches but never completes the SDK handshake (e.g. an outdated local
  CLI) now fails with the adapter's stderr attached instead of leaving the
  turn (pending...) indefinitely; prompts themselves stay un-timed
- dispose the adapter client when startup fails so the spawned process
  does not leak
- set DEBUG_CLAUDE_AGENT_SDK=1 so the SDK logs the exact spawn command and
  claude's stderr to ~/.claude/debug/sdk-*.txt and startup errors point at
  that file (engine stderr is otherwise discarded entirely)
- graft the user's login-shell PATH onto the adapter env on macOS/Linux:
  GUI launches inherit launchd's stripped PATH, which breaks node-shebang
  claude launchers (nvm/npm installs) and the engines' own subprocess spawns

* ci(code-mode): cross-platform smoke matrix + one-shot diagnose script

- x-code-mode-smoke.yml: on apps/x PRs, package the app on mac/linux/windows
  and run acp-smoke.mjs, which asserts (1) adapters staged + native engines
  stripped, (2) each staged adapter boots from the packaged app via the
  packaged Electron binary and answers ACP initialize, (3) a fake engine that
  launches but never responds is converted into a clear startup-timeout error
  instead of hanging forever (the silent-hang class)
- diagnose-code-mode.sh: colleagues run one command and send one blob
  (engine versions/paths/types, login-shell vs GUI PATH, auth presence,
  stream-json probe, newest SDK debug log) — one round trip instead of five
- forge.config.cjs: only sign/notarize when APPLE_ID is set, so unsigned
  local mac builds and the CI smoke matrix can package deterministically
- client.ts: startup timeout overridable via ROWBOAT_ACP_STARTUP_TIMEOUT_MS
  (CI uses 10s; also an escape hatch for slow MCP-heavy setups)

Verified on Windows: all smoke checks pass, including the end-to-end
fake-hanging-engine timeout (fails in 10.0s with the stderr-enriched error).

* fix(ci): make smoke fake engines executable — codex-acp spawns CODEX_PATH directly on unix

A bare .js with no shebang/exec bit fails with EACCES and crashes the adapter
on mac/linux. Split into an exec-bit exit-0 fake for the handshake check and
the hanging fake for the timeout check.

* fix(code-mode): resolve claude/codex installed via version managers

commonInstallPaths only checked ~/.nvm/versions/node/<binary>, never
descending into nvm's versioned vX.Y.Z/bin subdirs, so an nvm-installed
codex/claude showed "not installed" in Settings and failed code-mode
chat with "CLI not found" on GUI launches (where the login-shell PATH
isn't inherited).

Enumerate each installed Node version's bin dir for nvm/fnm/asdf, and
add pnpm global (PNPM_HOME / platform default) and Claude Code's legacy
~/.claude/local install location. Shared by both the Settings status
check and the chat/tab binary resolvers, so it covers all code-mode
entry points.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* chore(code-mode): remove code-mode smoke test workflow and script

Only needed during cross-platform verification of the packaged code-mode
fix; drop the CI workflow and its acp-smoke.mjs helper now that it's done.

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 14:16:00 -07:00
Arjun
f04e85670b Added a 1-second hover delay to all assistant chat composer tooltips, including native path model/stop tooltips. 2026-06-16 00:16:34 +05:30
hrsvrn
610cb66d40 fix: keep light canvas for styled emails in dark mode
Styled HTML emails (newsletters, branded mail) declared color-scheme
'light dark' whenever the app theme was dark, so Chromium resolved the
iframe to the dark scheme and painted an opaque dark canvas under
emails that assume a white background, making their text unreadable.
Only opt into the dark scheme when the email actually adapts to the
app theme.
2026-06-15 14:57:45 +05:30
Arjun
1632b16dfc add embedded terminal to code mode (node-pty + xterm)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 23:57:44 +05:30
Arjun
45100580c9 add code mode: coding-agent workspace with sessions, direct/Rowboat drive, diffs, and worktrees
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-12 23:57:44 +05:30
PRAKHAR PANDEY
0d21abcc7d
feat: add user-configurable notification settings (#601) 2026-06-11 19:43:26 +05:30
PRAKHAR PANDEY
faaefe936f
fix: resolve macOS mic permission on first click in voice mode (#613)
On macOS, the first getUserMedia({audio:true}) call hits TCC permission
status 'not-determined' — the OS prompt appears but the in-flight call
rejects, is silently swallowed, and the UI snaps back to idle. Second
click works because permission is already granted.

Fix: add voice:ensureMicAccess IPC channel (mirroring the existing
meeting:checkScreenPermission pattern) that calls
systemPreferences.askForMediaAccess('microphone') before getUserMedia,
so the same first click proceeds once the user grants access.

Also fixes a secondary bug: on the failure path, the code only called
setState('idle'), leaking the WebSocket that connectWs() had already
opened. Now calls stopAudioCapture() for proper cleanup.
2026-06-11 02:07:18 +05:30
PRAKHAR PANDEY
0f4a693b34
fix: macOS meeting auto-stop via track-state polling (#612)
* fix: add track-state polling for macOS meeting auto-stop

On macOS (ScreenCaptureKit/Electron 39) the system-audio track does not
fire 'ended' or 'mute' events when the meeting ends. Add a 3-second
polling interval that checks track.readyState and track.muted directly.
Auto-stops after the track is muted for 3 consecutive polls (~9 seconds),
or immediately if readyState becomes 'ended'. Windows behavior unchanged
(existing 'ended' event listener kept intact).

* fix: gate macOS meeting muted-poll auto-stop on scheduled calendar end

On macOS the system-audio track reports muted=true both when the meeting
ends and during any silent stretch of a still-live meeting, so the
unconditional ~9s muted hard-stop could cut a quiet-but-live meeting short
with no warning.

Only hard-stop on sustained mute once we're past the linked calendar
event's scheduled end (a strong "it's really over" signal); otherwise let
the existing silence nudge + backstop handle it. Gate the whole poll to
macOS — Windows already auto-stops via the track "ended" event — and drop
the noisy per-poll debug log.

---------

Co-authored-by: Gagancreates <gaganp000999@gmail.com>
2026-06-11 02:00:11 +05:30
gagan
9453e0d550
feat: render background-task HTML output and open its links externally (#615)
* feat: render background-task index.html output in a sandboxed iframe

The task output pane now prefers bg-tasks/<slug>/index.html when present and
non-empty, rendering it full-bleed via HtmlFileViewer (app://workspace
protocol) so CSS, layout, and scripts render faithfully. Falls back to the
markdown index.md note when there is no HTML artifact. The viewer remounts on
refreshKey so a re-run's updated HTML reloads. The Source/Rendered toggle works
for both formats.

The runner agent is instructed to choose index.md (default, notes) vs a
self-contained index.html (visual/styled output) per run, written via the
existing file-writeText tool. The Copilot background-task skill notes the HTML
option so visual asks are steered toward it.

* fix: open links from HTML report iframes in the system browser

Links inside the sandboxed iframe that renders a background-task/workspace
index.html did nothing on click, unlike the markdown viewer which opens links
in the browser.

Two causes: target="_blank" links were blocked by the sandbox before reaching
the window-open handler, and plain links fire will-frame-navigate (subframe),
which the app did not handle (will-navigate only covers the main frame).

- Add allow-popups to the HtmlFileViewer iframe sandbox so target="_blank"
  reaches setWindowOpenHandler, which routes to shell.openExternal.
- Handle will-frame-navigate in main, routing external subframe navigations to
  the system browser. Scoped to app://workspace frames so third-party note
  embeds (YouTube/Figma/Twitter) keep their internal navigation.
2026-06-11 01:45:10 +05:30
Harshvardhan Vatsa
c48ef5ac0c
add Gmail contacts autocomplete to compose box (#607)
Adds a gmail:searchContacts IPC channel backed by two indices: a
SENT-label API-backed index (gmail_sent_contacts) for full historical
coverage of people you've actually emailed, and a local-snapshot
fallback (gmail_contacts) used until the SENT sync finishes on first
launch. Both indices warm at startup so the first keystroke in the
recipient box is instant. Renderer wires the suggestions into the
to/cc/bcc fields in email-view with styled chips.

Co-authored-by: arkml <6592213+arkml@users.noreply.github.com>
2026-06-10 14:58:13 +05:30
Harshvardhan Vatsa
0aec665220
add pacman maker for Arch Linux packages (#604)
Custom Electron Forge maker that wraps makepkg to produce a
.pkg.tar.zst with /opt/<app>, /usr/bin wrapper, .desktop entry,
and hicolor icon. Only activates on Linux when makepkg is present,
so other platforms are unaffected.
2026-06-10 14:55:15 +05:30
gagan
80fef06da0
feat: make meeting recording auto-stop when the meeting ends (#611)
Detect silence from raw mic+system audio armed at recording start, add a quiet-meeting stop nudge, shorten the window once past the calendar end time, and stop instantly when the shared call window closes.
2026-06-10 14:50:45 +05:30
Arjun
fcbcc137ca make meeting note name wrap 2026-06-10 10:47:12 +05:30