@lucascouts/claude-agent-acp-plus 0.27.0 → 0.29.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/acp-agent.js CHANGED
@@ -19,7 +19,7 @@ import { filterSupersededModels } from "./model-recency.js";
19
19
  import { SettingsManager } from "./settings.js";
20
20
  import { ContextCompactionLifecycle, contextCompactionMetadataFromBoundary, } from "./context-compaction.js";
21
21
  import { createThinkingConfigOption, effectiveThinkingConfig, resolveThinkingSelection, THINKING_CONFIG_ID, } from "./thinking-option.js";
22
- import { effortOptionValue, isUltracodeAvailable, isUltracodeValue, ULTRACODE_OPTION_NAME, ULTRACODE_OPTION_VALUE, ultracodeFlagSettings, } from "./ultracode.js";
22
+ import { applyLegacyUltracodeEffort, applyUltracodeReadback, applyUltracodeToggle, effortFlagSettings, isLegacyUltracodeEffort, isUltracodeAvailable, readUltracodeState, resolveUltracodeRequested, ULTRACODE_CONFIG_ID, ultracodeConfigOption, } from "./ultracode.js";
23
23
  import { handleRewindCommand, parseRewindInvocation } from "./rewind-command.js";
24
24
  import { resolvePermissionMode, sessionAllowsBypass } from "./permissions/modes.js";
25
25
  import { normalizeDurablePermissionChangeSet } from "./permissions/normalization.js";
@@ -174,6 +174,14 @@ export const USAGE_CAPABILITY_VERSION = 1;
174
174
  * and a sample most of an interval old is exactly what the poll already
175
175
  * showed them. */
176
176
  export const USAGE_REFRESH_MAX_SAMPLE_AGE_MS = 5_000;
177
+ /** Parity item 106 (upstream issue #1284): how long a turn held for its
178
+ * background subagents (see `Turn.deferredSettle`) waits, once none of them is
179
+ * live and Claude Code is idle, for the followup cycle a task_notification
180
+ * would start. A notification that is lost starts none, and with no further
181
+ * idle nothing else would ever answer the prompt. A followup starts within
182
+ * milliseconds of its notification (the CLI flushes them together), so the
183
+ * bound only ever expires on a lost one. */
184
+ export const HELD_TURN_DRAIN_GRACE_MS = 5_000;
177
185
  /** The SDK's own text for a rejected control request, passed through to the
178
186
  * client as the internal error's message (R2.4). */
179
187
  function errorMessage(error) {
@@ -284,7 +292,11 @@ export function quotaPollIntervalMs(raw = process.env.CLAUDE_ACP_QUOTA_POLL_MS)
284
292
  * (the result is skipped, its trailing idle absorbed as owed, so the
285
293
  * #825 detector can't fire); misrouting an autonomous result into the
286
294
  * user lane is the bounded misattribution class this set exists to
287
- * reduce. */
295
+ * reduce.
296
+ *
297
+ * Exception: a result from one of these origins that names a pending prompt
298
+ * in `user_message_uuids` consumed that folded prompt and takes the user
299
+ * lane (see the result handler). */
288
300
  const AUTONOMOUS_RESULT_ORIGINS = new Set([
289
301
  "task-notification",
290
302
  "peer",
@@ -2221,6 +2233,40 @@ export class ClaudeAcpAgent {
2221
2233
  };
2222
2234
  /** The unsettled in-flight turn owning this prompt uuid, if any. */
2223
2235
  const findUnsettledTurn = (uuid) => (session.turnQueue ?? []).find((t) => t.promptUuid === uuid && !t.settled);
2236
+ /** Whether this result is the answer to a prompt that is still waiting.
2237
+ *
2238
+ * Claude Code can start a turn on its own, for example when a background
2239
+ * task finishes. If the user sends a prompt while that turn runs, Claude
2240
+ * Code adds the prompt to the running turn. The turn's result is still
2241
+ * marked as a background result, but it lists the uuids of the prompts it
2242
+ * answered.
2243
+ *
2244
+ * A turn held open for its background subagents already has its result,
2245
+ * so a result that names it does not answer it. */
2246
+ const answersPendingPrompt = (message) => {
2247
+ // Newer CLIs list every prompt the turn answered. Older ones name only
2248
+ // the last one.
2249
+ let answeredPromptUuids = [];
2250
+ if (Array.isArray(message.user_message_uuids)) {
2251
+ answeredPromptUuids = message.user_message_uuids;
2252
+ }
2253
+ else if (typeof message.user_message_uuid === "string") {
2254
+ answeredPromptUuids = [message.user_message_uuid];
2255
+ }
2256
+ for (const promptUuid of answeredPromptUuids) {
2257
+ const turn = findUnsettledTurn(promptUuid);
2258
+ if (turn === undefined) {
2259
+ // Not a prompt of this session, or it was answered already.
2260
+ continue;
2261
+ }
2262
+ if (isHeldOpen(turn)) {
2263
+ // This turn already has its result and only waits for its subagents.
2264
+ continue;
2265
+ }
2266
+ return true;
2267
+ }
2268
+ return false;
2269
+ };
2224
2270
  /** The first queued turn still awaiting its outcome, if any — the single
2225
2271
  * spelling of "a prompt is pending" shared by the head promotion and
2226
2272
  * the autonomous stretch-close guard. */
@@ -2291,6 +2337,34 @@ export class ClaudeAcpAgent {
2291
2337
  * while true, the turn's settlement stays deferred so the subagent's
2292
2338
  * output and permission requests land inside it (see
2293
2339
  * Turn.deferredSettle). */
2340
+ /** Ends the display terminal of a command that went to the background,
2341
+ * once its task ends (see `Session.backgroundTerminals`). The code is the
2342
+ * one Claude Code's summary names, else 1 for a failed or stopped task —
2343
+ * a known failure never goes out as null — and null for a completion
2344
+ * that names none. */
2345
+ const endBackgroundTerminal = async (taskId, exitCode) => {
2346
+ const terminal = session.backgroundTerminals?.get(taskId);
2347
+ if (!terminal)
2348
+ return;
2349
+ session.backgroundTerminals.delete(taskId);
2350
+ await sendUpdate({
2351
+ sessionId: params.sessionId,
2352
+ update: {
2353
+ sessionUpdate: "tool_call_update",
2354
+ toolCallId: terminal.toolCallId,
2355
+ _meta: {
2356
+ ...(terminal.parentToolUseId
2357
+ ? { claudeCode: { parentToolUseId: terminal.parentToolUseId } }
2358
+ : {}),
2359
+ terminal_exit: {
2360
+ terminal_id: terminal.toolCallId,
2361
+ exit_code: exitCode,
2362
+ signal: null,
2363
+ },
2364
+ },
2365
+ },
2366
+ });
2367
+ };
2294
2368
  const turnAwaitingSubagents = (turn) => {
2295
2369
  if (!turn.spawnedTaskIds?.size) {
2296
2370
  return false;
@@ -2318,6 +2392,33 @@ export class ClaudeAcpAgent {
2318
2392
  settleActive(turn.deferredSettle);
2319
2393
  }
2320
2394
  };
2395
+ /** Item 106: arms the drain grace (see `HELD_TURN_DRAIN_GRACE_MS`) when a
2396
+ * prune leaves the held turn with no live subagent while Claude Code is
2397
+ * idle — the state in which a lost task_notification parks the turn. At
2398
+ * expiry the turn settles only if nothing moved: same turn, still held,
2399
+ * still drained, still idle. A followup that started meanwhile (state
2400
+ * `running`) settles the turn itself at its result or idle. */
2401
+ let drainGrace;
2402
+ const armDrainGrace = () => {
2403
+ const turn = session.activeTurn;
2404
+ if (drainGrace !== undefined ||
2405
+ !isHeldOpen(turn) ||
2406
+ turnAwaitingSubagents(turn) ||
2407
+ session.lastSessionState !== "idle") {
2408
+ return;
2409
+ }
2410
+ drainGrace = setTimeout(() => {
2411
+ drainGrace = undefined;
2412
+ if (session.activeTurn === turn &&
2413
+ isHeldOpen(turn) &&
2414
+ !turnAwaitingSubagents(turn) &&
2415
+ session.lastSessionState === "idle") {
2416
+ this.logger.log(`[held-turn] settled after the drain grace: no followup came (task_notification lost?) session=${params.sessionId}`);
2417
+ settleDeferredIfDrained();
2418
+ }
2419
+ }, HELD_TURN_DRAIN_GRACE_MS);
2420
+ drainGrace.unref?.();
2421
+ };
2321
2422
  /** Settle the active turn with `outcome` now — unless subagents it
2322
2423
  * spawned are still live, in which case store the outcome and hold the
2323
2424
  * turn open (see Turn.deferredSettle). Every result-time settle of a
@@ -3270,6 +3371,8 @@ export class ClaudeAcpAgent {
3270
3371
  // The task settled — no further tool calls can originate
3271
3372
  // from it, so its registry entry can be dropped.
3272
3373
  session.liveBackgroundTasks.delete(message.task_id);
3374
+ await endBackgroundTerminal(message.task_id, backgroundExitCode(message.status, message.summary));
3375
+ armDrainGrace();
3273
3376
  if (session.taskFeed && session.taskFeedPublisher) {
3274
3377
  const readable = await endingOutputReadable(session, message.task_id, message.output_file);
3275
3378
  const change = session.taskFeed.onNotification(message);
@@ -3289,6 +3392,10 @@ export class ClaudeAcpAgent {
3289
3392
  message.patch.status === "failed" ||
3290
3393
  message.patch.status === "killed") {
3291
3394
  session.liveBackgroundTasks.delete(message.task_id);
3395
+ // Usually first: the notification with its summary follows
3396
+ // but is not guaranteed, so the terminal ends here.
3397
+ await endBackgroundTerminal(message.task_id, backgroundExitCode(message.patch.status, message.patch.error));
3398
+ armDrainGrace();
3292
3399
  }
3293
3400
  if (session.taskFeed && session.taskFeedPublisher) {
3294
3401
  // The CLI queues the terminal patch BEFORE the
@@ -3488,6 +3595,7 @@ export class ClaudeAcpAgent {
3488
3595
  session.liveBackgroundTasks.delete(taskId);
3489
3596
  }
3490
3597
  }
3598
+ armDrainGrace();
3491
3599
  }
3492
3600
  // The same level, forwarded: once the turn has settled the
3493
3601
  // client reads the thread as idle, and a background shell or
@@ -3509,7 +3617,10 @@ export class ClaudeAcpAgent {
3509
3617
  // the user's prompt's. Autonomous results must never touch the
3510
3618
  // user-turn lifecycle (stop reason, settles, failActive,
3511
3619
  // slash-command output forwarding), though their cost is real.
3512
- const isAutonomousResult = message.origin != null && AUTONOMOUS_RESULT_ORIGINS.has(message.origin.kind);
3620
+ // The exception: the user's prompt was added to that turn while it
3621
+ // ran, so its result answers the prompt (see answersPendingPrompt).
3622
+ const startedByClaudeCode = message.origin != null && AUTONOMOUS_RESULT_ORIGINS.has(message.origin.kind);
3623
+ const isAutonomousResult = startedByClaudeCode && !answersPendingPrompt(message);
3513
3624
  const pendingExitPlanModeInterruption = session.pendingExitPlanModeInterruption;
3514
3625
  const pendingExitPlanContextReset = session.pendingExitPlanContextReset;
3515
3626
  try {
@@ -4427,6 +4538,19 @@ export class ClaudeAcpAgent {
4427
4538
  // Before toAcpNotifications, which prunes the tool_use cache entry
4428
4539
  // that says the result is a Bash call's.
4429
4540
  observeBackgroundBashResult(message, content, session);
4541
+ // The command's terminal runs until its task ends, unless the task
4542
+ // has ended already (a fast command can end before its result).
4543
+ const runningTerminal = this.clientCapabilities?._meta?.["terminal_output"] === true
4544
+ ? backgroundBashTerminal(message, content, session)
4545
+ : undefined;
4546
+ if (runningTerminal && session.liveBackgroundTasks.has(runningTerminal.taskId)) {
4547
+ (session.backgroundTerminals ??= new Map()).set(runningTerminal.taskId, {
4548
+ toolCallId: runningTerminal.toolCallId,
4549
+ ...(message.parent_tool_use_id
4550
+ ? { parentToolUseId: message.parent_tool_use_id }
4551
+ : {}),
4552
+ });
4553
+ }
4430
4554
  for (const notification of toAcpNotifications(content, message.message.role, params.sessionId, session.toolUseCache, this.client, this.logger, {
4431
4555
  clientCapabilities: this.clientCapabilities,
4432
4556
  parentToolUseId: message.parent_tool_use_id,
@@ -4454,7 +4578,9 @@ export class ClaudeAcpAgent {
4454
4578
  // filtered out of `content` above; blocks that do pass through
4455
4579
  // (e.g. a subagent image) carry the stamped parentToolUseId
4456
4580
  // meta and are excluded there.
4457
- await sendUpdate(acceptedPlanToolResult(notification, acceptedPlanToolUseId));
4581
+ await sendUpdate(withRunningTerminal(acceptedPlanToolResult(notification, acceptedPlanToolUseId), runningTerminal && session.backgroundTerminals?.has(runningTerminal.taskId)
4582
+ ? runningTerminal.toolCallId
4583
+ : undefined));
4458
4584
  }
4459
4585
  break;
4460
4586
  }
@@ -5068,6 +5194,18 @@ export class ClaudeAcpAgent {
5068
5194
  await this.applyFastMode(session, resolveFastModeEnabled(params));
5069
5195
  return { configOptions: session.configOptions };
5070
5196
  }
5197
+ // Ultracode is a boolean too, and bypasses the same validation. The legacy
5198
+ // `effort = "ultracode"` (the retired notch) is accepted for one release.
5199
+ const useBoolean = clientSupportsBooleanConfigOptions(this.clientCapabilities);
5200
+ if (params.configId === ULTRACODE_CONFIG_ID) {
5201
+ await applyUltracodeToggle(session, resolveUltracodeRequested(params), useBoolean);
5202
+ return { configOptions: session.configOptions };
5203
+ }
5204
+ if (params.configId === EFFORT_CONFIG_ID &&
5205
+ isLegacyUltracodeEffort(params.value) &&
5206
+ (await applyLegacyUltracodeEffort(session, useBoolean))) {
5207
+ return { configOptions: session.configOptions };
5208
+ }
5071
5209
  // The Thinking toggle only records the session's intent — the SDK query
5072
5210
  // swap is deferred to the next prompt() start (lazy recreate, sub-task
5073
5211
  // 1.3), so there is no SDK call to fail here and the config option is
@@ -5696,6 +5834,13 @@ export class ClaudeAcpAgent {
5696
5834
  * Not written to `contextWindowCache` — that stays keyed to the
5697
5835
  * `result.modelUsage` spellings — and a result still overwrites it.
5698
5836
  * Ported from upstream #1186.
5837
+ *
5838
+ * Asks for the `summary` detail (parity item 97, upstream #1258): the
5839
+ * default `full` breakdown issues one `messages/count_tokens` call per
5840
+ * category, and only `rawMaxTokens` is read here. The two other callers
5841
+ * (`readResumedLiveModel`, `fetchContextUsedTokens`) read `totalTokens`,
5842
+ * which `summary` takes from the last response's usage plus local
5843
+ * estimates instead of counting — not the same number, so they keep `full`.
5699
5844
  */
5700
5845
  refreshContextWindowInBackground(sessionId, session) {
5701
5846
  if (session.contextWindowAuthoritative)
@@ -5707,7 +5852,7 @@ export class ClaudeAcpAgent {
5707
5852
  session.models.currentModelId === modelId;
5708
5853
  // A synchronous throw must not fail the caller either.
5709
5854
  Promise.resolve()
5710
- .then(() => query.getContextUsage())
5855
+ .then(() => query.getContextUsage({ detail: "summary" }))
5711
5856
  .then((usage) => {
5712
5857
  if (!stillCurrent() || session.contextWindowAuthoritative)
5713
5858
  return;
@@ -5753,7 +5898,10 @@ export class ClaudeAcpAgent {
5753
5898
  if (session.fastModeDisabledReason === "model_not_allowed") {
5754
5899
  session.fastModeDisabledReason = undefined;
5755
5900
  }
5756
- // Rebuild config options since effort levels depend on the selected model
5901
+ // Rebuild config options since effort levels depend on the selected model.
5902
+ // The new model decides whether Ultracode is shown (heuristic now, the
5903
+ // CLI's readback below); the retained intent decides its value.
5904
+ session.ultracodeAvailable = isUltracodeAvailable(newModelInfo?.supportsEffort ? (newModelInfo.supportedEffortLevels ?? []) : [], { disableWorkflows: session.workflowsDisabled });
5757
5905
  const effortOpt = session.configOptions.find((o) => o.id === EFFORT_CONFIG_ID);
5758
5906
  const currentEffort = typeof effortOpt?.currentValue === "string" ? effortOpt.currentValue : undefined;
5759
5907
  session.configOptions = buildConfigOptions(session.modes, session.models, session.modelInfos, currentEffort, session.agents, session.currentAgent, {
@@ -5772,15 +5920,7 @@ export class ClaudeAcpAgent {
5772
5920
  // (R1.6).
5773
5921
  session.thinkingEnabled ??
5774
5922
  effectiveThinkingConfig(undefined, process.env.MAX_THINKING_TOKENS, this.logger) !==
5775
- undefined, {
5776
- // The new model decides whether the entry renders at all; the session's
5777
- // retained intent decides whether it renders selected. A model without
5778
- // `xhigh` drops the entry, and `validEffort` then falls back for it the
5779
- // same way it does for any unsupported level.
5780
- available: isUltracodeAvailable(newModelInfo?.supportsEffort ? (newModelInfo.supportedEffortLevels ?? []) : [], { disableWorkflows: session.workflowsDisabled }),
5781
- enabled: session.ultracode,
5782
- }, {
5783
- disableWorkflows: session.workflowsDisabled,
5923
+ undefined, this.ultracodeState(session, session.ultracodeAvailable), {
5784
5924
  // Threaded for the same reason Thinking is (R1.7): an option not
5785
5925
  // passed through this rebuild silently drops from the picker on
5786
5926
  // every model switch. The account is model-independent, so the row
@@ -5792,8 +5932,7 @@ export class ClaudeAcpAgent {
5792
5932
  const newEffortOpt = session.configOptions.find((o) => o.id === EFFORT_CONFIG_ID);
5793
5933
  const newEffort = typeof newEffortOpt?.currentValue === "string" ? newEffortOpt.currentValue : undefined;
5794
5934
  if (newEffort !== currentEffort) {
5795
- await session.query.applyFlagSettings(ultracodeFlagSettings(newEffort));
5796
- session.ultracode = isUltracodeValue(newEffort);
5935
+ await session.query.applyFlagSettings(effortFlagSettings(newEffort, session.ultracodeRequested));
5797
5936
  }
5798
5937
  // Emit current_mode_update only after session.modes AND
5799
5938
  // session.configOptions have been fully reconciled. This way, a failure
@@ -5805,8 +5944,10 @@ export class ClaudeAcpAgent {
5805
5944
  await this.sessionModes.publishFallbackState(sessionId, session);
5806
5945
  }
5807
5946
  // Last, so the switch's own control requests don't queue behind it.
5808
- if (modelChanged)
5947
+ if (modelChanged) {
5809
5948
  this.refreshContextWindowInBackground(sessionId, session);
5949
+ this.refreshUltracodeInBackground(sessionId, session, false);
5950
+ }
5810
5951
  }
5811
5952
  else if (configId === AGENT_CONFIG_ID) {
5812
5953
  // Live agent switch — no subprocess restart needed. Apply the SDK flag
@@ -5843,11 +5984,9 @@ export class ClaudeAcpAgent {
5843
5984
  else {
5844
5985
  session.configOptions = session.configOptions.map((o) => o.id === configId && typeof o.currentValue === "string" ? { ...o, currentValue: value } : o);
5845
5986
  if (configId === EFFORT_CONFIG_ID) {
5846
- // Both keys, always. Selecting a plain level after Ultracode must CLEAR
5847
- // the flag, and only an explicit `null` clears it — see
5848
- // `ultracodeFlagSettings`.
5849
- await session.query.applyFlagSettings(ultracodeFlagSettings(value));
5850
- session.ultracode = isUltracodeValue(value);
5987
+ // An effort change without `ultracode` turns it off, so the intent
5988
+ // rides along — see `effortFlagSettings`.
5989
+ await session.query.applyFlagSettings(effortFlagSettings(value, session.ultracodeRequested));
5851
5990
  }
5852
5991
  }
5853
5992
  }
@@ -5900,6 +6039,50 @@ export class ClaudeAcpAgent {
5900
6039
  session.fastModeEnabled = enabled;
5901
6040
  this.refreshFastModeOption(session, enabled);
5902
6041
  }
6042
+ /** The Ultracode display state for `buildConfigOptions`. */
6043
+ ultracodeState(session, available) {
6044
+ return {
6045
+ available,
6046
+ requested: session.ultracodeRequested,
6047
+ useBooleanOption: clientSupportsBooleanConfigOptions(this.clientCapabilities),
6048
+ };
6049
+ }
6050
+ /**
6051
+ * Replace the Ultracode heuristic with the CLI's `applied` report, without
6052
+ * blocking the caller — never inline, because control requests queue ahead
6053
+ * of interrupt and close (upstream #1216). `seedIntent` at session start; a
6054
+ * model switch keeps its intent and only re-reads availability. Deferred a
6055
+ * tick so a resulting `config_option_update` follows the session/new reply.
6056
+ */
6057
+ refreshUltracodeInBackground(sessionId, session, seedIntent) {
6058
+ const { query } = session;
6059
+ const modelId = session.models.currentModelId;
6060
+ const requestedAtStart = session.ultracodeRequested;
6061
+ const stillCurrent = () => this.sessions[sessionId] === session &&
6062
+ session.query === query &&
6063
+ session.models.currentModelId === modelId;
6064
+ setTimeout(() => {
6065
+ void readUltracodeState(query, (error) => {
6066
+ this.logger.log(`[ultracode] get_settings failed session=${sessionId}: ${String(error)}`);
6067
+ })
6068
+ .then(async (readback) => {
6069
+ if (!readback || !stillCurrent())
6070
+ return;
6071
+ // A toggle that landed while the read was in flight is newer than it.
6072
+ const seed = seedIntent && session.ultracodeRequested === requestedAtStart;
6073
+ const useBoolean = clientSupportsBooleanConfigOptions(this.clientCapabilities);
6074
+ if (!applyUltracodeReadback(session, readback, seed, useBoolean))
6075
+ return;
6076
+ await this.client.sessionUpdate({
6077
+ sessionId,
6078
+ update: { sessionUpdate: "config_option_update", configOptions: session.configOptions },
6079
+ });
6080
+ })
6081
+ .catch((error) => {
6082
+ this.logger.error(`[ultracode] readback failed session=${sessionId}:`, error);
6083
+ });
6084
+ }, 0);
6085
+ }
5903
6086
  /** Lazily swap a session's SDK query for a fresh one so a Thinking change
5904
6087
  * takes effect on the next turn (R1.3): thinking has no live flag-settings
5905
6088
  * path in the SDK, so mid-session application goes through query recreation
@@ -6021,14 +6204,16 @@ export class ClaudeAcpAgent {
6021
6204
  // await is already included.
6022
6205
  const effortOpt = session.configOptions.find((o) => o.id === EFFORT_CONFIG_ID);
6023
6206
  const effortValue = typeof effortOpt?.currentValue === "string" ? effortOpt.currentValue : undefined;
6024
- const { effortLevel, ultracode } = ultracodeFlagSettings(effortValue);
6025
- // Only the positive case is re-applied: the replacement's flag layer
6207
+ const effortFlags = effortFlagSettings(effortValue, session.ultracodeRequested);
6208
+ // Only the positive cases are re-applied: the replacement's flag layer
6026
6209
  // starts empty, so clearing a key that was never set would be a control
6027
- // request that says nothing. `ultracode` is sent WITH its level rather
6028
- // than alone — the SDK requires an xhigh-capable model for it, and a
6029
- // flag layer carrying one half of the pair is a state no picker names.
6030
- if (effortLevel !== null) {
6031
- await replacement.applyFlagSettings(ultracode === true ? { effortLevel, ultracode: true } : { effortLevel });
6210
+ // request that says nothing. The Ultracode intent is replayed even at
6211
+ // Default effort.
6212
+ if (effortFlags.effortLevel !== null) {
6213
+ await replacement.applyFlagSettings(effortFlags);
6214
+ }
6215
+ else if (effortFlags.ultracode) {
6216
+ await replacement.applyFlagSettings({ ultracode: true });
6032
6217
  }
6033
6218
  const supportsFastMode = session.modelInfos.find((m) => m.value === session.models.currentModelId)
6034
6219
  ?.supportsFastMode ?? false;
@@ -6810,6 +6995,7 @@ export class ClaudeAcpAgent {
6810
6995
  disabledReason: fastModeDisabledReason,
6811
6996
  };
6812
6997
  const workflowsDisabled = settingsManager.getSettings().disableWorkflows === true;
6998
+ const ultracodeRequested = settingsManager.getSettings().ultracode === true;
6813
6999
  const configOptions = buildConfigOptions(modes, models,
6814
7000
  // Catalog-based (see `modelInfos` above), matching the model-switch
6815
7001
  // rebuild (which passes `session.modelInfos`): `buildConfigOptions`
@@ -6823,31 +7009,24 @@ export class ClaudeAcpAgent {
6823
7009
  // effectiveThinkingConfig(undefined, MAX_THINKING_TOKENS) from above, so
6824
7010
  // reusing it avoids re-parsing (and re-logging an invalid) env var —
6825
7011
  // exactly one error log per query creation.
6826
- thinking !== undefined, {
6827
- // Seeded from settings, not inferred from the level: `Settings.ultracode`
6828
- // is what the user (or a `--settings` payload) actually asked for, while
6829
- // `xhigh` on its own is a legitimate selection that is not Ultracode.
6830
- available: isUltracodeAvailable(currentModelInfo?.supportsEffort ? (currentModelInfo.supportedEffortLevels ?? []) : [], { disableWorkflows: workflowsDisabled }),
6831
- enabled: settingsManager.getSettings().ultracode === true,
6832
- }, {
6833
- disableWorkflows: workflowsDisabled,
7012
+ thinking !== undefined,
7013
+ // Seeded from settings and the heuristic; the CLI's own report replaces
7014
+ // both in the background (`refreshUltracodeInBackground`, below).
7015
+ this.ultracodeState({ ultracodeRequested }, isUltracodeAvailable(currentModelInfo?.supportsEffort ? (currentModelInfo.supportedEffortLevels ?? []) : [], { disableWorkflows: workflowsDisabled })), {
6834
7016
  // Both halves of the selector, resolved above alongside the env they
6835
7017
  // produced — so the row the client renders and the configuration
6836
7018
  // directory the query was actually started with cannot disagree.
6837
7019
  accounts: declaredAccounts,
6838
7020
  currentAccount: accountEntry?.value,
6839
7021
  });
6840
- // Apply the initial effort level to the SDK so it matches the UI default
7022
+ // Apply the initial effort level to the SDK so it matches the UI default.
7023
+ // It carries the Ultracode intent: an effort change without the key would
7024
+ // turn off an `ultracode: true` the session was started with.
6841
7025
  const initialEffort = configOptions.find((o) => o.id === EFFORT_CONFIG_ID);
6842
- // The picker's resolved value, not the raw setting: `buildConfigOptions`
6843
- // has already dropped Ultracode if this model cannot reach `xhigh`, and the
6844
- // session must track what is displayed rather than what was requested.
6845
- const initialUltracode = typeof initialEffort?.currentValue === "string" &&
6846
- isUltracodeValue(initialEffort.currentValue);
6847
7026
  if (initialEffort &&
6848
7027
  typeof initialEffort.currentValue === "string" &&
6849
7028
  initialEffort.currentValue !== "default") {
6850
- await q.applyFlagSettings(ultracodeFlagSettings(initialEffort.currentValue));
7029
+ await q.applyFlagSettings(effortFlagSettings(initialEffort.currentValue, ultracodeRequested));
6851
7030
  }
6852
7031
  // Seed the context window WITHOUT any extra IPC on the session/new path.
6853
7032
  // On session/load, the resumed session's own `getContextUsage` report — a
@@ -6912,7 +7091,8 @@ export class ClaudeAcpAgent {
6912
7091
  configOptions,
6913
7092
  agents,
6914
7093
  currentAgent,
6915
- ultracode: initialUltracode,
7094
+ ultracodeRequested,
7095
+ ultracodeAvailable: configOptions.some((o) => o.id === ULTRACODE_CONFIG_ID),
6916
7096
  workflowsDisabled,
6917
7097
  declaredAccounts,
6918
7098
  currentAccount: accountEntry?.value,
@@ -6960,6 +7140,7 @@ export class ClaudeAcpAgent {
6960
7140
  // A guessed window seed (text heuristic / default) is refined the same way,
6961
7141
  // unawaited; a resumed session's authoritative seed makes it a no-op.
6962
7142
  this.refreshContextWindowInBackground(sessionId, this.sessions[sessionId]);
7143
+ this.refreshUltracodeInBackground(sessionId, this.sessions[sessionId], true);
6963
7144
  return {
6964
7145
  sessionId,
6965
7146
  modes,
@@ -7293,16 +7474,11 @@ export function buildConfigOptions(modes, models, modelInfos, currentEffortLevel
7293
7474
  * Both session call sites always supply it (R1.1); `undefined` (direct
7294
7475
  * callers/tests) omits the row. */
7295
7476
  thinkingEnabled,
7296
- /** Display state for the Ultracode entry of the effort picker. Omitted by
7297
- * direct callers/tests, in which case availability is derived from
7298
- * `settings` and the entry renders unselected. */
7477
+ /** Display state for the Ultracode option, placed after effort. Omitted by
7478
+ * direct callers/tests, in which case the option is not shown. */
7299
7479
  ultracode,
7300
- /** Resolved session settings, read for `disableWorkflows` — the half of the
7301
- * Ultracode gate that is not a model capability — and, alongside them, the
7302
- * declared accounts plus the one in force, which decide whether an account
7303
- * selector is advertised at all (R6.1/R6.2). `accounts` is not a field of
7304
- * the SDK's `Settings`, so it is carried beside them rather than picked
7305
- * from them. */
7480
+ /** The declared accounts plus the one in force, which decide whether an
7481
+ * account selector is advertised at all (R6.1/R6.2). */
7306
7482
  settings) {
7307
7483
  const options = [
7308
7484
  SessionModeManager.configOption(modes),
@@ -7336,11 +7512,6 @@ settings) {
7336
7512
  ? (currentModelInfo.supportedEffortLevels ?? [])
7337
7513
  : [];
7338
7514
  if (supportedLevels.length > 0) {
7339
- // Ultracode rides the effort picker as one extra entry past the last level,
7340
- // which is where the VS Code extension draws it too. It is NOT a level (see
7341
- // `ultracode.ts`): the entry stands for `xhigh` plus workflow orchestration,
7342
- // and it is offered only when both halves are reachable.
7343
- const ultracodeAvailable = ultracode?.available ?? isUltracodeAvailable(supportedLevels, settings);
7344
7515
  const effortOptions = [
7345
7516
  { value: "default", name: "Default" },
7346
7517
  ...supportedLevels.map((level) => ({
@@ -7350,21 +7521,9 @@ settings) {
7350
7521
  .map((part) => (part ? part.charAt(0).toUpperCase() + part.slice(1) : part))
7351
7522
  .join(" "),
7352
7523
  })),
7353
- ...(ultracodeAvailable
7354
- ? [{ value: ULTRACODE_OPTION_VALUE, name: ULTRACODE_OPTION_NAME }]
7355
- : []),
7356
7524
  ];
7357
- const includes = (l) => l === "default" ||
7358
- supportedLevels.includes(l) ||
7359
- (ultracodeAvailable && l === ULTRACODE_OPTION_VALUE);
7360
- // `effortOptionValue` resolves the flag against the level BEFORE validation,
7361
- // so an Ultracode session on a model that dropped `xhigh` falls back to
7362
- // "Default" through the same path any unsupported level does.
7363
- const displayedEffort = effortOptionValue(currentEffortLevel, {
7364
- available: ultracodeAvailable,
7365
- enabled: ultracode?.enabled ?? false,
7366
- });
7367
- const validEffort = displayedEffort && includes(displayedEffort) ? displayedEffort : "default";
7525
+ const includes = (l) => l === "default" || supportedLevels.includes(l);
7526
+ const validEffort = currentEffortLevel && includes(currentEffortLevel) ? currentEffortLevel : "default";
7368
7527
  options.push({
7369
7528
  id: EFFORT_CONFIG_ID,
7370
7529
  name: "Effort",
@@ -7375,6 +7534,11 @@ settings) {
7375
7534
  options: effortOptions,
7376
7535
  });
7377
7536
  }
7537
+ // Ultracode: a toggle beside effort, not an effort level (`ultracode.ts`).
7538
+ const ultracodeOption = ultracodeConfigOption(ultracode);
7539
+ if (ultracodeOption) {
7540
+ options.push(ultracodeOption);
7541
+ }
7378
7542
  // Surface the Fast mode toggle only when the current model supports it. The
7379
7543
  // option renders as a native boolean toggle for Clients that opted in, and a
7380
7544
  // two-value select otherwise.
@@ -9005,6 +9169,71 @@ function getMatchingModelUsage(modelUsage, currentModel) {
9005
9169
  return { key: bestKey, usage: modelUsage[bestKey] };
9006
9170
  }
9007
9171
  }
9172
+ /**
9173
+ * Parity item 92: the Bash tool call and task of a command this result sent to
9174
+ * the background — the structured `BashOutput` carries `backgroundTaskId`, and
9175
+ * the message holds exactly one tool_result, of a Bash call.
9176
+ */
9177
+ function backgroundBashTerminal(message, content, session) {
9178
+ if (message.type !== "user" || !Array.isArray(content))
9179
+ return undefined;
9180
+ const result = message.tool_use_result;
9181
+ if (typeof result !== "object" || result === null || !("backgroundTaskId" in result)) {
9182
+ return undefined;
9183
+ }
9184
+ const taskId = result.backgroundTaskId;
9185
+ if (typeof taskId !== "string" || taskId === "")
9186
+ return undefined;
9187
+ const blocks = content.filter((c) => typeof c === "object" && c !== null && c.type === "tool_result");
9188
+ if (blocks.length !== 1)
9189
+ return undefined;
9190
+ const toolCallId = blocks[0].tool_use_id;
9191
+ if (session.toolUseCache[toolCallId]?.name !== "Bash")
9192
+ return undefined;
9193
+ return { taskId, toolCallId };
9194
+ }
9195
+ /**
9196
+ * Drops `terminal_exit` from the tool result update of `toolCallId`: the Bash
9197
+ * call returned as soon as its command detached, and the exit would mark the
9198
+ * terminal as ended while the command still runs.
9199
+ */
9200
+ export function withRunningTerminal(notification, toolCallId) {
9201
+ const update = notification.update;
9202
+ if (toolCallId === undefined ||
9203
+ update.sessionUpdate !== "tool_call_update" ||
9204
+ update.toolCallId !== toolCallId ||
9205
+ !update._meta ||
9206
+ !("terminal_exit" in update._meta)) {
9207
+ return notification;
9208
+ }
9209
+ const meta = { ...update._meta };
9210
+ delete meta.terminal_exit;
9211
+ const next = { ...update, _meta: meta };
9212
+ if (Object.keys(meta).length === 0)
9213
+ delete next._meta;
9214
+ return { ...notification, update: next };
9215
+ }
9216
+ /**
9217
+ * The exit code of a background command whose task ended, from what the task's
9218
+ * ending says. Claude Code's summary reads `Background command "<d>" completed
9219
+ * (exit code N[: note])` or `… failed with exit code N` (CLI 2.1.285); an
9220
+ * ending names a code only at its end, so a description holding the words
9221
+ * cannot be mistaken for it. A completion with a non-zero code is one Claude
9222
+ * Code accepted as a success (grep's "No matches found"), so it goes out as
9223
+ * null; a failure or stop that names no code goes out as 1, never null.
9224
+ */
9225
+ export function backgroundExitCode(status, text) {
9226
+ const failed = status === "failed" || status === "killed" || status === "stopped";
9227
+ const said = typeof text === "string" ? text : "";
9228
+ if (failed) {
9229
+ const match = /exit code (\d+)\s*$/.exec(said);
9230
+ return match ? Number(match[1]) : 1;
9231
+ }
9232
+ const match = /\(exit code (\d+)(?::[^)]*)?\)\s*$/.exec(said);
9233
+ if (match && Number(match[1]) === 0)
9234
+ return 0;
9235
+ return null;
9236
+ }
9008
9237
  /**
9009
9238
  * Story 041 (R1.1, R1.6): a backgrounded Bash call's result names the file the
9010
9239
  * CLI writes its output to. When the structured `BashOutput` carries
package/dist/tools.d.ts CHANGED
@@ -23,7 +23,8 @@ interface ToolUpdate {
23
23
  };
24
24
  terminal_exit?: {
25
25
  terminal_id: string;
26
- exit_code: number;
26
+ /** Null when the code is not known (as in `TerminalExitStatus`). */
27
+ exit_code: number | null;
27
28
  signal: string | null;
28
29
  };
29
30
  };
@@ -40,6 +41,12 @@ export type ClaudePlanEntry = {
40
41
  status: "pending" | "in_progress" | "completed";
41
42
  activeForm: string;
42
43
  };
44
+ /**
45
+ * The exit code the text of a failed command names. Claude Code starts the text
46
+ * of a command that exited with a failing code with `Exit code N`; other
47
+ * failures, such as a denial or a command that could not start, name none.
48
+ */
49
+ export declare function failureExitCode(text: string): number | undefined;
43
50
  export declare function planEntries(input: {
44
51
  todos: ClaudePlanEntry[];
45
52
  } | undefined): PlanEntry[];
@@ -1 +1 @@
1
- {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tools.d.ts","sourceRoot":"","sources":["../src/tools.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,SAAS,EACT,eAAe,EACf,gBAAgB,EAChB,QAAQ,EACT,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAC9D,OAAO,EAaL,eAAe,EACf,gBAAgB,EAChB,cAAc,EACd,eAAe,EACf,gBAAgB,EAKjB,MAAM,6CAA6C,CAAC;AACrD,OAAO,EAGL,oBAAoB,EAEpB,6BAA6B,EAE9B,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAEL,yCAAyC,EAGzC,qCAAqC,EAGrC,kCAAkC,EAGlC,+CAA+C,EAI/C,wBAAwB,EACxB,kCAAkC,EAIlC,gCAAgC,EAEhC,iCAAiC,EAClC,MAAM,sCAAsC,CAAC;AA2B9C,UAAU,QAAQ;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,QAAQ,CAAC;IACf,OAAO,EAAE,eAAe,EAAE,CAAC;IAC3B,SAAS,CAAC,EAAE,gBAAgB,EAAE,CAAC;CAChC;AAED,UAAU,UAAU;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,eAAe,EAAE,CAAC;IAC5B,SAAS,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC/B,KAAK,CAAC,EAAE;QACN,aAAa,CAAC,EAAE;YACd,WAAW,EAAE,MAAM,CAAC;SACrB,CAAC;QACF,eAAe,CAAC,EAAE;YAChB,WAAW,EAAE,MAAM,CAAC;YACpB,IAAI,EAAE,MAAM,CAAC;SACd,CAAC;QACF,aAAa,CAAC,EAAE;YACd,WAAW,EAAE,MAAM,CAAC;YACpB,oEAAoE;YACpE,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;YACzB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;SACvB,CAAC;KACH,CAAC;CACH;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAWpE;AAyCD,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,GAAG,EACZ,sBAAsB,GAAE,OAAe,EACvC,GAAG,CAAC,EAAE,MAAM,GACX,QAAQ,CA2WV;AAoFD,wBAAgB,wBAAwB,CACtC,UAAU,EACN,oBAAoB,GACpB,wBAAwB,GACxB,iCAAiC,GACjC,gCAAgC,GAChC,6BAA6B,GAC7B,qCAAqC,GACrC,yCAAyC,GACzC,+CAA+C,GAC/C,kCAAkC,GAClC,kCAAkC,EACtC,OAAO,EAAE,GAAG,GAAG,SAAS,EACxB,sBAAsB,GAAE,OAAe,EACvC,aAAa,CAAC,EAAE,OAAO,GACtB,UAAU,CAyVZ;AAiHD,MAAM,MAAM,eAAe,GAAG;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,SAAS,GAAG,aAAa,GAAG,WAAW,CAAC;IAChD,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAGhE;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE;IAAE,KAAK,EAAE,eAAe,EAAE,CAAA;CAAE,GAAG,SAAS,GAAG,SAAS,EAAE,CAMxF;AAED;;;;;;GAMG;AACH,MAAM,MAAM,SAAS,GAAG;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,SAAS,GAAG,aAAa,GAAG,WAAW,CAAC;IAChD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AACF,MAAM,MAAM,SAAS,GAAG,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;AAuD/C,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,OAAO,GAAG,gBAAgB,GAAG,SAAS,CAmBpF;AA0CD,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,OAAO,GAAG,cAAc,GAAG,SAAS,CA0DhF;AAED,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,OAAO,EAChB,cAAc,CAAC,EAAE,MAAM,GACtB,gBAAgB,GAAG,SAAS,CAwB9B;AAED,wBAAgB,eAAe,CAC7B,KAAK,EAAE,SAAS,EAChB,KAAK,EAAE,eAAe,GAAG,SAAS,EAClC,MAAM,EAAE,gBAAgB,GAAG,SAAS,GACnC,IAAI,CASN;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,eAAe,GAAG,SAAS,GAAG,IAAI,CAiB1F;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,cAAc,GAAG,IAAI,CAY5E;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,SAAS,GAAG,SAAS,EAAE,CAMpE;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQnD;AAeD;;;;;;GAMG;AACH,wBAAgB,8BAA8B,CAAC,YAAY,EAAE,OAAO,GAAG;IACrE,OAAO,CAAC,EAAE,eAAe,EAAE,CAAC;IAC5B,SAAS,CAAC,EAAE,gBAAgB,EAAE,CAAC;CAChC,CA4CA;AAcD,eAAO,MAAM,oBAAoB,GAC/B,WAAW,MAAM,EACjB,wBAEG;IACD,iBAAiB,CAAC,EAAE,CAClB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,OAAO,EAClB,YAAY,EAAE,OAAO,KAClB,OAAO,CAAC,IAAI,CAAC,CAAC;CACpB,SAKF,CAAC;AAGF,eAAO,MAAM,qBAAqB,GAC/B,UAAU;IAAE,eAAe,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAAE,KAAG,YAiBtD,CAAC;AAEJ;;;;;;;;;GASG;AACH,eAAO,MAAM,cAAc,GACxB,SAAS;IAAE,SAAS,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAAE,KAAG,YAsBpE,CAAC"}