diff --git a/apps/x/apps/renderer/src/App.tsx b/apps/x/apps/renderer/src/App.tsx index 6e9b8701..5023127f 100644 --- a/apps/x/apps/renderer/src/App.tsx +++ b/apps/x/apps/renderer/src/App.tsx @@ -2186,19 +2186,6 @@ function App() { status: 'running', timestamp: Date.now(), }]) - // Detect acpx-driven coding-agent runs so the composer can retroactively - // flip code mode on with the right agent (when the user reached the skill - // via plain prompt rather than the explicit toggle). - if (llmEvent.toolName === 'executeCommand') { - const input = llmEvent.input as { command?: unknown } | undefined - const cmd = typeof input?.command === 'string' ? input.command : '' - const match = cmd.match(/\bacpx\b[\s\S]*?\b(claude|codex)\b/) - if (match) { - window.dispatchEvent(new CustomEvent('code-mode-detected', { - detail: { runId: event.runId, agent: match[1] as 'claude' | 'codex' }, - })) - } - } } else if (llmEvent.type === 'finish-step') { const nextUsage = normalizeUsage(llmEvent.usage) if (nextUsage) { @@ -5881,24 +5868,6 @@ function App() { onApproveSession={() => handlePermissionResponse(permRequest.toolCall.toolCallId, permRequest.subflow, 'approve', 'session')} onApproveAlways={() => handlePermissionResponse(permRequest.toolCall.toolCallId, permRequest.subflow, 'approve', 'always')} onDeny={() => handlePermissionResponse(permRequest.toolCall.toolCallId, permRequest.subflow, 'deny')} - onSwitchAgent={async (newAgent) => { - const runIdForSwitch = tab.runId - await handlePermissionResponse(permRequest.toolCall.toolCallId, permRequest.subflow, 'deny') - window.dispatchEvent(new CustomEvent('code-mode-detected', { - detail: { runId: runIdForSwitch, agent: newAgent }, - })) - if (runIdForSwitch) { - try { - await window.ipc.invoke('runs:createMessage', { - runId: runIdForSwitch, - message: `Use ${newAgent === 'claude' ? 'Claude Code' : 'Codex'} instead — rerun the same task with the same prompt, just swap the agent binary to \`${newAgent}\`.`, - codeMode: newAgent, - }) - } catch (err) { - console.error('Failed to send swap-agent follow-up', err) - } - } - }} isProcessing={isActive && isProcessing} response={response} /> diff --git a/apps/x/apps/renderer/src/components/ai-elements/permission-request.tsx b/apps/x/apps/renderer/src/components/ai-elements/permission-request.tsx index d99d2e8b..cdcafc27 100644 --- a/apps/x/apps/renderer/src/components/ai-elements/permission-request.tsx +++ b/apps/x/apps/renderer/src/components/ai-elements/permission-request.tsx @@ -1,6 +1,5 @@ "use client"; -import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { DropdownMenu, @@ -9,7 +8,7 @@ import { DropdownMenuItem, } from "@/components/ui/dropdown-menu"; import { cn } from "@/lib/utils"; -import { AlertTriangleIcon, CheckIcon, ChevronDownIcon, RefreshCwIcon, Terminal, XIcon } from "lucide-react"; +import { AlertTriangleIcon, CheckIcon, ChevronDownIcon, XIcon } from "lucide-react"; import { useState, type ComponentProps } from "react"; import { ToolCallPart } from "@x/shared/dist/message.js"; import { ToolPermissionMetadata } from "@x/shared/dist/runs.js"; @@ -21,7 +20,6 @@ export type PermissionRequestProps = ComponentProps<"div"> & { onApproveSession?: () => void; onApproveAlways?: () => void; onDeny?: () => void; - onSwitchAgent?: (newAgent: 'claude' | 'codex') => void; isProcessing?: boolean; response?: 'approve' | 'deny' | null; permission?: z.infer; @@ -42,7 +40,6 @@ export const PermissionRequest = ({ onApproveSession, onApproveAlways, onDeny, - onSwitchAgent, isProcessing = false, response = null, permission, @@ -56,17 +53,6 @@ export const PermissionRequest = ({ : null; const filePermission = permission?.kind === "file" ? permission : null; - // Detect acpx coding-agent invocations so we can show the agent identity and - // offer a one-click swap-and-retry. - const acpxAgent: 'claude' | 'codex' | null = (() => { - if (!command) return null; - const match = command.match(/\bacpx\b[\s\S]*?\b(claude|codex)\b\s+exec\b/); - return match ? (match[1] as 'claude' | 'codex') : null; - })(); - const otherAgent: 'claude' | 'codex' | null = acpxAgent === 'claude' ? 'codex' : acpxAgent === 'codex' ? 'claude' : null; - const agentDisplay = acpxAgent === 'claude' ? 'Claude Code' : acpxAgent === 'codex' ? 'Codex' : null; - const otherDisplay = otherAgent === 'claude' ? 'Claude Code' : otherAgent === 'codex' ? 'Codex' : null; - const isResponded = response !== null; const isApproved = response === 'approve'; @@ -104,15 +90,6 @@ export const PermissionRequest = ({

{isResponded ? "Requested:" : "The agent wants to execute:"} {toolCall.toolName} - {agentDisplay && ( - - - {agentDisplay} - - )}

{isResponded && ( @@ -220,18 +197,6 @@ export const PermissionRequest = ({ Deny - {otherAgent && otherDisplay && onSwitchAgent && ( - - )} )} diff --git a/apps/x/apps/renderer/src/components/chat-input-with-mentions.tsx b/apps/x/apps/renderer/src/components/chat-input-with-mentions.tsx index 360a8657..096a5b3a 100644 --- a/apps/x/apps/renderer/src/components/chat-input-with-mentions.tsx +++ b/apps/x/apps/renderer/src/components/chat-input-with-mentions.tsx @@ -283,20 +283,6 @@ function ChatInputInner({ } }, [codeModeFeatureEnabled, codeModeEnabled]) - // Listen for coding-agent runs that were triggered without the explicit code-mode - // toggle. App.tsx dispatches this when it sees an acpx executeCommand fire. We - // flip the pill on with the detected agent so the UI reflects what's happening. - useEffect(() => { - const handler = (ev: Event) => { - const detail = (ev as CustomEvent<{ runId?: string; agent?: 'claude' | 'codex' }>).detail - if (!detail || !detail.agent) return - if (runId && detail.runId && detail.runId !== runId) return - setCodeModeEnabled(true) - setCodingAgent(detail.agent) - } - window.addEventListener('code-mode-detected', handler) - return () => window.removeEventListener('code-mode-detected', handler) - }, [runId]) // Cross-platform basename — handles both / and \ separators. const basename = useCallback((p: string): string => { diff --git a/apps/x/apps/renderer/src/components/settings-dialog.tsx b/apps/x/apps/renderer/src/components/settings-dialog.tsx index 37e0a930..3a88937f 100644 --- a/apps/x/apps/renderer/src/components/settings-dialog.tsx +++ b/apps/x/apps/renderer/src/components/settings-dialog.tsx @@ -1781,9 +1781,8 @@ function CodeModeSettings({ dialogOpen }: { dialogOpen: boolean }) {

Code mode lets the assistant delegate coding tasks to Claude Code or Codex running - on your machine. Pick the agent inline from the composer; the assistant calls it via - acpx - and streams results back into chat. + on your machine. Pick the agent inline from the composer; the assistant runs it on-device + and streams its work — tool calls, file diffs, and approvals — back into chat.

Requires an active Claude Code subscription or diff --git a/apps/x/apps/renderer/src/lib/chat-conversation.ts b/apps/x/apps/renderer/src/lib/chat-conversation.ts index 189bfdf7..603643de 100644 --- a/apps/x/apps/renderer/src/lib/chat-conversation.ts +++ b/apps/x/apps/renderer/src/lib/chat-conversation.ts @@ -521,41 +521,9 @@ const TOOL_DISPLAY_NAMES: Record = { * For builtin tools, returns a static friendly name (e.g., "Reading file"). * Falls back to the raw tool name if no mapping exists. */ -// Phrases shown while a code-mode task is running. They advance over time (5s -// each) to read as progress, then hold on the last one until the task finishes. -const CODE_MODE_RUNNING_LABELS = [ - 'Working on the task…', - 'Inspecting the project…', - 'Digging into the code…', - 'Figuring it out…', - 'Making the changes…', - 'Wiring things up…', - 'Putting it together…', -] -const CODE_MODE_LABEL_INTERVAL_MS = 5000 - -// Detect acpx coding-agent invocations (code mode) and produce a status-aware -// label, e.g. "Working on the task…" → "Completed the task". -export const getCodeModeCommandLabel = (tool: ToolCall): string | null => { - if (tool.name !== 'executeCommand') return null - const input = normalizeToolInput(tool.input) as Record | undefined - const command = typeof input?.command === 'string' ? input.command : '' - const match = command.match(/\bacpx\b[\s\S]*?\b(claude|codex)\b\s+exec\b/) - if (!match) return null - if (tool.status === 'error') return `Couldn't complete the task` - if (tool.status === 'completed') return `Completed the task` - // Advance through the phrases from the tool's start, holding on the last. - const elapsed = Math.max(0, Date.now() - tool.timestamp) - const step = Math.floor(elapsed / CODE_MODE_LABEL_INTERVAL_MS) - const idx = Math.min(step, CODE_MODE_RUNNING_LABELS.length - 1) - return CODE_MODE_RUNNING_LABELS[idx] -} - export const getToolDisplayName = (tool: ToolCall): string => { const browserLabel = getBrowserControlLabel(tool) if (browserLabel) return browserLabel - const codeModeLabel = getCodeModeCommandLabel(tool) - if (codeModeLabel) return codeModeLabel const composioData = getComposioActionCardData(tool) if (composioData) return composioData.label return TOOL_DISPLAY_NAMES[tool.name] || tool.name diff --git a/apps/x/packages/core/src/application/assistant/skills/index.ts b/apps/x/packages/core/src/application/assistant/skills/index.ts index 30ceea95..a06c153b 100644 --- a/apps/x/packages/core/src/application/assistant/skills/index.ts +++ b/apps/x/packages/core/src/application/assistant/skills/index.ts @@ -99,7 +99,7 @@ const definitions: SkillDefinition[] = [ { id: "code-with-agents", title: "Code with Agents", - summary: "Write code, build projects, create scripts, or fix bugs by delegating to Claude Code or Codex via acpx.", + summary: "Write code, build projects, create scripts, or fix bugs by delegating to Claude Code or Codex.", content: codeWithAgentsSkill, }, { diff --git a/apps/x/packages/core/src/application/lib/builtin-tools.ts b/apps/x/packages/core/src/application/lib/builtin-tools.ts index a07781e6..8796cb65 100644 --- a/apps/x/packages/core/src/application/lib/builtin-tools.ts +++ b/apps/x/packages/core/src/application/lib/builtin-tools.ts @@ -15,7 +15,6 @@ import { executeAction as executeComposioAction, isConfigured as isComposioConfi import { CURATED_TOOLKITS, CURATED_TOOLKIT_SLUGS } from "@x/shared/dist/composio.js"; import { BrowserControlInputSchema, type BrowserControlInput } from "@x/shared/dist/browser-control.js"; import { BackgroundTaskSchema, TriggersSchema } from "@x/shared/dist/background-task.js"; -import { resolveClaudeExeOnWindows } from "../../code-mode/acp/claude-exec.js"; import type { CodeModeManager } from "../../code-mode/acp/manager.js"; import type { CodePermissionRegistry } from "../../code-mode/acp/permission-registry.js"; import { ICodeModeConfigRepo } from "../../code-mode/repo.js"; @@ -94,14 +93,6 @@ const LLMPARSE_MIME_TYPES: Record = { '.tiff': 'image/tiff', }; -function envForCommand(command: string): NodeJS.ProcessEnv | undefined { - if (process.platform !== 'win32') return undefined; - if (!/\bacpx\b/.test(command)) return undefined; - if (process.env.CLAUDE_CODE_EXECUTABLE) return undefined; - const exe = resolveClaudeExeOnWindows(); - if (!exe) return undefined; - return { ...process.env, CLAUDE_CODE_EXECUTABLE: exe }; -} export const BuiltinTools: z.infer = { loadSkill: { @@ -763,14 +754,11 @@ export const BuiltinTools: z.infer = { // }; // } - const envOverride = envForCommand(command); - // Use abortable version when we have a signal if (ctx?.signal) { const { promise, process: proc } = executeCommandAbortable(command, { cwd: workingDir, signal: ctx.signal, - env: envOverride, onData: (chunk: string) => { ctx.publish({ runId: ctx.runId, @@ -800,7 +788,7 @@ export const BuiltinTools: z.infer = { } // Fallback to original for backward compatibility - const result = await executeCommand(command, { cwd: workingDir, env: envOverride }); + const result = await executeCommand(command, { cwd: workingDir }); return { success: result.exitCode === 0, diff --git a/apps/x/packages/core/src/application/lib/command-executor.ts b/apps/x/packages/core/src/application/lib/command-executor.ts index 6be3c0e6..357ce1a8 100644 --- a/apps/x/packages/core/src/application/lib/command-executor.ts +++ b/apps/x/packages/core/src/application/lib/command-executor.ts @@ -80,7 +80,7 @@ export async function executeCommand( cwd?: string; timeout?: number; // timeout in milliseconds maxBuffer?: number; // max buffer size in bytes - env?: NodeJS.ProcessEnv; // override environment (e.g. CLAUDE_CODE_EXECUTABLE for acpx) + env?: NodeJS.ProcessEnv; // override environment } ): Promise { try { diff --git a/apps/x/packages/core/src/code-mode/acp/claude-exec.ts b/apps/x/packages/core/src/code-mode/acp/claude-exec.ts index 31c7c4e8..ae6c9c51 100644 --- a/apps/x/packages/core/src/code-mode/acp/claude-exec.ts +++ b/apps/x/packages/core/src/code-mode/acp/claude-exec.ts @@ -5,7 +5,7 @@ import { commonInstallPaths } from '../status.js'; // Windows-only: Node refuses to spawn `.cmd` files without `shell: true` (EINVAL), // and the Claude ACP adapter spawns its executable directly. So we pre-resolve -// claude's real `.exe` from the npm-shim layout. Also used by the legacy acpx path. +// claude's real `.exe` from the npm-shim layout. Used by resolveClaudeExecutable below. export function resolveClaudeExeOnWindows(): string | undefined { // Candidate dirs = everything on PATH, plus well-known npm/pnpm/volta global // bin dirs. Electron's runtime PATH can omit these even when the user's shell