diff --git a/dist/live-checkpoint-ClPCSdrW.js b/dist/live-checkpoint-ClPCSdrW.js index 243c9d13bcba520923b63adfddad75cf2d94362d..643315c1e9b529768695c863eae7a29e9f5a3dac 100644 --- a/dist/live-checkpoint-ClPCSdrW.js +++ b/dist/live-checkpoint-ClPCSdrW.js @@ -1532,7 +1532,7 @@ const ZED_TAG_KEYS = /* @__PURE__ */ new Set([ "RedactedThinking", "ToolUse" ]); -const MAP_OBJECT_PATHS = /* @__PURE__ */ new Set(["request_token_usage", "messages.Agent.tool_results"]); +const MAP_OBJECT_PATHS = /* @__PURE__ */ new Set(["request_token_usage", "messages.Agent.tool_results", "acpx.session_options.env"]); const OPAQUE_VALUE_PATHS = /* @__PURE__ */ new Set([ "agent_capabilities", "messages.Agent.content.ToolUse.input", @@ -2557,7 +2557,7 @@ function readCommandLineChar(state) { escaping: false, hasPart: true }; - if (state.ch === "\\" && state.quote !== "'") return { + if (process.platform !== "win32" && state.ch === "\\" && state.quote !== "'") return { current: state.current, quote: state.quote, escaping: true, @@ -2912,8 +2912,8 @@ function promotePrefixedAuthEnvironment(env) { } return protectedKeys; } -function buildAgentEnvironment(authCredentials, sessionEnv) { - const env = { ...process.env }; +function buildAgentEnvironment(authCredentials, sessionEnv, inheritProcessEnv = true) { + const env = inheritProcessEnv ? { ...process.env } : {}; const protectedAuthEnvKeys = promotePrefixedAuthEnvironment(env); if (authCredentials) for (const [methodId, credential] of Object.entries(authCredentials)) { addAuthCredentialEnvKeys(protectedAuthEnvKeys, methodId, credential); @@ -2955,10 +2955,10 @@ function resolveConfiguredAuthCredential(methodId, authCredentials) { const configCredentials = authCredentials ?? {}; return configCredentials[methodId] ?? configCredentials[toEnvToken(methodId)]; } -function buildAgentSpawnOptions(cwd, authCredentials, sessionEnv) { +function buildAgentSpawnOptions(cwd, authCredentials, sessionEnv, inheritProcessEnv) { return { cwd, - env: buildAgentEnvironment(authCredentials, sessionEnv), + env: buildAgentEnvironment(authCredentials, sessionEnv, inheritProcessEnv), stdio: [ "pipe", "pipe", @@ -3724,10 +3724,13 @@ function resolveClientCapabilities(params) { }, terminal: params.terminal }; - if (!params.devinAcp) return baseCapabilities; + const typedSessionFailureMeta = { + jetbrains: { air: { version: 1, capabilities: ["sessionFailure"] } } + }; + if (!params.devinAcp) return { ...baseCapabilities, _meta: typedSessionFailureMeta }; return { ...baseCapabilities, - _meta: DEVIN_COMPATIBILITY_CLIENT_CAPABILITIES_META + _meta: { ...typedSessionFailureMeta, ...DEVIN_COMPATIBILITY_CLIENT_CAPABILITIES_META } }; } function isDevinRequestDiagnosticsMethod(method) { @@ -3957,9 +3960,26 @@ var AcpClient = class { this.lastAgentExit = void 0; this.lastKnownPid = child.pid ?? void 0; this.attachAgentLifecycleObservers(child); + if (this.options.onAgentSpawn) { + try { + if (typeof child.pid !== "number" || child.pid <= 0) { + throw new Error("ACPX agent spawn did not expose a valid process id."); + } + await this.options.onAgentSpawn({ pid: child.pid, startedAt: this.agentStartedAt }); + } catch (error) { + try { + child.kill("SIGKILL"); + } catch {} + throw error; + } + } const startupStderr = []; child.stderr.on("data", (chunk) => { this.captureStartupStderr(startupStderr, chunk); + if (this.options.onAgentStderr) { + this.options.onAgentStderr(chunk.toString()); + return; + } if (!this.options.verbose) return; process.stderr.write(chunk); }); @@ -3994,7 +4014,7 @@ var AcpClient = class { geminiAcp: isGeminiAcpCommand(spawnCommand, args), copilotAcp: isCopilotAcpCommand(spawnCommand, args), claudeAcp: isClaudeAcpCommand(spawnCommand, args), - spawnOptions: buildAgentSpawnOptions(this.options.cwd, this.options.authCredentials, this.options.sessionOptions?.env) + spawnOptions: buildAgentSpawnOptions(this.options.spawnCwd ?? this.options.cwd, this.options.authCredentials, this.options.sessionOptions?.env, this.options.inheritProcessEnv) }; } logAgentLaunch(plan) { @@ -6070,6 +6090,27 @@ async function withConnectedSession(options) { //#region src/runtime/engine/prompt-turn.ts const SESSION_REPLY_IDLE_MS = 1e3; const SESSION_REPLY_DRAIN_TIMEOUT_MS = 5e3; +const TYPED_SESSION_FAILURE_CATEGORIES = /* @__PURE__ */ new Set([ + "connection", + "access", + "limit", + "service", + "request", + "unknown" +]); +function typedTerminalSessionFailureCategory(response) { + if (response === null || typeof response !== "object" || Array.isArray(response)) return null; + const meta = response._meta; + if (meta === null || typeof meta !== "object" || Array.isArray(meta)) return null; + const jetbrains = meta.jetbrains; + if (jetbrains === null || typeof jetbrains !== "object" || Array.isArray(jetbrains)) return null; + const air = jetbrains.air; + if (air === null || typeof air !== "object" || Array.isArray(air)) return null; + if (!Number.isInteger(air.version) || air.version < 1) return null; + const failure = air.sessionFailure; + if (failure === null || typeof failure !== "object" || Array.isArray(failure) || failure.severity !== "error") return null; + return typeof failure.category === "string" && TYPED_SESSION_FAILURE_CATEGORIES.has(failure.category) ? failure.category : "unknown"; +} async function runPromptTurn(params) { try { const promptPromise = params.client.prompt(params.sessionId, params.prompt); @@ -6079,6 +6120,9 @@ async function runPromptTurn(params) { idleMs: SESSION_REPLY_IDLE_MS, timeoutMs: SESSION_REPLY_DRAIN_TIMEOUT_MS }).catch(() => {}); + const terminalFailureCategory = typedTerminalSessionFailureCategory(response); + if (terminalFailureCategory !== null) + throw new Error(`ACP agent reported a terminal ${terminalFailureCategory} failure.`); recordPromptResponseUsage(params.conversation, response.usage, params.promptMessageId); return { stopReason: response.stopReason, diff --git a/dist/runtime.d.ts b/dist/runtime.d.ts index ccdbe5b032521518022223733049b8b38793473b..a04948e2b1ab8e169778e0d839ab5bf680573266 100644 --- a/dist/runtime.d.ts +++ b/dist/runtime.d.ts @@ -266,6 +266,10 @@ type AcpRuntimeOptions = { timeoutMs?: number; probeAgent?: string; verbose?: boolean; + onAgentStderr?: (chunk: string) => void; + onAgentSpawn?: (meta: { pid: number; startedAt: string }) => Promise; + spawnCwd?: string; + inheritProcessEnv?: boolean; onPermissionRequest?: (req: AcpPermissionRequest, ctx: { signal: AbortSignal; }) => Promise; diff --git a/dist/runtime.js b/dist/runtime.js index 6c9cc999e50a11c399c68b3a0f1b7af4bc2317c0..7ec28ecf778623c6e63a2149a599172c184c49bd 100644 --- a/dist/runtime.js +++ b/dist/runtime.js @@ -744,7 +744,8 @@ var AcpRuntimeManager = class { this.deps = deps; } createClient(options) { - return this.deps.clientFactory?.(options) ?? new AcpClient(options); + const clientOptions = { ...options, onAgentStderr: this.options.onAgentStderr, onAgentSpawn: this.options.onAgentSpawn, spawnCwd: this.options.spawnCwd, inheritProcessEnv: this.options.inheritProcessEnv }; + return this.deps.clientFactory?.(clientOptions) ?? new AcpClient(clientOptions); } async readPendingPersistentClient(record, options) { const pendingClient = this.pendingPersistentClients.get(record.acpxRecordId); diff --git a/dist/session-options-jkYbBxGE.d.ts b/dist/session-options-jkYbBxGE.d.ts index 9d37f377fb6a0828e0d2bc5a48754f3aa71509a4..22dda59e0b7616a20ad45218913e5d8f884bae49 100644 --- a/dist/session-options-jkYbBxGE.d.ts +++ b/dist/session-options-jkYbBxGE.d.ts @@ -84,6 +84,10 @@ type AcpClientOptions = { terminal?: boolean; suppressSdkConsoleErrors?: boolean; verbose?: boolean; + onAgentStderr?: (chunk: string) => void; + onAgentSpawn?: (meta: { pid: number; startedAt: string }) => Promise; + spawnCwd?: string; + inheritProcessEnv?: boolean; sessionOptions?: { model?: string; allowedTools?: string[];