Merge pull request #674 from rowboatlabs/code-mode-fixes

Code mode fixes
This commit is contained in:
Ramnique Singh 2026-07-06 14:06:41 +05:30 committed by GitHub
commit 1050614295
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
24 changed files with 686 additions and 259 deletions

View file

@ -13,8 +13,8 @@
"make": "electron-forge make"
},
"dependencies": {
"@agentclientprotocol/claude-agent-acp": "^0.39.0",
"@agentclientprotocol/codex-acp": "^0.0.44",
"@agentclientprotocol/claude-agent-acp": "^0.55.0",
"@agentclientprotocol/codex-acp": "^1.1.0",
"@x/core": "workspace:*",
"@x/shared": "workspace:*",
"agent-slack": "0.9.3",

View file

@ -38,6 +38,7 @@ import type { IOAuthRepo } from '@x/core/dist/auth/repo.js';
import { IGranolaConfigRepo } from '@x/core/dist/knowledge/granola/repo.js';
import { ICodeModeConfigRepo } from '@x/core/dist/code-mode/repo.js';
import { CodePermissionRegistry } from '@x/core/dist/code-mode/acp/permission-registry.js';
import type { CodeRunFeed } from '@x/core/dist/code-mode/feed.js';
import { checkCodeModeAgentStatus } from '@x/core/dist/code-mode/status.js';
import { ensureEngine } from '@x/core/dist/code-mode/acp/engine-provisioner.js';
import type { ICodeProjectsRepo } from '@x/core/dist/code-mode/projects/repo.js';
@ -703,6 +704,25 @@ export function startSessionsWatcher(): void {
sessionsWatcher = sessionBus.subscribe((event) => emitSessionEvent(event));
}
// Ephemeral code-run stream: CodeRunFeed → all renderer windows. A direct
// tool→renderer side-channel that bypasses the turn runtime; the durable
// record is the settle-time code-run-events-batch tool progress.
let codeRunFeedWatcher: (() => void) | null = null;
export function startCodeRunFeedWatcher(): void {
if (codeRunFeedWatcher) {
return;
}
const feed = container.resolve<CodeRunFeed>('codeRunFeed');
codeRunFeedWatcher = feed.subscribe((event) => {
const windows = BrowserWindow.getAllWindows();
for (const win of windows) {
if (!win.isDestroyed() && win.webContents) {
win.webContents.send('codeRun:events', event);
}
}
});
}
// The renderer window is created before the session-index startup scan
// finishes, so an early sessions:list could observe a partially built index
// (the scan runs oldest-first — exactly the newest chats would be missing).

View file

@ -3,6 +3,7 @@ import path from "node:path";
import {
setupIpcHandlers,
startRunsWatcher, startSessionsWatcher, markSessionsIndexReady,
startCodeRunFeedWatcher,
startChannelsWatcher,
startCodeSessionStatusWatcher,
startServicesWatcher,
@ -422,6 +423,7 @@ app.whenReady().then(async () => {
markSessionsIndexReady();
}
startSessionsWatcher();
startCodeRunFeedWatcher();
// Mobile channels (WhatsApp/Telegram bridge): needs the session index, so
// start after initialize(). Failures must never block boot.

View file

@ -1,4 +1,4 @@
import { useMemo, useState } from 'react'
import { useEffect, useMemo, useState } from 'react'
import {
AlertCircle,
CheckCircle2,
@ -19,6 +19,7 @@ import type { CodeRunEvent, PermissionAsk, PermissionDecision } from '@x/shared/
import { cn } from '@/lib/utils'
import { Tool, ToolContent, ToolHeader } from '@/components/ai-elements/tool'
import { getToolErrorText, toToolState, type ToolCall } from '@/lib/chat-conversation'
import { clearCodeRunBuffer, useCodeRunFeed } from '@/lib/code-run-feed'
// ── Timeline reduction ──────────────────────────────────────────────
// The raw ACP stream is a flat list of events; collapse it into ordered rows,
@ -283,12 +284,22 @@ export function CodingRunBlock({
(item.input as { agent?: string } | undefined)?.agent
const title = AGENT_LABEL[agent ?? ''] ?? 'Coding agent'
const error = getToolErrorText(item)
// Timeline source: the durable record (item.codeRunEvents — the settle-time
// batch, or the legacy path's inline accumulation) wins; while it's absent
// the live CodeRunFeed buffer streams the run in real time.
const liveEvents = useCodeRunFeed(item.id)
const durableEvents = item.codeRunEvents
const events = durableEvents?.length ? durableEvents : liveEvents
// Once the durable batch has landed the buffer is redundant — drop it.
useEffect(() => {
if (durableEvents?.length) clearCodeRunBuffer(item.id)
}, [durableEvents?.length, item.id])
return (
<>
<Tool open={open} onOpenChange={onOpenChange}>
<ToolHeader title={title} type="tool-code_agent_run" state={toToolState(item.status)} />
<ToolContent>
<CodingRunTimeline events={item.codeRunEvents ?? []} error={error} />
<CodingRunTimeline events={events} error={error} />
</ToolContent>
</Tool>
{item.pendingCodePermission && (

View file

@ -0,0 +1,52 @@
import { useSyncExternalStore } from 'react'
import type { CodeRunEvent, CodeRunFeedEvent } from '@x/shared/src/code-mode.js'
// Renderer half of the ephemeral CodeRunFeed side-channel: buffers the live
// `codeRun:events` broadcast per toolCallId so tool cards can render a
// code_agent_run's activity while it streams. Module-level (not tied to any
// session store) so the buffer survives session switches mid-run. Nothing here
// is persisted — on settle the durable code-run-events-batch in the turn
// record supersedes the buffer, which is then dropped.
const buffers = new Map<string, CodeRunEvent[]>()
const listeners = new Set<() => void>()
const EMPTY: CodeRunEvent[] = []
// Backstop so abandoned runs can't grow the map forever (a run's buffer is
// normally dropped explicitly once its durable batch lands).
const MAX_TRACKED_RUNS = 32
let attached = false
function ensureAttached(): void {
if (attached) return
attached = true
window.ipc.on('codeRun:events', ((raw: unknown) => {
const { toolCallId, event } = raw as CodeRunFeedEvent
if (!toolCallId || !event) return
if (!buffers.has(toolCallId) && buffers.size >= MAX_TRACKED_RUNS) {
const oldest = buffers.keys().next().value
if (oldest !== undefined) buffers.delete(oldest)
}
// Immutable append: useSyncExternalStore consumers compare by reference.
buffers.set(toolCallId, [...(buffers.get(toolCallId) ?? EMPTY), event])
for (const listener of [...listeners]) listener()
}) as never)
}
function subscribe(onChange: () => void): () => void {
ensureAttached()
listeners.add(onChange)
return () => {
listeners.delete(onChange)
}
}
export function clearCodeRunBuffer(toolCallId: string): void {
if (buffers.delete(toolCallId)) {
for (const listener of [...listeners]) listener()
}
}
// Live events for one code_agent_run tool call, empty once the durable batch
// takes over (or if the buffer never existed — e.g. after an app reload).
export function useCodeRunFeed(toolCallId: string): CodeRunEvent[] {
return useSyncExternalStore(subscribe, () => buffers.get(toolCallId) ?? EMPTY)
}

View file

@ -219,6 +219,88 @@ describe('buildTurnConversation', () => {
expect(items.map((i) => i.status)).toEqual(['error', 'completed'])
})
it('derives the code-run timeline from the settle-time batch and asks from request events', () => {
const codeProgress = (progress: unknown): TEvent => ({
type: 'tool_progress',
turnId: T1,
ts: TS,
toolCallId: 'cr1',
source: 'sync',
progress: progress as never,
})
const state = reduceTurn([
created(T1, S1),
requested(T1, 0),
completed(T1, 0, assistantCalls(toolCallPart('cr1', 'code_agent_run', { agent: 'codex' }))),
invocation(T1, 'cr1', 'code_agent_run'),
codeProgress({
kind: 'code-run-permission-request',
requestId: 'cpr-1',
ask: { toolCallId: 'x', title: 'write file', options: [] },
}),
codeProgress({
kind: 'code-run-events',
events: [
{ type: 'message', role: 'agent', text: 'hi' },
{ type: 'tool_call', id: 'x', title: 'write file' },
],
}),
])
const tool = buildTurnConversation(state).filter(isToolCall)[0]
expect(tool.status).toBe('running')
expect(tool.codeRunEvents?.map((e) => e.type)).toEqual(['message', 'tool_call'])
expect(tool.pendingCodePermission?.requestId).toBe('cpr-1')
})
it('clears the pending code permission on the resolved marker and on tool result', () => {
const codeProgress = (toolCallId: string, progress: unknown): TEvent => ({
type: 'tool_progress',
turnId: T1,
ts: TS,
toolCallId,
source: 'sync',
progress: progress as never,
})
const ask = { toolCallId: 'x', title: 'write file', options: [] }
// resolved: the durable marker pairs off the request mid-run
const resolvedState = reduceTurn([
created(T1, S1),
requested(T1, 0),
completed(T1, 0, assistantCalls(toolCallPart('cr1', 'code_agent_run'))),
invocation(T1, 'cr1', 'code_agent_run'),
codeProgress('cr1', { kind: 'code-run-permission-request', requestId: 'cpr-1', ask }),
codeProgress('cr1', { kind: 'code-run-permission-resolved' }),
])
const resolved = buildTurnConversation(resolvedState).filter(isToolCall)[0]
expect(resolved.pendingCodePermission).toBeUndefined()
// a second ask after the first resolution is pending again
const secondAskState = reduceTurn([
created(T1, S1),
requested(T1, 0),
completed(T1, 0, assistantCalls(toolCallPart('cr1', 'code_agent_run'))),
invocation(T1, 'cr1', 'code_agent_run'),
codeProgress('cr1', { kind: 'code-run-permission-request', requestId: 'cpr-1', ask }),
codeProgress('cr1', { kind: 'code-run-permission-resolved' }),
codeProgress('cr1', { kind: 'code-run-permission-request', requestId: 'cpr-2', ask }),
])
const secondAsk = buildTurnConversation(secondAskState).filter(isToolCall)[0]
expect(secondAsk.pendingCodePermission?.requestId).toBe('cpr-2')
// settled: an unanswered ask must not survive the tool's terminal result
const settledState = reduceTurn([
created(T1, S1),
requested(T1, 0),
completed(T1, 0, assistantCalls(toolCallPart('cr2', 'code_agent_run'))),
invocation(T1, 'cr2', 'code_agent_run'),
codeProgress('cr2', { kind: 'code-run-permission-request', requestId: 'cpr-2', ask }),
toolResult(T1, 'cr2', 'code_agent_run', { success: false, stopReason: 'cancelled' }),
])
const settled = buildTurnConversation(settledState).filter(isToolCall)[0]
expect(settled.pendingCodePermission).toBeUndefined()
expect(settled.status).toBe('completed')
})
it('renders user attachments and a failed turn as an error item', () => {
const input = {
role: 'user' as const,

View file

@ -13,6 +13,7 @@ import {
type TurnState,
type TurnStreamEvent,
} from '@x/shared/src/turns.js'
import type { CodeRunEvent, PermissionAsk } from '@x/shared/src/code-mode.js'
import type {
ChatMessage,
ConversationItem,
@ -205,6 +206,41 @@ function toolStatus(tc: ToolCallState): ToolCall['status'] {
return 'running'
}
// code_agent_run's durable trail in tool_progress (see the publish bridge in
// real-tool-registry.ts): ONE settle-time 'code-run-events' batch carrying the
// whole timeline (the live per-event stream travels over the ephemeral
// CodeRunFeed and never reaches turn state), plus per-ask
// 'code-run-permission-request' / 'code-run-permission-resolved' pairs. An ask
// is pending while requests outnumber resolutions and the tool hasn't settled.
function codeRunViewOf(
tc: ToolCallState,
): Pick<ToolCall, 'codeRunEvents' | 'pendingCodePermission'> {
let events: CodeRunEvent[] | undefined
let pending: { requestId: string; ask: PermissionAsk } | null = null
let unresolved = 0
for (const p of tc.progress) {
const entry = p.progress
if (!entry || typeof entry !== 'object' || Array.isArray(entry)) continue
const kind = (entry as { kind?: unknown }).kind
if (kind === 'code-run-events') {
const batch = (entry as { events?: unknown }).events
if (Array.isArray(batch)) events = batch as CodeRunEvent[]
} else if (kind === 'code-run-permission-request') {
const { requestId, ask } = entry as { requestId?: unknown; ask?: unknown }
if (typeof requestId === 'string' && ask) {
pending = { requestId, ask: ask as PermissionAsk }
unresolved += 1
}
} else if (kind === 'code-run-permission-resolved') {
unresolved -= 1
}
}
return {
...(events && events.length > 0 ? { codeRunEvents: events } : {}),
...(pending && unresolved > 0 && !tc.result ? { pendingCodePermission: pending } : {}),
}
}
// One turn's contribution to the conversation: the user input, then per
// completed model call its text and tool calls (with live status/results).
export function buildTurnConversation(state: TurnState): ConversationItem[] {
@ -258,6 +294,7 @@ export function buildTurnConversation(state: TurnState): ConversationItem[] {
...(tc?.result ? { result: tc.result.result.output as ToolCall['result'] } : {}),
status: tc ? toolStatus(tc) : 'running',
timestamp: ts(),
...(tc ? codeRunViewOf(tc) : {}),
} satisfies ToolCall)
}
}

View file

@ -13,9 +13,9 @@
"inspect": "node dist/turns/inspect-cli.js"
},
"dependencies": {
"@agentclientprotocol/claude-agent-acp": "^0.39.0",
"@agentclientprotocol/codex-acp": "^0.0.44",
"@agentclientprotocol/sdk": "^0.22.1",
"@agentclientprotocol/claude-agent-acp": "^0.55.0",
"@agentclientprotocol/codex-acp": "^1.1.0",
"@agentclientprotocol/sdk": "^1.1.0",
"@ai-sdk/anthropic": "^2.0.63",
"@ai-sdk/google": "^2.0.53",
"@ai-sdk/openai": "^2.0.91",

View file

@ -1,28 +1,42 @@
import * as os from "os";
import { afterEach, describe, expect, it, vi } from "vitest";
import type { CodeRunEvent } from "@x/shared/dist/code-mode.js";
import container from "../../di/container.js";
import { InMemoryAbortRegistry } from "../../runs/abort-registry.js";
import { BuiltinTools } from "./builtin-tools.js";
import { BuiltinTools, coalesceCodeRunEvents } from "./builtin-tools.js";
import type { ToolContext } from "./exec-tool.js";
function context(signal: AbortSignal): ToolContext {
// A real directory: code_agent_run validates the cwd exists before spawning.
const CWD = os.tmpdir();
function context(signal: AbortSignal, published: unknown[] = []): ToolContext {
return {
runId: "turn-1",
toolCallId: "tool-1",
signal,
abortRegistry: new InMemoryAbortRegistry(),
publish: async () => {},
publish: async (event) => {
published.push(event);
},
codePolicy: "ask",
};
}
function mockCodeServices(runPrompt: () => Promise<never>): void {
function mockCodeServices(
runPrompt: (opts: { onEvent: (event: CodeRunEvent) => void }) => Promise<unknown>,
): { feedEvents: unknown[] } {
const feedEvents: unknown[] = [];
vi.spyOn(container, "resolve").mockImplementation(((name: string) => {
if (name === "codeModeManager") return { runPrompt };
if (name === "codePermissionRegistry") {
return { cancelRun: vi.fn(), request: vi.fn() };
}
if (name === "codeRunFeed") {
return { broadcast: (event: unknown) => feedEvents.push(event) };
}
throw new Error(`Unexpected dependency: ${name}`);
}) as typeof container.resolve);
return { feedEvents };
}
describe("code_agent_run", () => {
@ -34,11 +48,22 @@ describe("code_agent_run", () => {
});
await expect(BuiltinTools.code_agent_run.execute(
{ agent: "codex", cwd: "/repo", prompt: "Fix it" },
{ agent: "codex", cwd: CWD, prompt: "Fix it" },
context(new AbortController().signal),
)).rejects.toThrow("Coding agent failed: spawn Electron ENOENT");
});
it("rejects a working directory that does not exist with a clear error", async () => {
mockCodeServices(async () => {
throw new Error("unreachable");
});
await expect(BuiltinTools.code_agent_run.execute(
{ agent: "codex", cwd: "/nonexistent-dir-for-test", prompt: "Fix it" },
context(new AbortController().signal),
)).rejects.toThrow("working directory does not exist");
});
it("returns an ordinary cancellation result when the turn was aborted", async () => {
const controller = new AbortController();
controller.abort();
@ -47,8 +72,81 @@ describe("code_agent_run", () => {
});
await expect(BuiltinTools.code_agent_run.execute(
{ agent: "codex", cwd: "/repo", prompt: "Fix it" },
{ agent: "codex", cwd: CWD, prompt: "Fix it" },
context(controller.signal),
)).resolves.toMatchObject({ success: false, stopReason: "cancelled" });
});
it("broadcasts events on the feed live and publishes ONE coalesced durable batch", async () => {
const { feedEvents } = mockCodeServices(async ({ onEvent }) => {
onEvent({ type: "message", role: "agent", text: "hel" });
onEvent({ type: "message", role: "agent", text: "lo" });
onEvent({ type: "tool_call", id: "x", title: "write file" });
return { stopReason: "end_turn", sessionId: "s1" };
});
const published: unknown[] = [];
const result = await BuiltinTools.code_agent_run.execute(
{ agent: "codex", cwd: CWD, prompt: "Fix it" },
context(new AbortController().signal, published),
);
expect(result).toMatchObject({ success: true, summary: "hello" });
// Live side-channel: every event, verbatim, keyed by the tool call.
expect(feedEvents).toHaveLength(3);
expect(feedEvents[0]).toMatchObject({
toolCallId: "tool-1",
event: { type: "message", text: "hel" },
});
// Durable: per-event publishes for the legacy bus + exactly one batch,
// with consecutive same-role message chunks coalesced.
const batches = published.filter(
(e) => (e as { type?: string }).type === "code-run-events-batch",
);
expect(batches).toHaveLength(1);
expect((batches[0] as { events: CodeRunEvent[] }).events).toEqual([
{ type: "message", role: "agent", text: "hello" },
{ type: "tool_call", id: "x", title: "write file" },
]);
});
it("publishes the partial batch even when the run fails", async () => {
mockCodeServices(async ({ onEvent }) => {
onEvent({ type: "message", role: "agent", text: "started..." });
throw new Error("engine crashed");
});
const published: unknown[] = [];
await expect(BuiltinTools.code_agent_run.execute(
{ agent: "codex", cwd: CWD, prompt: "Fix it" },
context(new AbortController().signal, published),
)).rejects.toThrow("Coding agent failed");
const batches = published.filter(
(e) => (e as { type?: string }).type === "code-run-events-batch",
);
expect(batches).toHaveLength(1);
});
});
describe("coalesceCodeRunEvents", () => {
it("merges consecutive same-role message chunks and keeps everything else in order", () => {
const events: CodeRunEvent[] = [
{ type: "message", role: "agent", text: "a" },
{ type: "message", role: "agent", text: "b" },
{ type: "tool_call", id: "t1", title: "run" },
{ type: "message", role: "agent", text: "c" },
{ type: "message", role: "user", text: "d" },
{ type: "message", role: "user", text: "e" },
];
expect(coalesceCodeRunEvents(events)).toEqual([
{ type: "message", role: "agent", text: "ab" },
{ type: "tool_call", id: "t1", title: "run" },
{ type: "message", role: "agent", text: "c" },
{ type: "message", role: "user", text: "de" },
]);
});
it("returns an empty list unchanged", () => {
expect(coalesceCodeRunEvents([])).toEqual([]);
});
});

View file

@ -20,7 +20,8 @@ import { BackgroundTaskSchema, TriggersSchema } from "@x/shared/dist/background-
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";
import type { ApprovalPolicy } from "@x/shared/dist/code-mode.js";
import type { ApprovalPolicy, CodeRunEvent as CodeRunEventType } from "@x/shared/dist/code-mode.js";
import type { CodeRunFeed } from "../../code-mode/feed.js";
import type { ICodeProjectsRepo } from "../../code-mode/projects/repo.js";
import * as gitService from "../../code-mode/git/service.js";
import { listImportantThreads, searchThreads } from "../../knowledge/sync_gmail.js";
@ -68,6 +69,27 @@ function expandHome(p: string): string {
return t;
}
// Shrink a code-run timeline for durable storage: consecutive same-role message
// chunks merge into one event. Display-lossless — the timeline renderer
// concatenates consecutive messages anyway (CodingRunTimeline) — and typically
// collapses the ~90% of a run's events that are per-token text deltas.
// Everything else (tool calls/updates, plans, permissions) is kept verbatim in
// order: updates are id-keyed transitions and must not be merged.
export function coalesceCodeRunEvents(events: CodeRunEventType[]): CodeRunEventType[] {
const out: CodeRunEventType[] = [];
for (const event of events) {
const last = out[out.length - 1];
if (
event.type === 'message' && last?.type === 'message' && last.role === event.role
) {
out[out.length - 1] = { ...last, text: last.text + event.text };
} else {
out.push(event);
}
}
return out;
}
async function resolveCodeProject(dirPath: string): Promise<
{ ok: true; projectId: string; path: string; warning?: string } | { ok: false; error: string }
> {
@ -876,8 +898,19 @@ export const BuiltinTools: z.infer<typeof BuiltinToolsSchema> = {
// chip change. Honor the chip so switching it deterministically switches agents.
const effectiveAgent = ctx.codeMode ?? agent;
// Code-section sessions pin the working directory — never trust the model's
// cwd argument over the session's.
const effectiveCwd = ctx.codeCwd ?? cwd;
// cwd argument over the session's. Expand `~` and resolve to an absolute path:
// the engine is spawned with this as the child's cwd, and `child_process.spawn`
// does NO shell tilde expansion.
const effectiveCwd = path.resolve(expandHome(ctx.codeCwd ?? cwd));
// Fail loudly if the directory is missing. Otherwise the spawn below fails with
// Node's misleading "spawn <command> ENOENT" (it blames the executable, not the
// bad cwd), which reads as "the coding engine isn't installed" — see the enriched
// message the model surfaces. A clear error lets the model/user fix the path.
try {
if (!(await fs.stat(effectiveCwd)).isDirectory()) throw new Error('not a directory');
} catch {
throw new Error(`code_agent_run: working directory does not exist: ${effectiveCwd}`);
}
const manager = container.resolve<CodeModeManager>('codeModeManager');
const registry = container.resolve<CodePermissionRegistry>('codePermissionRegistry');
@ -905,6 +938,10 @@ export const BuiltinTools: z.infer<typeof BuiltinToolsSchema> = {
let finalText = '';
const changedFiles = new Set<string>();
// The full ordered timeline, published ONCE as a durable batch when the
// run settles (see finally). The per-event copies below are ephemeral.
const collected: CodeRunEventType[] = [];
const feed = container.resolve<CodeRunFeed>('codeRunFeed');
try {
const result = await manager.runPrompt({
runId: ctx.runId,
@ -916,6 +953,11 @@ export const BuiltinTools: z.infer<typeof BuiltinToolsSchema> = {
onEvent: (event) => {
if (event.type === 'message' && event.role === 'agent') finalText += event.text;
if (event.type === 'tool_call_update') for (const f of event.diffs) changedFiles.add(f);
collected.push(event);
// Live rendering, two transports: the CodeRunFeed side-channel
// (turns-runtime chats — the runtime never sees this traffic)
// and the legacy runs bus (code-section tabs). Both ephemeral.
feed.broadcast({ toolCallId: ctx.toolCallId, event });
void ctx.publish({
runId: ctx.runId,
type: 'code-run-event',
@ -958,6 +1000,23 @@ export const BuiltinTools: z.infer<typeof BuiltinToolsSchema> = {
throw new Error(`Coding agent failed: ${error instanceof Error ? error.message : String(error)}`);
} finally {
ctx.signal.removeEventListener('abort', onAbort);
// Durable record for replay-on-reload — one event with the whole
// (coalesced) timeline, on every settle path including errors and
// cancellation, so partial runs keep their history too.
if (collected.length > 0) {
await ctx.publish({
runId: ctx.runId,
type: 'code-run-events-batch',
toolCallId: ctx.toolCallId,
events: coalesceCodeRunEvents(collected),
subflow: [],
}).catch((e: unknown) => {
// History is best-effort (rethrowing here would mask the run's
// real outcome) — but a lost timeline must leave a trail, since
// this batch is the only durable record of the run's activity.
console.warn(`[code_agent_run] failed to persist code-run timeline: ${e instanceof Error ? e.message : String(e)}`);
});
}
}
},
},

View file

@ -275,8 +275,11 @@ export class AcpClient {
// Point the open session at a specific model. The adapter resolves aliases
// ("opus"/"sonnet"/…) to concrete ids. Throws if the model is unknown; the
// caller applies this best-effort so a bad value never blocks a turn.
// ACP 1.x folded model selection into the generic config-option system (the
// 'model' category), so this goes through setSessionConfigOption just like
// effort does — matching the id extractModelOptions reads.
async setModel(sessionId: string, modelId: string): Promise<void> {
await this.conn().unstable_setSessionModel({ sessionId, modelId });
await this.conn().setSessionConfigOption({ sessionId, configId: 'model', value: modelId });
}
// Set the reasoning-effort level via the agent's "effort" config option.

View file

@ -4,96 +4,96 @@
export const ENGINE_MANIFEST = {
"claude": {
"version": "0.3.156",
"version": "0.3.198",
"platforms": {
"darwin-arm64": {
"pkg": "@anthropic-ai/claude-agent-sdk-darwin-arm64",
"pkgVersion": "0.3.156",
"tarball": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-darwin-arm64/-/claude-agent-sdk-darwin-arm64-0.3.156.tgz",
"integrity": "sha512-IkjcS9dqAUlD4Nb62L9AZtmAXCa+FV4ul8lIlyXXUprh3nlecbKsWOXVd/GORrzAhMmynJaX4+iV1JiutFKXUA=="
"pkgVersion": "0.3.198",
"tarball": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-darwin-arm64/-/claude-agent-sdk-darwin-arm64-0.3.198.tgz",
"integrity": "sha512-ZmiAybQKIKcP1qEAE/vfXvfxtKxG9CnJn98QTXC5Zxiwuy7Mllx2ALXh9dfmsf0V87CGEodlZQmMgUJotNIsUw=="
},
"darwin-x64": {
"pkg": "@anthropic-ai/claude-agent-sdk-darwin-x64",
"pkgVersion": "0.3.156",
"tarball": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-darwin-x64/-/claude-agent-sdk-darwin-x64-0.3.156.tgz",
"integrity": "sha512-6PKi5fPmGRuzXu+Em/iwLmPG3mqg0hl92wcTU8fmChqyNtxhxsjCw7LTbdFqp/05o5NeZVVV4k3p7YUv5IFD6g=="
"pkgVersion": "0.3.198",
"tarball": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-darwin-x64/-/claude-agent-sdk-darwin-x64-0.3.198.tgz",
"integrity": "sha512-XwH5vgN46WSwg8aC1OagNofnJpV/G1ciEu118GEKer8ZhVkq/dvK/DqShxMkb6r1jV7u5IJ7zPXu9uKliyNJAw=="
},
"linux-x64": {
"pkg": "@anthropic-ai/claude-agent-sdk-linux-x64",
"pkgVersion": "0.3.156",
"tarball": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-linux-x64/-/claude-agent-sdk-linux-x64-0.3.156.tgz",
"integrity": "sha512-ymhrdlbWoYvTACUdaGdhrEv+ZMfwXLsf0BRLkr/IvY5aqybP7URzWmmZGOtDQpqkT/8xu/UCGqUYH3woJwUxfg=="
"pkgVersion": "0.3.198",
"tarball": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-linux-x64/-/claude-agent-sdk-linux-x64-0.3.198.tgz",
"integrity": "sha512-Zqxyz2AT1UM5WlOOoLJhLssZDgZo8rBK5ku6daveK12zp+UTJGZhGsjFghz1/ASxH08KqOTbUePNTORnPhHAEQ=="
},
"linux-arm64": {
"pkg": "@anthropic-ai/claude-agent-sdk-linux-arm64",
"pkgVersion": "0.3.156",
"tarball": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-linux-arm64/-/claude-agent-sdk-linux-arm64-0.3.156.tgz",
"integrity": "sha512-H0Nfd41iw5isto9uQI1FlVSZ0eaDttr8rBpJMR25oK/mj3egMO5EmZ6aAxeeUYSLn2mSU50HA5VNxlGUE118TQ=="
"pkgVersion": "0.3.198",
"tarball": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-linux-arm64/-/claude-agent-sdk-linux-arm64-0.3.198.tgz",
"integrity": "sha512-qmz8dxEtDIlKntU5qYe0R4aWTxTue5S7zIQknatLX7aJ6HN/nq1aCNXWn5smTH2FViBkUPPR+sCIsNwSk6AT6Q=="
},
"linux-x64-musl": {
"pkg": "@anthropic-ai/claude-agent-sdk-linux-x64-musl",
"pkgVersion": "0.3.156",
"tarball": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-linux-x64-musl/-/claude-agent-sdk-linux-x64-musl-0.3.156.tgz",
"integrity": "sha512-/Q6WUizI6a+hqZZ6ElwRU0PEuFhOoN4v6CuU35HHbiZ/7uaocGht4A8ZIgK1Fw6wOGtZzGLbc00CA1OU1Zg8EA=="
"pkgVersion": "0.3.198",
"tarball": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-linux-x64-musl/-/claude-agent-sdk-linux-x64-musl-0.3.198.tgz",
"integrity": "sha512-h1SrWVIMjLInYNPlf+TxXuKTOdoiOfJLBSoQG97315Z2Nh0IpBfqWExlqYTtPCgKE7q2iga31U283QfHpIDlSQ=="
},
"linux-arm64-musl": {
"pkg": "@anthropic-ai/claude-agent-sdk-linux-arm64-musl",
"pkgVersion": "0.3.156",
"tarball": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-linux-arm64-musl/-/claude-agent-sdk-linux-arm64-musl-0.3.156.tgz",
"integrity": "sha512-R7KEVjxkR4rYgIQoHGBzwPdUJYxRTO8I4vHjRbMLH1eW4FS7BJvVs7ogfKR/NnHFBvMVqtC+l6jHLQv8bobUiw=="
"pkgVersion": "0.3.198",
"tarball": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-linux-arm64-musl/-/claude-agent-sdk-linux-arm64-musl-0.3.198.tgz",
"integrity": "sha512-Q7lKVNjIrUQ2B/AR77OvRf0zeOdEjonFVaR9FYrrwtzGeEqum69WSht5nM7Y7el3wjbNi0/eV0QTUM0DlsTEfw=="
},
"win32-x64": {
"pkg": "@anthropic-ai/claude-agent-sdk-win32-x64",
"pkgVersion": "0.3.156",
"tarball": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-win32-x64/-/claude-agent-sdk-win32-x64-0.3.156.tgz",
"integrity": "sha512-/PofeTWoiKgnWNSNk0wG4SsRn22GGLmnLhg2R94WcNhCRFOyOTmiZcYH2DBlWZBIRVTZDsSfa/Pl1DyPvYCGKw=="
"pkgVersion": "0.3.198",
"tarball": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-win32-x64/-/claude-agent-sdk-win32-x64-0.3.198.tgz",
"integrity": "sha512-y3HLuCCz1kDwUrhd6OnqO+d5BUpTFSzNUsPT9kf3r1vk9HYKF+eMC9eIlcOhiW2kX491kxEvuEOfqgIkGx15cg=="
},
"win32-arm64": {
"pkg": "@anthropic-ai/claude-agent-sdk-win32-arm64",
"pkgVersion": "0.3.156",
"tarball": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-win32-arm64/-/claude-agent-sdk-win32-arm64-0.3.156.tgz",
"integrity": "sha512-5sAeNObQQrMy4NF9HwxewrMnU7mVxZDHh+/MfJVQSz0GSTvXQ6gOuRH8helMlfspoU6VOdekPxVLRooX/3foEw=="
"pkgVersion": "0.3.198",
"tarball": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-win32-arm64/-/claude-agent-sdk-win32-arm64-0.3.198.tgz",
"integrity": "sha512-mjIHf1HFiRuXefewWTaNZFlTZlCaEt/xsRjc1nSTCEEpFolZayVhrDKz+O2QFVcDtPl8x8GeYSL0kiikg1DZjQ=="
}
}
},
"codex": {
"version": "0.128.0",
"version": "0.142.5",
"platforms": {
"darwin-arm64": {
"pkg": "@openai/codex",
"pkgVersion": "0.128.0-darwin-arm64",
"tarball": "https://registry.npmjs.org/@openai/codex/-/codex-0.128.0-darwin-arm64.tgz",
"integrity": "sha512-w+6zohfHx/kHBdles/CyFKaY57u9I3nK8QI9+NrdwMliKA0b7xn13yblRNkMpe09j6vL1oAWoxYsMOQ/vjBGug=="
"pkgVersion": "0.142.5-darwin-arm64",
"tarball": "https://registry.npmjs.org/@openai/codex/-/codex-0.142.5-darwin-arm64.tgz",
"integrity": "sha512-l43p8xv+Z/2/b6fCUc7/FmcQZsaPB7RFizLponGwHAnFOWe3i9Vky69p+up3BUam9AetoQQUv7Mo+2KdaFEqhA=="
},
"darwin-x64": {
"pkg": "@openai/codex",
"pkgVersion": "0.128.0-darwin-x64",
"tarball": "https://registry.npmjs.org/@openai/codex/-/codex-0.128.0-darwin-x64.tgz",
"integrity": "sha512-SDbn6fO22Puy8xmMIbZi4f2znMrUEPwABApke4mo+4ihaauwuVjeqzXvW5SPJz5ty/bG11/mSupQgReT7T8BBw=="
"pkgVersion": "0.142.5-darwin-x64",
"tarball": "https://registry.npmjs.org/@openai/codex/-/codex-0.142.5-darwin-x64.tgz",
"integrity": "sha512-yk6A06/VmW7NFsa48OVPaj//g/zeSpd79wjuqfXZwW8ZKRYQm3+wCd3hWjPl79F3QnXvDvM2j3JMIBL3m3GXXg=="
},
"linux-x64": {
"pkg": "@openai/codex",
"pkgVersion": "0.128.0-linux-x64",
"tarball": "https://registry.npmjs.org/@openai/codex/-/codex-0.128.0-linux-x64.tgz",
"integrity": "sha512-2lnSPA05CRRuKAzFW8BCmmNCSieDcToLwfC2ALLbBYilGLgzhRibjlDglK9F1BkEzfohSSWJu4PBbRu/aG60lQ=="
"pkgVersion": "0.142.5-linux-x64",
"tarball": "https://registry.npmjs.org/@openai/codex/-/codex-0.142.5-linux-x64.tgz",
"integrity": "sha512-pxY+d3NgNE57Y/MApD3/TZUAygxJN6I9h3ZeDUwe67mxWjUxsuapxMRFTKSznCalYbRAeZp752+AAXmUbmguEg=="
},
"linux-arm64": {
"pkg": "@openai/codex",
"pkgVersion": "0.128.0-linux-arm64",
"tarball": "https://registry.npmjs.org/@openai/codex/-/codex-0.128.0-linux-arm64.tgz",
"integrity": "sha512-+SvH73H60qvCXFuQGP/EsmR//s1hHMBR22PvJkXvM/hdnTIGucx+JqRUjAWdmmQ1IU6j3kgwVvdLW/6ICB+M6w=="
"pkgVersion": "0.142.5-linux-arm64",
"tarball": "https://registry.npmjs.org/@openai/codex/-/codex-0.142.5-linux-arm64.tgz",
"integrity": "sha512-77ka5PSnm5HdxdBT99IwntCasmbqevlS0eiC0AtEb6ZXCLkim2gm0AWm+jNYy0EhbssvNK+KghayWo34HMgXeA=="
},
"win32-x64": {
"pkg": "@openai/codex",
"pkgVersion": "0.128.0-win32-x64",
"tarball": "https://registry.npmjs.org/@openai/codex/-/codex-0.128.0-win32-x64.tgz",
"integrity": "sha512-k3jmUAFrzkUtvjGTXvSKjQqJLLlzjxp/VoHJDYedgmXUn6j70HxK38IwapzmnYfiBiTuzETvGwjXHzZgzKjhoQ=="
"pkgVersion": "0.142.5-win32-x64",
"tarball": "https://registry.npmjs.org/@openai/codex/-/codex-0.142.5-win32-x64.tgz",
"integrity": "sha512-a+wI4PEx9a2fg6V5ueTTDkOkr1XpEvA5RFXIbo/L2hOfzMmGtyRnbG24bCGu5Q2RSgVxSQV0aLkdb3vdYMNH9A=="
},
"win32-arm64": {
"pkg": "@openai/codex",
"pkgVersion": "0.128.0-win32-arm64",
"tarball": "https://registry.npmjs.org/@openai/codex/-/codex-0.128.0-win32-arm64.tgz",
"integrity": "sha512-ECJvsqmYFdA9pn42xxK3Odp/G16AjmBW0BglX8L0PwPjqbstbmlew9bfHf7xvL+SNfNl4NmyotW0+RNo1phgaA=="
"pkgVersion": "0.142.5-win32-arm64",
"tarball": "https://registry.npmjs.org/@openai/codex/-/codex-0.142.5-win32-arm64.tgz",
"integrity": "sha512-65BEqGbUZ7r0ayunIHdBjo5crwgbwKX/6puOcO+VCswUw/dXvDsN2IGcbXB52+bS9U5+FxP783cUHfTT6m40DQ=="
}
}
}

View file

@ -89,13 +89,16 @@ function locateExecutable(agent: CodingAgent, root: string): string | null {
}
return null;
}
// codex: vendor/<target-triple>/codex/codex[.exe]
// codex ships its native binary under vendor/<target-triple>/. The containing
// subdir moved from `codex/` (≤0.128) to `bin/` (≥0.142), so probe both.
const vendor = path.join(root, 'vendor');
if (!fs.existsSync(vendor)) return null;
for (const triple of fs.readdirSync(vendor)) {
for (const name of ['codex', 'codex.exe']) {
const p = path.join(vendor, triple, 'codex', name);
if (fs.existsSync(p)) return p;
for (const sub of ['bin', 'codex']) {
for (const name of ['codex', 'codex.exe']) {
const p = path.join(vendor, triple, sub, name);
if (fs.existsSync(p)) return p;
}
}
}
return null;
@ -224,8 +227,11 @@ function makeExecutable(agent: CodingAgent, root: string, exe: string): void {
if (agent === 'codex') {
const vendor = path.join(root, 'vendor');
for (const triple of fs.existsSync(vendor) ? fs.readdirSync(vendor) : []) {
const rg = path.join(vendor, triple, 'path', 'rg');
if (fs.existsSync(rg)) fs.chmodSync(rg, 0o755);
// Bundled ripgrep moved from `path/` (≤0.128) to `codex-path/` (≥0.142).
for (const sub of ['codex-path', 'path']) {
const rg = path.join(vendor, triple, sub, 'rg');
if (fs.existsSync(rg)) fs.chmodSync(rg, 0o755);
}
}
}
}

View file

@ -0,0 +1,32 @@
import type { CodeRunFeedEvent } from '@x/shared/dist/code-mode.js';
// Ephemeral side-channel for code_agent_run's live ACP stream — a direct
// tool-implementation → renderer contract that deliberately bypasses the turn
// runtime. The stream is chatty (per-chunk agent messages, tool status
// updates) and only ever renders inside one tool card, so persisting each
// event as durable turn progress bloats the turn log for no benefit. Instead:
// - live: the tool broadcasts here; main forwards over `codeRun:events`
// (see apps/main ipc.ts) and the renderer buffers per toolCallId.
// - durable: ONE code-run-events-batch is published when the run settles,
// so reloads replay the full timeline from the turn record.
// Fire-and-forget: no subscribers ⇒ events vanish, which is the point.
export class CodeRunFeed {
private readonly listeners = new Set<(event: CodeRunFeedEvent) => void>();
broadcast(event: CodeRunFeedEvent): void {
for (const listener of [...this.listeners]) {
try {
listener(event);
} catch {
// A broken subscriber must not stall the coding turn.
}
}
}
subscribe(listener: (event: CodeRunFeedEvent) => void): () => void {
this.listeners.add(listener);
return () => {
this.listeners.delete(listener);
};
}
}

View file

@ -21,6 +21,7 @@ import { FSSlackConfigRepo, ISlackConfigRepo } from "../slack/repo.js";
import { FSChannelsConfigRepo, IChannelsConfigRepo } from "../channels/repo.js";
import { CodeModeManager } from "../code-mode/acp/manager.js";
import { CodePermissionRegistry } from "../code-mode/acp/permission-registry.js";
import { CodeRunFeed } from "../code-mode/feed.js";
import { FSCodeProjectsRepo, ICodeProjectsRepo } from "../code-mode/projects/repo.js";
import { FSCodeSessionsRepo, ICodeSessionsRepo } from "../code-mode/sessions/repo.js";
import { CodeSessionService } from "../code-mode/sessions/service.js";
@ -98,6 +99,9 @@ container.register({
// session/load); the registry brokers mid-run approvals.
codeModeManager: asClass(CodeModeManager).singleton(),
codePermissionRegistry: asClass(CodePermissionRegistry).singleton(),
// Ephemeral live stream for code_agent_run (renderer side-channel; the
// durable record is the settle-time code-run-events-batch).
codeRunFeed: asClass(CodeRunFeed).singleton(),
// Code section: project registry, session metadata, the direct-drive
// session service, and the live status tracker.

View file

@ -125,6 +125,59 @@ describe("RealToolRegistry", () => {
expect(ctx.progress).toEqual([{ kind: "tool-output", chunk: "chunk-1" }]);
});
it("keeps code-run durability to permission asks/resolutions and the settle batch", async () => {
const chunk = { type: "message", role: "agent", text: "hi" } as const;
const resolution = {
type: "permission",
ask: { toolCallId: "x", title: "write file", options: [] },
decision: "allow_once",
auto: false,
} as const;
const ask = { toolCallId: "x", title: "write file", options: [] };
const { registry } = makeRegistry(async ({ ctx }) => {
// Chatty stream events are ephemeral (CodeRunFeed) — NOT progress.
await ctx.publish({
runId: "turn-1",
type: "code-run-event",
toolCallId: "tc-1",
event: chunk,
subflow: [],
});
await ctx.publish({
runId: "turn-1",
type: "code-run-permission-request",
toolCallId: "tc-1",
requestId: "cpr-1",
ask,
subflow: [],
});
// A permission resolution in the stream leaves a durable marker.
await ctx.publish({
runId: "turn-1",
type: "code-run-event",
toolCallId: "tc-1",
event: resolution,
subflow: [],
});
await ctx.publish({
runId: "turn-1",
type: "code-run-events-batch",
toolCallId: "tc-1",
events: [chunk, resolution],
subflow: [],
});
return "done";
});
const tool = (await registry.resolve(descriptor())) as SyncRuntimeTool;
const ctx = makeCtx();
await tool.execute({}, ctx);
expect(ctx.progress).toEqual([
{ kind: "code-run-permission-request", requestId: "cpr-1", ask },
{ kind: "code-run-permission-resolved" },
{ kind: "code-run-events", events: [chunk, resolution] },
]);
});
it("wires the abort signal to the registry's force-kill path", async () => {
const controller = new AbortController();
const { registry, abortRegistry } = makeRegistry(async () => {

View file

@ -108,6 +108,35 @@ export class RealToolRegistry implements IToolRegistry {
kind: "tool-output",
chunk: event.output,
});
} else if (event.type === "code-run-event") {
// The live per-event stream travels over the
// ephemeral CodeRunFeed (never persisted) — but a
// permission RESOLUTION is durably marked so an
// answered ask never resurrects as a pending card
// after a reload or session switch.
if (event.event.type === "permission") {
await ctx.reportProgress({
kind: "code-run-permission-resolved",
});
}
} else if (event.type === "code-run-permission-request") {
// Durable (not feed-ephemeral): the coding turn is
// BLOCKED until the user answers via
// codeRun:resolvePermission, so the ask must survive
// session switches — dropping it would hang the turn
// under policy 'ask' with no card to answer.
await ctx.reportProgress({
kind: "code-run-permission-request",
requestId: event.requestId,
ask: toJsonValue(event.ask),
});
} else if (event.type === "code-run-events-batch") {
// Settle-time durable record of the whole timeline —
// what reloads replay instead of the live feed.
await ctx.reportProgress({
kind: "code-run-events",
events: toJsonValue(event.events),
});
}
},
},

View file

@ -73,3 +73,11 @@ export const RunPromptResult = z.object({
sessionId: z.string(),
});
export type RunPromptResult = z.infer<typeof RunPromptResult>;
// One item on the ephemeral CodeRunFeed (`codeRun:events` broadcast): a live
// code-run event tagged with the tool call it belongs to. Fire-and-forget —
// the durable record is the code-run-events-batch written when the run settles.
export type CodeRunFeedEvent = {
toolCallId: string;
event: CodeRunEvent;
};

View file

@ -21,7 +21,7 @@ import { ZListToolkitsResponse } from './composio.js';
import { BrowserStateSchema, HttpAuthRequestSchema } from './browser-control.js';
import { BillingInfoSchema } from './billing.js';
import { EmailBlockSchema, GmailThreadSchema } from './blocks.js';
import { PermissionDecision, ApprovalPolicy, CodingAgent } from './code-mode.js';
import { PermissionDecision, ApprovalPolicy, CodingAgent, type CodeRunFeedEvent } from './code-mode.js';
import { NotificationSettingsSchema } from './notification-settings.js';
import { CodeProject, CodeSession, CodeSessionMode, CodeSessionStatus, GitRepoInfo, GitStatusFile, CodeAgentModelOptions } from './code-sessions.js';
import { ChannelsConfig, ChannelsStatus } from './channels.js';
@ -450,6 +450,14 @@ const ipcSchemas = {
req: z.null(),
res: z.null(),
},
// Ephemeral code-run stream (CodeRunFeed): per-event broadcast of a
// code_agent_run's live ACP activity, keyed by toolCallId. Never persisted —
// the durable record is the code-run-events-batch tool progress written when
// the run settles. Typed via z.custom like the other broadcast feeds.
'codeRun:events': {
req: z.custom<CodeRunFeedEvent>(),
res: z.null(),
},
// ── New runtime: sessions + turns (session-design.md) ────────────────────
// Turn-mutating calls return quickly; the renderer follows progress through
// the sessions:events feed and the shared reduceTurn reducer.

View file

@ -130,6 +130,17 @@ export const CodeRunPermissionRequestEvent = BaseRunEvent.extend({
ask: PermissionAsk,
});
// The complete, ordered code-run timeline, published ONCE when the coding turn
// settles (consecutive agent message chunks coalesced — display-lossless, the
// timeline concatenates them anyway). This is the durable record; the live
// per-event stream travels over the ephemeral CodeRunFeed (`codeRun:events`)
// and is never persisted.
export const CodeRunEventsBatchEvent = BaseRunEvent.extend({
type: z.literal("code-run-events-batch"),
toolCallId: z.string(),
events: z.array(CodeRunEventSchema),
});
export const ToolPermissionAutoDecisionEvent = BaseRunEvent.extend({
type: z.literal("tool-permission-auto-decision"),
toolCallId: z.string(),
@ -165,6 +176,7 @@ export const RunEvent = z.union([
ToolPermissionResponseEvent,
CodeRunStreamEvent,
CodeRunPermissionRequestEvent,
CodeRunEventsBatchEvent,
ToolPermissionAutoDecisionEvent,
RunErrorEvent,
RunStoppedEvent,

View file

@ -1,57 +0,0 @@
diff --git a/dist/index.js b/dist/index.js
--- a/dist/index.js
+++ b/dist/index.js
@@ -17678,15 +17678,22 @@
case "dynamicToolCall":
return await createDynamicToolCallUpdate(event.item);
+ case "contextCompaction":
+ return {
+ sessionUpdate: "tool_call",
+ toolCallId: event.item.id,
+ kind: "other",
+ title: "Compacting context",
+ status: "in_progress"
+ };
case "collabAgentToolCall":
case "userMessage":
case "hookPrompt":
case "agentMessage":
case "reasoning":
case "webSearch":
case "imageView":
case "imageGeneration":
case "enteredReviewMode":
case "exitedReviewMode":
- case "contextCompaction":
case "plan":
return null;
@@ -17713,23 +17720,28 @@
return this.completeCommandExecutionEvent(event.item);
case "reasoning":
const summary = event.item.summary[0];
if (!summary) return null;
return {
sessionUpdate: "agent_thought_chunk",
content: {
type: "text",
text: summary
}
};
+ case "contextCompaction":
+ return {
+ sessionUpdate: "tool_call_update",
+ toolCallId: event.item.id,
+ status: "completed"
+ };
case "collabAgentToolCall":
case "userMessage":
case "hookPrompt":
case "agentMessage":
case "webSearch":
case "imageView":
case "imageGeneration":
case "enteredReviewMode":
case "exitedReviewMode":
- case "contextCompaction":
case "plan":
return null;

View file

@ -1,15 +0,0 @@
diff --git a/bin/codex.js b/bin/codex.js
index 67ab3e2d95dfac1c91882578b5403916c3121484..f8030b6e1459e05161af99e152b2e7f65ea6c41d 100644
--- a/bin/codex.js
+++ b/bin/codex.js
@@ -175,6 +175,10 @@ env[packageManagerEnvVar] = "1";
const child = spawn(binaryPath, process.argv.slice(2), {
stdio: "inherit",
env,
+ // Native console-subsystem binary: without this Windows pops a visible console
+ // window when launched from a console-less (Electron GUI) parent. Closing that
+ // window wedges the agent. CREATE_NO_WINDOW keeps the console hidden.
+ windowsHide: true,
});
child.on("error", (err) => {

214
apps/x/pnpm-lock.yaml generated
View file

@ -10,13 +10,8 @@ catalogs:
specifier: 4.1.7
version: 4.1.7
patchedDependencies:
'@agentclientprotocol/codex-acp@0.0.44':
hash: 0079b1ab3870451b47fe5ea5ecaca697e17139cff50fd2ee9c296b172aba525e
path: patches/@agentclientprotocol__codex-acp@0.0.44.patch
'@openai/codex@0.128.0':
hash: 9edd926108a95aaa788aa93870fd6b16d70eeccdf5740b503af5d34cc9f25e86
path: patches/@openai__codex@0.128.0.patch
overrides:
vscode-jsonrpc: 8.2.0
importers:
@ -56,11 +51,11 @@ importers:
apps/main:
dependencies:
'@agentclientprotocol/claude-agent-acp':
specifier: ^0.39.0
version: 0.39.0(@anthropic-ai/sdk@0.100.1(zod@4.2.1))(@modelcontextprotocol/sdk@1.25.1(hono@4.11.3)(zod@4.2.1))
specifier: ^0.55.0
version: 0.55.0(@anthropic-ai/sdk@0.100.1(zod@4.2.1))(@modelcontextprotocol/sdk@1.25.1(hono@4.11.3)(zod@4.2.1))
'@agentclientprotocol/codex-acp':
specifier: ^0.0.44
version: 0.0.44(patch_hash=0079b1ab3870451b47fe5ea5ecaca697e17139cff50fd2ee9c296b172aba525e)(zod@4.2.1)
specifier: ^1.1.0
version: 1.1.0
'@x/core':
specifier: workspace:*
version: link:../../packages/core
@ -428,14 +423,14 @@ importers:
packages/core:
dependencies:
'@agentclientprotocol/claude-agent-acp':
specifier: ^0.39.0
version: 0.39.0(@anthropic-ai/sdk@0.100.1(zod@4.2.1))(@modelcontextprotocol/sdk@1.25.1(hono@4.11.3)(zod@4.2.1))
specifier: ^0.55.0
version: 0.55.0(@anthropic-ai/sdk@0.100.1(zod@4.2.1))(@modelcontextprotocol/sdk@1.25.1(hono@4.11.3)(zod@4.2.1))
'@agentclientprotocol/codex-acp':
specifier: ^0.0.44
version: 0.0.44(patch_hash=0079b1ab3870451b47fe5ea5ecaca697e17139cff50fd2ee9c296b172aba525e)(zod@4.2.1)
specifier: ^1.1.0
version: 1.1.0
'@agentclientprotocol/sdk':
specifier: ^0.22.1
version: 0.22.1(zod@4.2.1)
specifier: ^1.1.0
version: 1.1.0(zod@4.2.1)
'@ai-sdk/anthropic':
specifier: ^2.0.63
version: 2.0.70(zod@4.2.1)
@ -579,21 +574,17 @@ packages:
'@adobe/css-tools@4.5.0':
resolution: {integrity: sha512-6OzddxPio9UiWTCemp4N8cYLV2ZN1ncRnV1cVGtve7dhPOtRkleRyx32GQCYSwDYgaHU3USMm84tNsvKzRCa1Q==}
'@agentclientprotocol/claude-agent-acp@0.39.0':
resolution: {integrity: sha512-+tCm5v32L0R3zE4qjZQowfO1L/zqvQ5FapmsMSIf4gawXfTf26CG5hgz99wARdo0zn20/1eP80gzx7PbZlSX9A==}
'@agentclientprotocol/claude-agent-acp@0.55.0':
resolution: {integrity: sha512-zZ4EpT6OppURh3lrTTvQR42+ggPi5Q42TC7Nig+Vt0RGBAmw73xAnM6W5BpdNRL7VcT/2aRndV0Z7fuGrruMGA==}
engines: {node: '>=22'}
hasBin: true
'@agentclientprotocol/codex-acp@0.0.44':
resolution: {integrity: sha512-iHzFWKzJ0Z8I6yJCkuLZ+nb9mF2WYmfTcHFFvc7sU/awBsQmVBmpSOXOpZ+IK2Dy9cR3iRoML/B2/Wq2/zKBCA==}
'@agentclientprotocol/codex-acp@1.1.0':
resolution: {integrity: sha512-EdUwW6n12yy4khxS6YpOgT8dd4JbVeOP8qPLdCEj795kp85qVI6369EWUXHq1CrnvOmGVwieUMvnrMlsqJaRWg==}
hasBin: true
'@agentclientprotocol/sdk@0.21.1':
resolution: {integrity: sha512-ZTLH+o9QxcZDLX/9ww+W7C2iExnXFM+vD/uGFVSlR61Kzj9FaxUqBC6Rv/kwgA7qVWYUEI9c5ZNqCuO9PM4rKg==}
peerDependencies:
zod: ^3.25.0 || ^4.0.0
'@agentclientprotocol/sdk@0.22.1':
resolution: {integrity: sha512-DfqXtl/8gO9NImq094MTaCXEU2vkhh6v7q/kT+9UjZxUqj8hYaya2OjLVIqn16MzNHcXEpShTR2RIauLSYeDQQ==}
'@agentclientprotocol/sdk@1.1.0':
resolution: {integrity: sha512-NT2KqphUJ3w6EksUL51ZhJgIYgq/ZLGcBPkyMKgRSO5PMVwe9DnKKX+Htnvk6KHh6dUuh34UHK4gKp+4te1Mdg==}
peerDependencies:
zod: ^3.25.0 || ^4.0.0
@ -652,48 +643,48 @@ packages:
'@antfu/install-pkg@1.1.0':
resolution: {integrity: sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==}
'@anthropic-ai/claude-agent-sdk-darwin-arm64@0.3.156':
resolution: {integrity: sha512-IkjcS9dqAUlD4Nb62L9AZtmAXCa+FV4ul8lIlyXXUprh3nlecbKsWOXVd/GORrzAhMmynJaX4+iV1JiutFKXUA==}
'@anthropic-ai/claude-agent-sdk-darwin-arm64@0.3.198':
resolution: {integrity: sha512-ZmiAybQKIKcP1qEAE/vfXvfxtKxG9CnJn98QTXC5Zxiwuy7Mllx2ALXh9dfmsf0V87CGEodlZQmMgUJotNIsUw==}
cpu: [arm64]
os: [darwin]
'@anthropic-ai/claude-agent-sdk-darwin-x64@0.3.156':
resolution: {integrity: sha512-6PKi5fPmGRuzXu+Em/iwLmPG3mqg0hl92wcTU8fmChqyNtxhxsjCw7LTbdFqp/05o5NeZVVV4k3p7YUv5IFD6g==}
'@anthropic-ai/claude-agent-sdk-darwin-x64@0.3.198':
resolution: {integrity: sha512-XwH5vgN46WSwg8aC1OagNofnJpV/G1ciEu118GEKer8ZhVkq/dvK/DqShxMkb6r1jV7u5IJ7zPXu9uKliyNJAw==}
cpu: [x64]
os: [darwin]
'@anthropic-ai/claude-agent-sdk-linux-arm64-musl@0.3.156':
resolution: {integrity: sha512-R7KEVjxkR4rYgIQoHGBzwPdUJYxRTO8I4vHjRbMLH1eW4FS7BJvVs7ogfKR/NnHFBvMVqtC+l6jHLQv8bobUiw==}
'@anthropic-ai/claude-agent-sdk-linux-arm64-musl@0.3.198':
resolution: {integrity: sha512-Q7lKVNjIrUQ2B/AR77OvRf0zeOdEjonFVaR9FYrrwtzGeEqum69WSht5nM7Y7el3wjbNi0/eV0QTUM0DlsTEfw==}
cpu: [arm64]
os: [linux]
'@anthropic-ai/claude-agent-sdk-linux-arm64@0.3.156':
resolution: {integrity: sha512-H0Nfd41iw5isto9uQI1FlVSZ0eaDttr8rBpJMR25oK/mj3egMO5EmZ6aAxeeUYSLn2mSU50HA5VNxlGUE118TQ==}
'@anthropic-ai/claude-agent-sdk-linux-arm64@0.3.198':
resolution: {integrity: sha512-qmz8dxEtDIlKntU5qYe0R4aWTxTue5S7zIQknatLX7aJ6HN/nq1aCNXWn5smTH2FViBkUPPR+sCIsNwSk6AT6Q==}
cpu: [arm64]
os: [linux]
'@anthropic-ai/claude-agent-sdk-linux-x64-musl@0.3.156':
resolution: {integrity: sha512-/Q6WUizI6a+hqZZ6ElwRU0PEuFhOoN4v6CuU35HHbiZ/7uaocGht4A8ZIgK1Fw6wOGtZzGLbc00CA1OU1Zg8EA==}
'@anthropic-ai/claude-agent-sdk-linux-x64-musl@0.3.198':
resolution: {integrity: sha512-h1SrWVIMjLInYNPlf+TxXuKTOdoiOfJLBSoQG97315Z2Nh0IpBfqWExlqYTtPCgKE7q2iga31U283QfHpIDlSQ==}
cpu: [x64]
os: [linux]
'@anthropic-ai/claude-agent-sdk-linux-x64@0.3.156':
resolution: {integrity: sha512-ymhrdlbWoYvTACUdaGdhrEv+ZMfwXLsf0BRLkr/IvY5aqybP7URzWmmZGOtDQpqkT/8xu/UCGqUYH3woJwUxfg==}
'@anthropic-ai/claude-agent-sdk-linux-x64@0.3.198':
resolution: {integrity: sha512-Zqxyz2AT1UM5WlOOoLJhLssZDgZo8rBK5ku6daveK12zp+UTJGZhGsjFghz1/ASxH08KqOTbUePNTORnPhHAEQ==}
cpu: [x64]
os: [linux]
'@anthropic-ai/claude-agent-sdk-win32-arm64@0.3.156':
resolution: {integrity: sha512-5sAeNObQQrMy4NF9HwxewrMnU7mVxZDHh+/MfJVQSz0GSTvXQ6gOuRH8helMlfspoU6VOdekPxVLRooX/3foEw==}
'@anthropic-ai/claude-agent-sdk-win32-arm64@0.3.198':
resolution: {integrity: sha512-mjIHf1HFiRuXefewWTaNZFlTZlCaEt/xsRjc1nSTCEEpFolZayVhrDKz+O2QFVcDtPl8x8GeYSL0kiikg1DZjQ==}
cpu: [arm64]
os: [win32]
'@anthropic-ai/claude-agent-sdk-win32-x64@0.3.156':
resolution: {integrity: sha512-/PofeTWoiKgnWNSNk0wG4SsRn22GGLmnLhg2R94WcNhCRFOyOTmiZcYH2DBlWZBIRVTZDsSfa/Pl1DyPvYCGKw==}
'@anthropic-ai/claude-agent-sdk-win32-x64@0.3.198':
resolution: {integrity: sha512-y3HLuCCz1kDwUrhd6OnqO+d5BUpTFSzNUsPT9kf3r1vk9HYKF+eMC9eIlcOhiW2kX491kxEvuEOfqgIkGx15cg==}
cpu: [x64]
os: [win32]
'@anthropic-ai/claude-agent-sdk@0.3.156':
resolution: {integrity: sha512-6nM/Dj+VMds52UXJ2YaV4IKhYamlUqN0HtdDrFzYz5lvPMpDS935qD8YZDAUpy+ltdoD6PJMd1V/CKFY3/oWCQ==}
'@anthropic-ai/claude-agent-sdk@0.3.198':
resolution: {integrity: sha512-xt469sSCyclTPtzpLAg0Aschy665GiRMgZKabSmESbGUA5/H56HcILVOiFxclXswkeMUk2fQxfHJUY9UZfiTnA==}
engines: {node: '>=18.0.0'}
peerDependencies:
'@anthropic-ai/sdk': '>=0.93.0'
@ -2295,43 +2286,43 @@ packages:
resolution: {integrity: sha512-6gH/bLQJSJEg7OEpkH4wGQdA8KXHRbzL1YkGyUO12YNAgV3jxKy4K9kvfXj4+9T0OLug5k58cnPCKSSIKzp7pg==}
engines: {node: '>=8.0'}
'@openai/codex@0.128.0':
resolution: {integrity: sha512-+xp6ODmFfBNnexIWRHApEaPXot2j6gyM8A5we/5IS/uY4eYHj4arETct4hQ5M4eO+MK7JY3ZU4xhuobhlysr0A==}
'@openai/codex@0.142.5':
resolution: {integrity: sha512-WQEpD7l3k68eIAP0aq28EdR18ENBAf8DyprzFhzNwCOQJSv4nHzpwT8Fl30IJacprko2ZCmUBZjM2u941l2yLw==}
engines: {node: '>=16'}
hasBin: true
'@openai/codex@0.128.0-darwin-arm64':
resolution: {integrity: sha512-w+6zohfHx/kHBdles/CyFKaY57u9I3nK8QI9+NrdwMliKA0b7xn13yblRNkMpe09j6vL1oAWoxYsMOQ/vjBGug==}
'@openai/codex@0.142.5-darwin-arm64':
resolution: {integrity: sha512-l43p8xv+Z/2/b6fCUc7/FmcQZsaPB7RFizLponGwHAnFOWe3i9Vky69p+up3BUam9AetoQQUv7Mo+2KdaFEqhA==}
engines: {node: '>=16'}
cpu: [arm64]
os: [darwin]
'@openai/codex@0.128.0-darwin-x64':
resolution: {integrity: sha512-SDbn6fO22Puy8xmMIbZi4f2znMrUEPwABApke4mo+4ihaauwuVjeqzXvW5SPJz5ty/bG11/mSupQgReT7T8BBw==}
'@openai/codex@0.142.5-darwin-x64':
resolution: {integrity: sha512-yk6A06/VmW7NFsa48OVPaj//g/zeSpd79wjuqfXZwW8ZKRYQm3+wCd3hWjPl79F3QnXvDvM2j3JMIBL3m3GXXg==}
engines: {node: '>=16'}
cpu: [x64]
os: [darwin]
'@openai/codex@0.128.0-linux-arm64':
resolution: {integrity: sha512-+SvH73H60qvCXFuQGP/EsmR//s1hHMBR22PvJkXvM/hdnTIGucx+JqRUjAWdmmQ1IU6j3kgwVvdLW/6ICB+M6w==}
'@openai/codex@0.142.5-linux-arm64':
resolution: {integrity: sha512-77ka5PSnm5HdxdBT99IwntCasmbqevlS0eiC0AtEb6ZXCLkim2gm0AWm+jNYy0EhbssvNK+KghayWo34HMgXeA==}
engines: {node: '>=16'}
cpu: [arm64]
os: [linux]
'@openai/codex@0.128.0-linux-x64':
resolution: {integrity: sha512-2lnSPA05CRRuKAzFW8BCmmNCSieDcToLwfC2ALLbBYilGLgzhRibjlDglK9F1BkEzfohSSWJu4PBbRu/aG60lQ==}
'@openai/codex@0.142.5-linux-x64':
resolution: {integrity: sha512-pxY+d3NgNE57Y/MApD3/TZUAygxJN6I9h3ZeDUwe67mxWjUxsuapxMRFTKSznCalYbRAeZp752+AAXmUbmguEg==}
engines: {node: '>=16'}
cpu: [x64]
os: [linux]
'@openai/codex@0.128.0-win32-arm64':
resolution: {integrity: sha512-ECJvsqmYFdA9pn42xxK3Odp/G16AjmBW0BglX8L0PwPjqbstbmlew9bfHf7xvL+SNfNl4NmyotW0+RNo1phgaA==}
'@openai/codex@0.142.5-win32-arm64':
resolution: {integrity: sha512-65BEqGbUZ7r0ayunIHdBjo5crwgbwKX/6puOcO+VCswUw/dXvDsN2IGcbXB52+bS9U5+FxP783cUHfTT6m40DQ==}
engines: {node: '>=16'}
cpu: [arm64]
os: [win32]
'@openai/codex@0.128.0-win32-x64':
resolution: {integrity: sha512-k3jmUAFrzkUtvjGTXvSKjQqJLLlzjxp/VoHJDYedgmXUn6j70HxK38IwapzmnYfiBiTuzETvGwjXHzZgzKjhoQ==}
'@openai/codex@0.142.5-win32-x64':
resolution: {integrity: sha512-a+wI4PEx9a2fg6V5ueTTDkOkr1XpEvA5RFXIbo/L2hOfzMmGtyRnbG24bCGu5Q2RSgVxSQV0aLkdb3vdYMNH9A==}
engines: {node: '>=16'}
cpu: [x64]
os: [win32]
@ -5340,8 +5331,8 @@ packages:
diff3@0.0.3:
resolution: {integrity: sha512-iSq8ngPOt0K53A6eVr4d5Kn6GNrM2nQZtC740pzIriHtn4pOQ2lyzEXQMBeVcWERN0ye7fhBsk9PbLLQOnUx/g==}
diff@8.0.4:
resolution: {integrity: sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==}
diff@9.0.0:
resolution: {integrity: sha512-svtcdpS8CgJyqAjEQIXdb3OjhFVVYjzGAPO8WGCmRbrml64SPw/jJD4GoE98aR7r25A0XcgrK3F02yw9R/vhQw==}
engines: {node: '>=0.3.1'}
dijkstrajs@1.0.3:
@ -8921,10 +8912,6 @@ packages:
resolution: {integrity: sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==}
engines: {node: '>=14.0.0'}
vscode-jsonrpc@8.2.1:
resolution: {integrity: sha512-kdjOSJ2lLIn7r1rtrMbbNCHjyMPfRnowdKjBQ+mGq6NAW5QY2bEZC/khaC5OR8svbbjvLEaIXkOq45e2X9BIbQ==}
engines: {node: '>=14.0.0'}
vscode-languageserver-protocol@3.17.5:
resolution: {integrity: sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==}
@ -9190,32 +9177,31 @@ snapshots:
'@adobe/css-tools@4.5.0': {}
'@agentclientprotocol/claude-agent-acp@0.39.0(@anthropic-ai/sdk@0.100.1(zod@4.2.1))(@modelcontextprotocol/sdk@1.25.1(hono@4.11.3)(zod@4.2.1))':
'@agentclientprotocol/claude-agent-acp@0.55.0(@anthropic-ai/sdk@0.100.1(zod@4.2.1))(@modelcontextprotocol/sdk@1.25.1(hono@4.11.3)(zod@4.2.1))':
dependencies:
'@agentclientprotocol/sdk': 0.22.1(zod@4.2.1)
'@anthropic-ai/claude-agent-sdk': 0.3.156(@anthropic-ai/sdk@0.100.1(zod@4.2.1))(@modelcontextprotocol/sdk@1.25.1(hono@4.11.3)(zod@4.2.1))(zod@4.2.1)
zod: 4.2.1
'@agentclientprotocol/sdk': 1.1.0(zod@4.4.3)
'@anthropic-ai/claude-agent-sdk': 0.3.198(@anthropic-ai/sdk@0.100.1(zod@4.2.1))(@modelcontextprotocol/sdk@1.25.1(hono@4.11.3)(zod@4.2.1))(zod@4.4.3)
zod: 4.4.3
transitivePeerDependencies:
- '@anthropic-ai/sdk'
- '@modelcontextprotocol/sdk'
'@agentclientprotocol/codex-acp@0.0.44(patch_hash=0079b1ab3870451b47fe5ea5ecaca697e17139cff50fd2ee9c296b172aba525e)(zod@4.2.1)':
'@agentclientprotocol/codex-acp@1.1.0':
dependencies:
'@agentclientprotocol/sdk': 0.21.1(zod@4.2.1)
'@openai/codex': 0.128.0(patch_hash=9edd926108a95aaa788aa93870fd6b16d70eeccdf5740b503af5d34cc9f25e86)
diff: 8.0.4
'@agentclientprotocol/sdk': 1.1.0(zod@4.4.3)
'@openai/codex': 0.142.5
diff: 9.0.0
open: 11.0.0
vscode-jsonrpc: 8.2.1
transitivePeerDependencies:
- zod
vscode-jsonrpc: 8.2.0
zod: 4.4.3
'@agentclientprotocol/sdk@0.21.1(zod@4.2.1)':
'@agentclientprotocol/sdk@1.1.0(zod@4.2.1)':
dependencies:
zod: 4.2.1
'@agentclientprotocol/sdk@0.22.1(zod@4.2.1)':
'@agentclientprotocol/sdk@1.1.0(zod@4.4.3)':
dependencies:
zod: 4.2.1
zod: 4.4.3
'@ai-sdk/anthropic@2.0.70(zod@4.2.1)':
dependencies:
@ -9278,44 +9264,44 @@ snapshots:
package-manager-detector: 1.6.0
tinyexec: 1.0.2
'@anthropic-ai/claude-agent-sdk-darwin-arm64@0.3.156':
'@anthropic-ai/claude-agent-sdk-darwin-arm64@0.3.198':
optional: true
'@anthropic-ai/claude-agent-sdk-darwin-x64@0.3.156':
'@anthropic-ai/claude-agent-sdk-darwin-x64@0.3.198':
optional: true
'@anthropic-ai/claude-agent-sdk-linux-arm64-musl@0.3.156':
'@anthropic-ai/claude-agent-sdk-linux-arm64-musl@0.3.198':
optional: true
'@anthropic-ai/claude-agent-sdk-linux-arm64@0.3.156':
'@anthropic-ai/claude-agent-sdk-linux-arm64@0.3.198':
optional: true
'@anthropic-ai/claude-agent-sdk-linux-x64-musl@0.3.156':
'@anthropic-ai/claude-agent-sdk-linux-x64-musl@0.3.198':
optional: true
'@anthropic-ai/claude-agent-sdk-linux-x64@0.3.156':
'@anthropic-ai/claude-agent-sdk-linux-x64@0.3.198':
optional: true
'@anthropic-ai/claude-agent-sdk-win32-arm64@0.3.156':
'@anthropic-ai/claude-agent-sdk-win32-arm64@0.3.198':
optional: true
'@anthropic-ai/claude-agent-sdk-win32-x64@0.3.156':
'@anthropic-ai/claude-agent-sdk-win32-x64@0.3.198':
optional: true
'@anthropic-ai/claude-agent-sdk@0.3.156(@anthropic-ai/sdk@0.100.1(zod@4.2.1))(@modelcontextprotocol/sdk@1.25.1(hono@4.11.3)(zod@4.2.1))(zod@4.2.1)':
'@anthropic-ai/claude-agent-sdk@0.3.198(@anthropic-ai/sdk@0.100.1(zod@4.2.1))(@modelcontextprotocol/sdk@1.25.1(hono@4.11.3)(zod@4.2.1))(zod@4.4.3)':
dependencies:
'@anthropic-ai/sdk': 0.100.1(zod@4.2.1)
'@modelcontextprotocol/sdk': 1.25.1(hono@4.11.3)(zod@4.2.1)
zod: 4.2.1
zod: 4.4.3
optionalDependencies:
'@anthropic-ai/claude-agent-sdk-darwin-arm64': 0.3.156
'@anthropic-ai/claude-agent-sdk-darwin-x64': 0.3.156
'@anthropic-ai/claude-agent-sdk-linux-arm64': 0.3.156
'@anthropic-ai/claude-agent-sdk-linux-arm64-musl': 0.3.156
'@anthropic-ai/claude-agent-sdk-linux-x64': 0.3.156
'@anthropic-ai/claude-agent-sdk-linux-x64-musl': 0.3.156
'@anthropic-ai/claude-agent-sdk-win32-arm64': 0.3.156
'@anthropic-ai/claude-agent-sdk-win32-x64': 0.3.156
'@anthropic-ai/claude-agent-sdk-darwin-arm64': 0.3.198
'@anthropic-ai/claude-agent-sdk-darwin-x64': 0.3.198
'@anthropic-ai/claude-agent-sdk-linux-arm64': 0.3.198
'@anthropic-ai/claude-agent-sdk-linux-arm64-musl': 0.3.198
'@anthropic-ai/claude-agent-sdk-linux-x64': 0.3.198
'@anthropic-ai/claude-agent-sdk-linux-x64-musl': 0.3.198
'@anthropic-ai/claude-agent-sdk-win32-arm64': 0.3.198
'@anthropic-ai/claude-agent-sdk-win32-x64': 0.3.198
'@anthropic-ai/sdk@0.100.1(zod@4.2.1)':
dependencies:
@ -11605,31 +11591,31 @@ snapshots:
'@oozcitak/util@8.3.4': {}
'@openai/codex@0.128.0(patch_hash=9edd926108a95aaa788aa93870fd6b16d70eeccdf5740b503af5d34cc9f25e86)':
'@openai/codex@0.142.5':
optionalDependencies:
'@openai/codex-darwin-arm64': '@openai/codex@0.128.0-darwin-arm64'
'@openai/codex-darwin-x64': '@openai/codex@0.128.0-darwin-x64'
'@openai/codex-linux-arm64': '@openai/codex@0.128.0-linux-arm64'
'@openai/codex-linux-x64': '@openai/codex@0.128.0-linux-x64'
'@openai/codex-win32-arm64': '@openai/codex@0.128.0-win32-arm64'
'@openai/codex-win32-x64': '@openai/codex@0.128.0-win32-x64'
'@openai/codex-darwin-arm64': '@openai/codex@0.142.5-darwin-arm64'
'@openai/codex-darwin-x64': '@openai/codex@0.142.5-darwin-x64'
'@openai/codex-linux-arm64': '@openai/codex@0.142.5-linux-arm64'
'@openai/codex-linux-x64': '@openai/codex@0.142.5-linux-x64'
'@openai/codex-win32-arm64': '@openai/codex@0.142.5-win32-arm64'
'@openai/codex-win32-x64': '@openai/codex@0.142.5-win32-x64'
'@openai/codex@0.128.0-darwin-arm64':
'@openai/codex@0.142.5-darwin-arm64':
optional: true
'@openai/codex@0.128.0-darwin-x64':
'@openai/codex@0.142.5-darwin-x64':
optional: true
'@openai/codex@0.128.0-linux-arm64':
'@openai/codex@0.142.5-linux-arm64':
optional: true
'@openai/codex@0.128.0-linux-x64':
'@openai/codex@0.142.5-linux-x64':
optional: true
'@openai/codex@0.128.0-win32-arm64':
'@openai/codex@0.142.5-win32-arm64':
optional: true
'@openai/codex@0.128.0-win32-x64':
'@openai/codex@0.142.5-win32-x64':
optional: true
'@openrouter/ai-sdk-provider@1.5.4(ai@5.0.151(zod@4.2.1))(zod@4.2.1)':
@ -11640,7 +11626,7 @@ snapshots:
'@openrouter/sdk@0.1.27':
dependencies:
zod: 4.2.1
zod: 4.4.3
'@opentelemetry/api-logs@0.208.0':
dependencies:
@ -14994,7 +14980,7 @@ snapshots:
diff3@0.0.3: {}
diff@8.0.4: {}
diff@9.0.0: {}
dijkstrajs@1.0.3: {}
@ -19396,8 +19382,6 @@ snapshots:
vscode-jsonrpc@8.2.0: {}
vscode-jsonrpc@8.2.1: {}
vscode-languageserver-protocol@3.17.5:
dependencies:
vscode-jsonrpc: 8.2.0

View file

@ -12,6 +12,9 @@ allowBuilds:
node-pty: true
protobufjs: true
overrides:
vscode-jsonrpc: 8.2.0
catalog:
vitest: 4.1.7
@ -24,7 +27,3 @@ onlyBuiltDependencies:
- fs-xattr
- macos-alias
- protobufjs
patchedDependencies:
'@agentclientprotocol/codex-acp@0.0.44': patches/@agentclientprotocol__codex-acp@0.0.44.patch
'@openai/codex@0.128.0': patches/@openai__codex@0.128.0.patch