rowboat/apps/x/packages/shared/src
gagan 372309eb18
feat: run code mode on an in-app ACP client with live approvals (#593)
* feat(code-mode): add ACP client engine (Layer 2 core)

Own the Agent Client Protocol client instead of shelling out to `acpx`, so code
mode can stream structured events (tool calls, diffs, plan) and surface live
permission requests. Headless acpx can't do live approvals (it only supports
--approve-all), which is why we drive the agent adapters ourselves.

- code-mode/acp/{agents,client,permission-broker,session-store,manager,types}.ts:
  headless engine driving the Claude/Codex ACP adapters; one warm session per chat
  with create-or-resume via session/load; approval policy (ask | auto-approve-reads
  | yolo) in the broker.
- claude-exec.ts: cross-platform claude resolver (Windows .cmd EINVAL fix + macOS/Linux
  GUI-PATH safety net) shared with the legacy acpx path in builtin-tools.ts.
- add @agentclientprotocol/sdk + claude/codex adapters to core.

* feat(code-mode): route code mode through code_agent_run tool + live approvals

Replace the acpx shell-out with a structured code_agent_run tool that drives the
ACP engine directly, streaming the agent's tool calls / diffs / plan into the chat
and surfacing permission requests inline.

- shared: code-mode.ts zod schemas; add code-run-event + code-run-permission-request
  RunEvent variants (stream to the renderer over the existing runs:events channel);
  codeRun:resolvePermission IPC channel.
- core: CodePermissionRegistry (promise-based mid-run approvals — the LLM tool-loop's
  pre-call gate can't model a mid-execution wait); register codeModeManager +
  codePermissionRegistry in awilix.
- core: code_agent_run builtin tool (streams via ctx.publish, asks via the registry,
  cancels on ctx.signal, returns the agent summary). CodeModeConfig.approvalPolicy
  (ask | auto-approve-reads | yolo; default ask). Exclude the tool from the headless
  background-task / live-note / inline-task agents so they can't block on an approval.
- main: codeRun:resolvePermission handler -> registry.resolve.
- rewrite the code-with-agents skill and the runtime "Code Mode (Active)" block to call
  code_agent_run instead of emitting npx acpx commands.

* feat(code-mode): render coding runs inline (live timeline + permission card)

Render a code_agent_run tool call as a live CodingRun block instead of generic
tool output: the agent's text, tool-call rows (kind icon + status + changed-file
names from diffs), a plan checklist, and resolved-permission lines — plus an
inline Allow / Always-allow / Deny card wired to codeRun:resolvePermission.

- chat-conversation.ts: ToolCall carries codeRunEvents + pendingCodePermission;
  code_agent_run is excluded from tool-grouping so it renders standalone.
- App.tsx: handle code-run-event / code-run-permission-request, clear the pending
  card on tool-result, handleCodePermissionResponse, render via CodingRunBlock.

* fix(code-mode): run the ACP adapter as Node under Electron + resolve it from main

Two runtime failures that only surfaced inside the packaged/bundled Electron app
(the headless harness used real node, so neither showed there):

- "ACP connection closed": the main process spawns the adapter via
  process.execPath, which inside Electron is the Electron binary, not node — so
  the child never ran as Node and its ACP stdio stream closed immediately. Set
  ELECTRON_RUN_AS_NODE=1 on the adapter env (a no-op under real node).
- "Cannot find module '@agentclientprotocol/claude-agent-acp'": the adapters were
  transitive (core) deps, unreachable from the esbuild-bundled main.cjs. Add them
  as direct deps of the main app so require.resolve finds them at runtime (and so
  they ship when packaged).

Also capture the adapter's stderr + exit code and enrich connection errors, so a
future failure reports the real cause instead of the opaque "ACP connection closed".

* chore(code-mode): remove dead acpx code paths and stale copy

Code mode now runs through the code_agent_run tool (owning the ACP client), so the
legacy acpx shell-out paths are dead. Remove them:

- core: envForCommand (acpx-only CLAUDE_CODE_EXECUTABLE injection) from
  executeCommand; getCodeModeCommandLabel (acpx run-status label).
- renderer: the acpx-detection "switch agent / auto-flip the code-mode chip" flow —
  App.tsx executeCommand detection, the permission-request onSwitchAgent button +
  badge, and the composer's code-mode-detected listener.
- copy: Settings -> Code Mode and the code-with-agents skill summary no longer
  mention acpx; tidy stale comments (claude-exec, command-executor).

No behavior change for code mode; the general executeCommand tool is unaffected.

* feat(code-mode): approval-policy selector in Settings

Surface the approval policy (Ask every time / Auto-approve reads / YOLO) in
Settings -> Code Mode, instead of being config-file only. The broker already
reads CodeModeConfig.approvalPolicy; this plumbs it through the
codeMode:getConfig / setConfig IPC + main handlers and adds the picker UI
(with a one-line explanation of each level). Defaults to "ask".

* fix(code-mode): harden ACP engine — turn-scoped connections, chip-authoritative agent, reliable stop

Three robustness fixes that co-modify manager.runPrompt and the code_agent_run
tool, so they land together:

- Lifecycle: scope each ACP adapter connection to the agent turn. Dispose it a
  short grace (60s) after the turn ends instead of holding it for the app's life;
  the next turn resumes via session/load (both agents support it). Wire
  disposeAll() on app quit (was dead code). Fixes the unbounded per-chat leak of
  booted agent processes.

- Agent selection: make the composer chip the source of truth. Thread codeMode
  into ToolContext; code_agent_run uses it instead of the model's guessed `agent`
  arg, which anchored on the thread's earlier agent and ignored a chip change.
  Prompts updated to match; the run is labelled by the agent that actually ran.

- Stop/abort: guarantee a stopped turn unwinds. On abort the manager sends ACP
  session/cancel, then force-kills the adapter after a 2s grace and resolves the
  turn as cancelled — a wedged adapter can no longer hang the run and lock the
  chat. code_agent_run returns a clean cancelled result.

* fix(code-mode): hide Codex's native console window on Windows

Codex's engine ships as a native console-subsystem binary (codex.exe). Launched
from our console-less Electron process tree, Windows allocated a fresh *visible*
console window for it; closing that window wedged the run in a pending state.
(Claude Code is a Node CLI, so it never triggers this.)

The window is created by @openai/codex's launcher (bin/codex.js), which spawns
codex.exe with no windowsHide. Patch it via pnpm to pass windowsHide: true
(CREATE_NO_WINDOW) so the console stays hidden — no window, nothing to close.

* refactor(code-mode): move ACP session files out of WorkDir/config

Per-run ACP session state is runtime state that accumulates one file per
chat run, not user/app config. Relocate it from WorkDir/config to a
dedicated WorkDir/code-mode/sessions/ so it can be listed, cleaned up, and
managed on its own without crowding config. Drop the now-redundant
codesession- filename prefix (the directory conveys it).
2026-06-05 14:45:08 +05:30
..
agent-schedule-state.ts feat: add background agents with scheduling support 2026-02-05 16:43:09 +05:30
agent-schedule.ts feat: add background agents with scheduling support 2026-02-05 16:43:09 +05:30
agent.ts bootstrap new electron app 2026-01-16 12:05:33 +05:30
background-task.ts feat: background tasks 2026-05-12 17:43:25 +05:30
bases.ts app navigation 2026-03-13 10:39:05 +05:30
billing.ts Show split monthly and daily credits 2026-05-24 12:48:23 +05:30
blocks.ts Gmail send, archive and delete (#573) 2026-05-25 09:47:08 +05:30
browser-control.ts pull browser-harness skills (#519) 2026-05-06 12:25:10 +05:30
code-mode.ts feat: run code mode on an in-app ACP client with live approvals (#593) 2026-06-05 14:45:08 +05:30
composio.ts Feature/composio tools library (#461) 2026-04-06 13:30:46 +05:30
events.ts feat: background tasks 2026-05-12 17:43:25 +05:30
example.ts bootstrap new electron app 2026-01-16 12:05:33 +05:30
frontmatter.ts app navigation 2026-03-13 10:39:05 +05:30
index.ts Update Electron billing UI for free plan 2026-05-18 11:12:39 +05:30
inline-task.ts Livenote2 (#440) 2026-03-19 01:34:10 +05:30
ipc.ts feat: run code mode on an in-app ACP client with live approvals (#593) 2026-06-05 14:45:08 +05:30
live-note.ts feat: background tasks 2026-05-12 17:43:25 +05:30
llm-step-events.ts feat(ui): surface LLM stream errors in chat 2026-02-16 08:34:51 +05:30
mcp.ts bootstrap new electron app 2026-01-16 12:05:33 +05:30
message.ts Persist per-message context for prompt caching 2026-05-28 23:00:44 +05:30
models.ts Add run-level auto permission mode 2026-06-03 07:58:04 +05:30
prefix-logger.ts bootstrap new electron app 2026-01-16 12:05:33 +05:30
prompt-block.ts add prompt block 2026-04-20 14:42:13 +05:30
rowboat-account.ts use deepgram ws proxy, simplify env vars 2026-03-24 11:50:22 +05:30
runs.ts feat: run code mode on an in-app ACP client with live approvals (#593) 2026-06-05 14:45:08 +05:30
service-events.ts Memory2 (#444) 2026-03-23 22:30:02 +05:30
workspace.ts bootstrap new electron app 2026-01-16 12:05:33 +05:30