lody 0.76.0 → 0.77.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.
@@ -27,14 +27,14 @@ import path__default from "node:path";
27
27
  import * as os$1 from "node:os";
28
28
  import os__default from "node:os";
29
29
  import process$1 from "node:process";
30
- import { a as CreateElicitationResponse, n as ndJsonStream, b as agent$1, m as methods, R as RequestError, p as packageJson } from "./chunks/package-C-zjBee4.js";
30
+ import { R as RequestError, a as CreateElicitationResponse, n as ndJsonStream, b as agent$1, m as methods, p as packageJson } from "./chunks/package-qnDHmQq4.js";
31
31
  import { execFile as execFile$1 } from "node:child_process";
32
32
  import { randomUUID as randomUUID$1 } from "node:crypto";
33
33
  import * as fs$2 from "node:fs/promises";
34
34
  import { promisify as promisify$1 } from "node:util";
35
35
  import * as fs$1 from "node:fs";
36
36
  import { WritableStream, ReadableStream as ReadableStream$1 } from "node:stream/web";
37
- import "./chunks/schemas-DAtmu1t9.js";
37
+ import "./chunks/schemas-Du3qLZPS.js";
38
38
  (async () => {
39
39
  var wW = Object.create;
40
40
  var { getPrototypeOf: TW, defineProperty: $y, getOwnPropertyNames: AW } = Object;
@@ -52928,6 +52928,63 @@ new Anthropic({ apiKey, dangerouslyAllowBrowser: true });
52928
52928
  }
52929
52929
  return null;
52930
52930
  }
52931
+ const GOAL_EXTENSION_VERSION = 1;
52932
+ const GOAL_CONTROL_METHOD = "_session/goal";
52933
+ const GOAL_ACTIONS = [
52934
+ "set",
52935
+ "clear"
52936
+ ];
52937
+ function goalUpdateFromPrompt(prompt) {
52938
+ const match = /^\/goal(?:\s+([\s\S]*))?$/.exec(prompt);
52939
+ const argument = match?.[1]?.trim();
52940
+ if (!argument) {
52941
+ return void 0;
52942
+ }
52943
+ if (argument === "clear") {
52944
+ return null;
52945
+ }
52946
+ return {
52947
+ objective: argument,
52948
+ status: "active",
52949
+ controlMethod: GOAL_CONTROL_METHOD
52950
+ };
52951
+ }
52952
+ function parseGoalRequest(params) {
52953
+ if (!params || typeof params !== "object") {
52954
+ throw RequestError.invalidParams(void 0, "goal params must be an object");
52955
+ }
52956
+ const { sessionId, action, objective } = params;
52957
+ if (typeof sessionId !== "string" || sessionId.length === 0) {
52958
+ throw RequestError.invalidParams(void 0, "goal params require a non-empty sessionId");
52959
+ }
52960
+ if (!GOAL_ACTIONS.includes(action)) {
52961
+ throw RequestError.invalidParams(void 0, 'goal action must be "set" or "clear"');
52962
+ }
52963
+ if (action === "set" && (typeof objective !== "string" || objective.trim().length === 0)) {
52964
+ throw RequestError.invalidParams(void 0, 'goal action "set" requires a non-empty objective');
52965
+ }
52966
+ return action === "set" ? {
52967
+ sessionId,
52968
+ action,
52969
+ objective: objective.trim()
52970
+ } : {
52971
+ sessionId,
52972
+ action: "clear"
52973
+ };
52974
+ }
52975
+ function toGoalSnapshot(message) {
52976
+ if (message.value === null) {
52977
+ return null;
52978
+ }
52979
+ return {
52980
+ objective: message.value.condition.trim(),
52981
+ status: "active",
52982
+ iterations: message.value.iterations,
52983
+ lastReason: message.value.last_reason ?? null,
52984
+ createdAt: message.value.set_at,
52985
+ controlMethod: GOAL_CONTROL_METHOD
52986
+ };
52987
+ }
52931
52988
  function mcpElicitationToCreateRequest(request, sessionId) {
52932
52989
  if (request.mode === "url") {
52933
52990
  if (!request.url) {
@@ -52984,6 +53041,7 @@ new Anthropic({ apiKey, dangerouslyAllowBrowser: true });
52984
53041
  return `question_${index}_custom`;
52985
53042
  }
52986
53043
  const OPTION_META_KEY = "_claude/askUserQuestionOption";
53044
+ const CUSTOM_ANSWER_META_KEY = "_askUserQuestionCustomAnswer";
52987
53045
  function askUserQuestionsToCreateRequest(questions, sessionId, toolCallId) {
52988
53046
  const single = questions.length === 1;
52989
53047
  const properties = {};
@@ -53023,7 +53081,13 @@ new Anthropic({ apiKey, dangerouslyAllowBrowser: true });
53023
53081
  properties[questionCustomFieldKey(index)] = {
53024
53082
  type: "string",
53025
53083
  title: "Other",
53026
- description: "Type your own answer instead of choosing an option above (optional)."
53084
+ description: "Type your own answer instead of choosing an option above (optional).",
53085
+ _meta: {
53086
+ [CUSTOM_ANSWER_META_KEY]: {
53087
+ questionId: questionFieldKey(index),
53088
+ isCustomAnswer: true
53089
+ }
53090
+ }
53027
53091
  };
53028
53092
  });
53029
53093
  const requestedSchema = {
@@ -53721,7 +53785,8 @@ ${output}\`\`\``
53721
53785
  }
53722
53786
  case "Bash": {
53723
53787
  const result = toolResult.content;
53724
- const terminalId = "tool_use_id" in toolResult ? String(toolResult.tool_use_id) : "";
53788
+ const terminalIdOf = (id) => typeof id === "string" && id.length > 0 ? id : void 0;
53789
+ const terminalId = terminalIdOf(toolUse?.id) ?? terminalIdOf("tool_use_id" in toolResult ? toolResult.tool_use_id : void 0);
53725
53790
  const isError = "is_error" in toolResult && toolResult.is_error;
53726
53791
  let output = "";
53727
53792
  let exitCode = isError ? 1 : 0;
@@ -53762,7 +53827,7 @@ ${output}\`\`\``
53762
53827
  return toAcpContentUpdate(result, isError);
53763
53828
  }
53764
53829
  }
53765
- if (supportsTerminalOutput) {
53830
+ if (supportsTerminalOutput && terminalId !== void 0) {
53766
53831
  return {
53767
53832
  content: [
53768
53833
  {
@@ -53945,25 +54010,26 @@ ${content.text}
53945
54010
  }
53946
54011
  function planEntries(input) {
53947
54012
  return (input?.todos ?? []).map((todo) => ({
53948
- content: todo.content,
54013
+ content: todo.status === "in_progress" && todo.activeForm ? todo.activeForm : todo.content,
53949
54014
  status: todo.status,
53950
54015
  priority: "medium"
53951
54016
  }));
53952
54017
  }
53953
- function parseTaskCreateOutput(content) {
54018
+ function parseJsonToolOutput(content, isExpectedOutput) {
53954
54019
  const tryParse = (text) => {
53955
54020
  try {
53956
54021
  const parsed = JSON.parse(text);
53957
- if (parsed && typeof parsed === "object" && parsed.task && typeof parsed.task.id === "string") {
53958
- return parsed;
53959
- }
54022
+ return isExpectedOutput(parsed) ? parsed : void 0;
53960
54023
  } catch {
54024
+ return void 0;
53961
54025
  }
53962
- return void 0;
53963
54026
  };
53964
54027
  if (typeof content === "string") {
53965
54028
  return tryParse(content);
53966
54029
  }
54030
+ if (content && typeof content === "object" && !Array.isArray(content)) {
54031
+ return isExpectedOutput(content) ? content : void 0;
54032
+ }
53967
54033
  if (Array.isArray(content)) {
53968
54034
  for (const block of content) {
53969
54035
  if (block && typeof block === "object" && "type" in block && block.type === "text") {
@@ -53977,6 +54043,82 @@ ${content.text}
53977
54043
  }
53978
54044
  return void 0;
53979
54045
  }
54046
+ function toolOutputTexts(content) {
54047
+ if (typeof content === "string") return [
54048
+ content
54049
+ ];
54050
+ if (!Array.isArray(content)) return [];
54051
+ return content.flatMap((block) => block && typeof block === "object" && "type" in block && block.type === "text" && "text" in block && typeof block.text === "string" ? [
54052
+ block.text
54053
+ ] : []);
54054
+ }
54055
+ function parseTaskCreateOutput(content) {
54056
+ const structured = parseJsonToolOutput(content, (parsed) => Boolean(parsed && typeof parsed === "object" && "task" in parsed && parsed.task && typeof parsed.task === "object" && "id" in parsed.task && typeof parsed.task.id === "string"));
54057
+ if (structured) return structured;
54058
+ for (const text of toolOutputTexts(content)) {
54059
+ const match = /^Task #(\S+) created successfully: (.+)$/.exec(text.trim());
54060
+ if (match) return {
54061
+ task: {
54062
+ id: match[1],
54063
+ subject: match[2]
54064
+ }
54065
+ };
54066
+ }
54067
+ return void 0;
54068
+ }
54069
+ function parseTaskListOutput(content) {
54070
+ const validStatuses = /* @__PURE__ */ new Set([
54071
+ "pending",
54072
+ "in_progress",
54073
+ "completed"
54074
+ ]);
54075
+ const structured = parseJsonToolOutput(content, (parsed) => Boolean(parsed && typeof parsed === "object" && "tasks" in parsed && Array.isArray(parsed.tasks) && parsed.tasks.every((task) => task && typeof task === "object" && typeof task.id === "string" && typeof task.subject === "string" && typeof task.status === "string" && validStatuses.has(task.status))));
54076
+ if (structured) return structured;
54077
+ for (const text of toolOutputTexts(content)) {
54078
+ if (text.trim() === "No tasks found") return {
54079
+ tasks: []
54080
+ };
54081
+ const tasks = [];
54082
+ const lines = text.trim().split("\n");
54083
+ for (const line of lines) {
54084
+ const match = /^#(\S+) \[(pending|in_progress|completed)\] (.+?)(?: \(([^()]*)\))?(?: \[blocked by ((?:#[^,\]]+(?:, )?)+)\])?$/.exec(line);
54085
+ if (!match) {
54086
+ tasks.length = 0;
54087
+ break;
54088
+ }
54089
+ tasks.push({
54090
+ id: match[1],
54091
+ subject: match[3],
54092
+ status: match[2],
54093
+ ...match[4] ? {
54094
+ owner: match[4]
54095
+ } : {},
54096
+ blockedBy: match[5] ? match[5].split(", ").map((id) => id.slice(1)) : []
54097
+ });
54098
+ }
54099
+ if (tasks.length > 0) return {
54100
+ tasks
54101
+ };
54102
+ }
54103
+ return void 0;
54104
+ }
54105
+ function parseTaskUpdateOutput(content, expectedTaskId) {
54106
+ const structured = parseJsonToolOutput(content, (parsed) => Boolean(parsed && typeof parsed === "object" && "success" in parsed && typeof parsed.success === "boolean" && "taskId" in parsed && typeof parsed.taskId === "string" && "updatedFields" in parsed && Array.isArray(parsed.updatedFields) && parsed.updatedFields.every((field) => typeof field === "string")));
54107
+ if (structured) return structured;
54108
+ for (const text of toolOutputTexts(content)) {
54109
+ const notFound = /^Task #(\S+) not found$/.exec(text.trim());
54110
+ const taskId = notFound?.[1] ?? expectedTaskId;
54111
+ if (taskId && (notFound || text.trim() === "Failed to delete task")) {
54112
+ return {
54113
+ success: false,
54114
+ taskId,
54115
+ updatedFields: [],
54116
+ error: text.trim()
54117
+ };
54118
+ }
54119
+ }
54120
+ return void 0;
54121
+ }
53980
54122
  function applyTaskCreate(state, input, output) {
53981
54123
  const taskId = output?.task?.id;
53982
54124
  if (!taskId || !input) return;
@@ -54003,9 +54145,22 @@ ${content.text}
54003
54145
  description: input.description ?? existing?.description
54004
54146
  });
54005
54147
  }
54148
+ function applyTaskList(state, output) {
54149
+ const previous = new Map(state);
54150
+ state.clear();
54151
+ for (const task of output.tasks) {
54152
+ const existing = previous.get(task.id);
54153
+ state.set(task.id, {
54154
+ subject: task.subject,
54155
+ status: task.status,
54156
+ activeForm: existing?.activeForm,
54157
+ description: existing?.description
54158
+ });
54159
+ }
54160
+ }
54006
54161
  function taskStateToPlanEntries(state) {
54007
54162
  return Array.from(state.values()).map((task) => ({
54008
- content: task.subject,
54163
+ content: task.status === "in_progress" && task.activeForm ? task.activeForm : task.subject,
54009
54164
  status: task.status,
54010
54165
  priority: "medium"
54011
54166
  }));
@@ -54458,16 +54613,22 @@ ${content.text}
54458
54613
  if (!params || typeof params !== "object") {
54459
54614
  throw RequestError.invalidParams(void 0, "steer params must be an object");
54460
54615
  }
54461
- const { sessionId, prompt } = params;
54616
+ const { sessionId, prompt, _meta } = params;
54462
54617
  if (typeof sessionId !== "string" || sessionId.length === 0) {
54463
54618
  throw RequestError.invalidParams(void 0, "steer params require a non-empty sessionId");
54464
54619
  }
54465
54620
  if (!Array.isArray(prompt) || prompt.length === 0) {
54466
54621
  throw RequestError.invalidParams(void 0, "steer params require a non-empty prompt array");
54467
54622
  }
54623
+ const steering = _meta && typeof _meta === "object" ? _meta.steering : void 0;
54624
+ const idleBehavior = steering && typeof steering === "object" ? steering.idleBehavior : void 0;
54625
+ if (idleBehavior !== void 0 && idleBehavior !== "promptRequired") {
54626
+ throw RequestError.invalidParams(void 0, "unsupported steering idleBehavior");
54627
+ }
54468
54628
  return {
54469
54629
  sessionId,
54470
- prompt
54630
+ prompt,
54631
+ _meta
54471
54632
  };
54472
54633
  }
54473
54634
  function getClientSteerId(meta) {
@@ -54492,6 +54653,9 @@ ${content.text}
54492
54653
  function isHeldOpen(turn) {
54493
54654
  return turn != null && turn.deferredSettle !== void 0 && !turn.settled;
54494
54655
  }
54656
+ function isSteering(turn) {
54657
+ return turn != null && turn.steeredEchoes !== void 0 && !turn.settled;
54658
+ }
54495
54659
  function disarmForceCancel(session) {
54496
54660
  if (session.forceCancelTimer) {
54497
54661
  clearTimeout(session.forceCancelTimer);
@@ -54513,6 +54677,18 @@ ${content.text}
54513
54677
  "bedrock",
54514
54678
  "vertex"
54515
54679
  ];
54680
+ const SUBAGENT_TRANSCRIPT_CAPABILITY = "subagent-transcript";
54681
+ function supportsSubagentTranscript(capabilities) {
54682
+ return capabilities?._meta?.[SUBAGENT_TRANSCRIPT_CAPABILITY] === true;
54683
+ }
54684
+ function parentToolUseIdOf(message) {
54685
+ if (!("parent_tool_use_id" in message)) return null;
54686
+ return typeof message.parent_tool_use_id === "string" ? message.parent_tool_use_id : null;
54687
+ }
54688
+ function stripSubagentTextAndThinking(content) {
54689
+ if (!Array.isArray(content)) return content;
54690
+ return content.filter((item) => !item || typeof item !== "object" || !("type" in item) || item.type !== "text" && item.type !== "thinking");
54691
+ }
54516
54692
  function scanStreamedToolInput(state) {
54517
54693
  let complete = false;
54518
54694
  for (let index = state.scannedTo; index < state.partialJson.length; index++) {
@@ -54696,32 +54872,116 @@ ${content.text}
54696
54872
  }
54697
54873
  return mapped;
54698
54874
  }
54699
- function describeAlwaysAllow(suggestions, toolName) {
54700
- if (!suggestions || suggestions.length === 0) {
54701
- return `Always Allow all ${toolName}`;
54875
+ function permissionLifetime(destination) {
54876
+ switch (destination) {
54877
+ case "session":
54878
+ return {
54879
+ scope: "session"
54880
+ };
54881
+ case "cliArg":
54882
+ return {
54883
+ scope: "process",
54884
+ storage: "cli_argument"
54885
+ };
54886
+ case "userSettings":
54887
+ return {
54888
+ scope: "persistent",
54889
+ storage: "user"
54890
+ };
54891
+ case "projectSettings":
54892
+ return {
54893
+ scope: "persistent",
54894
+ storage: "project"
54895
+ };
54896
+ case "localSettings":
54897
+ return {
54898
+ scope: "persistent",
54899
+ storage: "project_local"
54900
+ };
54901
+ default:
54902
+ return {
54903
+ scope: "unknown"
54904
+ };
54702
54905
  }
54703
- const ruleLabels = [];
54704
- const directories = [];
54705
- for (const update of suggestions) {
54706
- if (update.type === "addRules" && update.behavior === "allow") {
54707
- for (const rule of update.rules) {
54708
- ruleLabels.push(rule.ruleContent ? `${rule.toolName}(${rule.ruleContent})` : `all ${rule.toolName}`);
54906
+ }
54907
+ function permissionMetadataForAlwaysAllow(suggestions, toolName) {
54908
+ const effectiveSuggestions = suggestions && suggestions.length > 0 ? suggestions : [
54909
+ {
54910
+ type: "addRules",
54911
+ rules: [
54912
+ {
54913
+ toolName
54914
+ }
54915
+ ],
54916
+ behavior: "allow",
54917
+ destination: "session"
54918
+ }
54919
+ ];
54920
+ const changes = [];
54921
+ for (const update of effectiveSuggestions) {
54922
+ switch (update.type) {
54923
+ case "addRules":
54924
+ case "removeRules":
54925
+ case "replaceRules": {
54926
+ const operation = update.type === "addRules" ? "add" : update.type === "removeRules" ? "remove" : "replace";
54927
+ const targets = update.rules.map((rule) => ({
54928
+ type: "tool",
54929
+ toolName: rule.toolName,
54930
+ ...rule.ruleContent ? {
54931
+ matcher: {
54932
+ type: "provider_rule",
54933
+ provider: "claudeCode",
54934
+ value: rule.ruleContent
54935
+ }
54936
+ } : {}
54937
+ }));
54938
+ const renderedRules = update.rules.map((rule) => rule.ruleContent ? `${rule.toolName} calls matching ${rule.ruleContent}` : `all ${rule.toolName} calls`).join(", ");
54939
+ const verb = operation === "add" ? update.behavior === "allow" ? "Allow" : update.behavior === "deny" ? "Deny" : "Ask before" : operation === "remove" ? `Remove ${update.behavior} rules for` : `Replace ${update.behavior} rules with`;
54940
+ changes.push({
54941
+ type: "policy_rule",
54942
+ operation,
54943
+ ruleBehavior: update.behavior,
54944
+ description: `${verb} ${renderedRules}`,
54945
+ lifetime: permissionLifetime(update.destination),
54946
+ targets
54947
+ });
54948
+ break;
54709
54949
  }
54710
- } else if (update.type === "addDirectories") {
54711
- directories.push(...update.directories);
54950
+ case "addDirectories":
54951
+ case "removeDirectories": {
54952
+ const operation = update.type === "addDirectories" ? "add" : "remove";
54953
+ changes.push({
54954
+ type: "policy_rule",
54955
+ operation,
54956
+ ruleBehavior: "allow",
54957
+ description: operation === "add" ? `Allow filesystem access under ${update.directories.join(", ")}` : `Remove additional filesystem access under ${update.directories.join(", ")}`,
54958
+ lifetime: permissionLifetime(update.destination),
54959
+ targets: update.directories.map((path2) => ({
54960
+ type: "filesystem",
54961
+ matcher: {
54962
+ type: "directory",
54963
+ path: path2
54964
+ }
54965
+ }))
54966
+ });
54967
+ break;
54968
+ }
54969
+ case "setMode":
54970
+ changes.push({
54971
+ type: "permission_mode",
54972
+ operation: "set",
54973
+ provider: "claudeCode",
54974
+ mode: update.mode,
54975
+ description: `Set Claude Code permission mode to ${update.mode}`,
54976
+ lifetime: permissionLifetime(update.destination)
54977
+ });
54978
+ break;
54712
54979
  }
54713
54980
  }
54714
- const parts = [];
54715
- if (ruleLabels.length > 0) {
54716
- parts.push(ruleLabels.join(", "));
54717
- }
54718
- if (directories.length > 0) {
54719
- parts.push(`access to ${directories.join(", ")}`);
54720
- }
54721
- if (parts.length === 0) {
54722
- return `Always Allow all ${toolName}`;
54723
- }
54724
- return `Always Allow ${parts.join(" and ")}`;
54981
+ return {
54982
+ version: 1,
54983
+ changes
54984
+ };
54725
54985
  }
54726
54986
  class ClientConnection {
54727
54987
  ctx;
@@ -54934,6 +55194,13 @@ ${content.text}
54934
55194
  _meta: {
54935
55195
  steering: {
54936
55196
  supported: true
55197
+ },
55198
+ goal: {
55199
+ version: GOAL_EXTENSION_VERSION,
55200
+ controlMethod: GOAL_CONTROL_METHOD,
55201
+ actions: [
55202
+ ...GOAL_ACTIONS
55203
+ ]
54937
55204
  }
54938
55205
  }
54939
55206
  };
@@ -55150,6 +55417,9 @@ ${content.text}
55150
55417
  if (session.queryClosed) {
55151
55418
  throw RequestError.internalError(void 0, SESSION_ENDED_MESSAGE);
55152
55419
  }
55420
+ if (Array.from(session.taskState.values()).some((task) => task.status !== "completed")) {
55421
+ await this.publishTaskPlan(params.sessionId, session.taskState);
55422
+ }
55153
55423
  const userMessage = promptToClaude(params);
55154
55424
  const clientSteerId = getClientSteerId(params._meta);
55155
55425
  if (clientSteerId) {
@@ -55177,11 +55447,87 @@ ${content.text}
55177
55447
  session.turnQueue.push(turn);
55178
55448
  session.input.push(userMessage);
55179
55449
  this.ensureConsumer(session, params.sessionId);
55450
+ await this.publishGoalFromPrompt(params.sessionId, firstText, promptUuid);
55180
55451
  return response;
55181
55452
  }
55453
+ async goal(params) {
55454
+ const command = params.action === "set" ? `/goal ${params.objective}` : "/goal clear";
55455
+ const prompt = [
55456
+ {
55457
+ type: "text",
55458
+ text: command
55459
+ }
55460
+ ];
55461
+ const steering = await this.steer({
55462
+ sessionId: params.sessionId,
55463
+ prompt,
55464
+ _meta: {
55465
+ steering: {
55466
+ idleBehavior: "promptRequired"
55467
+ }
55468
+ }
55469
+ });
55470
+ if (steering.outcome === "promptRequired") {
55471
+ await this.prompt({
55472
+ sessionId: params.sessionId,
55473
+ prompt
55474
+ });
55475
+ }
55476
+ return {};
55477
+ }
55478
+ async publishGoal(sessionId, goal) {
55479
+ const session = this.sessions[sessionId];
55480
+ if (session) {
55481
+ session.lastPublishedGoal = goal;
55482
+ }
55483
+ await this.client.sessionUpdate({
55484
+ sessionId,
55485
+ update: {
55486
+ sessionUpdate: "session_info_update",
55487
+ _meta: {
55488
+ goal
55489
+ }
55490
+ }
55491
+ });
55492
+ }
55493
+ async publishTaskPlan(sessionId, taskState) {
55494
+ await this.client.sessionUpdate({
55495
+ sessionId,
55496
+ update: {
55497
+ sessionUpdate: "plan",
55498
+ entries: taskStateToPlanEntries(taskState)
55499
+ }
55500
+ });
55501
+ }
55502
+ async publishGoalFromPrompt(sessionId, prompt, commandUuid) {
55503
+ const goalUpdate = goalUpdateFromPrompt(prompt);
55504
+ if (goalUpdate !== void 0) {
55505
+ const session = this.sessions[sessionId];
55506
+ if (session) {
55507
+ session.pendingGoalUpdate = {
55508
+ commandUuid,
55509
+ expected: goalUpdate,
55510
+ previous: session.lastPublishedGoal,
55511
+ started: false
55512
+ };
55513
+ }
55514
+ await this.publishGoal(sessionId, goalUpdate);
55515
+ }
55516
+ }
55517
+ async publishRuntimeGoal(sessionId, goal) {
55518
+ const session = this.sessions[sessionId];
55519
+ const pending = session?.pendingGoalUpdate;
55520
+ if (pending) {
55521
+ const matchesPending = pending.expected === null ? goal === null : goal !== null && goal.objective === pending.expected.objective;
55522
+ if (!matchesPending) {
55523
+ return;
55524
+ }
55525
+ session.pendingGoalUpdate = void 0;
55526
+ }
55527
+ await this.publishGoal(sessionId, goal);
55528
+ }
55182
55529
  async steer(params) {
55183
55530
  const sessionId = params.sessionId;
55184
- const prompt = params.prompt;
55185
55531
  const session = this.sessions[sessionId];
55186
55532
  if (!session) {
55187
55533
  throw new Error("Session not found");
@@ -55189,23 +55535,41 @@ ${content.text}
55189
55535
  if (session.queryClosed) {
55190
55536
  throw RequestError.internalError(void 0, SESSION_ENDED_MESSAGE);
55191
55537
  }
55192
- const turnInFlight = (session.turnQueue ?? []).some((t) => !t.settled);
55193
- const promptRequest = {
55194
- sessionId,
55195
- prompt
55196
- };
55538
+ const turnInFlight = (session.turnQueue ?? []).find((turn) => !turn.settled);
55197
55539
  if (!turnInFlight) {
55198
- this.prompt(promptRequest).catch((error) => {
55540
+ const promptRequest2 = {
55541
+ sessionId,
55542
+ prompt: params.prompt
55543
+ };
55544
+ if (params._meta?.steering?.idleBehavior === "promptRequired") {
55545
+ return {
55546
+ outcome: "promptRequired",
55547
+ reason: "noRunningTurn"
55548
+ };
55549
+ }
55550
+ this.prompt(promptRequest2).catch((error) => {
55199
55551
  this.logger.error(`Session ${sessionId}: steered new turn failed: ${error}`);
55200
55552
  });
55201
55553
  return {
55202
55554
  outcome: "startedNewTurn"
55203
55555
  };
55204
55556
  }
55557
+ const promptRequest = {
55558
+ sessionId,
55559
+ prompt: params.prompt
55560
+ };
55205
55561
  const userMessage = promptToClaude(promptRequest);
55206
- userMessage.uuid = randomUUID$1();
55562
+ const steeredUuid = randomUUID$1();
55563
+ userMessage.uuid = steeredUuid;
55207
55564
  userMessage.priority = STEER_PRIORITY;
55565
+ (turnInFlight.steeredEchoes ??= /* @__PURE__ */ new Set()).add(steeredUuid);
55566
+ if (turnInFlight.deferredSettle !== void 0) {
55567
+ turnInFlight.steeredSettle = turnInFlight.deferredSettle;
55568
+ turnInFlight.deferredSettle = void 0;
55569
+ }
55208
55570
  session.input.push(userMessage);
55571
+ const firstText = params.prompt[0]?.type === "text" ? params.prompt[0].text : "";
55572
+ await this.publishGoalFromPrompt(sessionId, firstText, steeredUuid);
55209
55573
  return {
55210
55574
  outcome: "injected"
55211
55575
  };
@@ -55354,6 +55718,10 @@ ${content.text}
55354
55718
  }
55355
55719
  };
55356
55720
  const settleOrDefer = (outcome) => {
55721
+ if (isSteering(session.activeTurn)) {
55722
+ session.activeTurn.steeredSettle = outcome;
55723
+ return;
55724
+ }
55357
55725
  if (session.activeTurn && !session.activeTurn.settled && turnAwaitingSubagents(session.activeTurn)) {
55358
55726
  session.activeTurn.deferredSettle = outcome;
55359
55727
  } else {
@@ -55543,6 +55911,11 @@ ${content.text}
55543
55911
  }
55544
55912
  continue;
55545
55913
  }
55914
+ if (message.type === "active_goal") {
55915
+ const activeGoal = message;
55916
+ await this.publishRuntimeGoal(params.sessionId, toGoalSnapshot(activeGoal));
55917
+ continue;
55918
+ }
55546
55919
  switch (message.type) {
55547
55920
  case "system":
55548
55921
  switch (message.subtype) {
@@ -55550,7 +55923,7 @@ ${content.text}
55550
55923
  if (message.capabilities?.includes("msg_lifecycle_v1")) {
55551
55924
  session.msgLifecycleV1 = true;
55552
55925
  }
55553
- await this.syncFastModeState(message.session_id, session, message.fast_mode_state);
55926
+ await this.syncFastModeState(message.session_id, session, message.fast_mode_state, message.fast_mode_disabled_reason);
55554
55927
  break;
55555
55928
  case "status": {
55556
55929
  if (message.status === "compacting") {
@@ -55640,6 +56013,14 @@ Compacting failed${reason}`
55640
56013
  settleDeferredIfDrained();
55641
56014
  } else if (session.owedTrailingIdles > 0) {
55642
56015
  session.owedTrailingIdles--;
56016
+ } else if (isSteering(session.activeTurn)) {
56017
+ const steered = session.activeTurn;
56018
+ if (steered.steeredEchoes?.size === 0 && steered.steeredSettle !== void 0) {
56019
+ steered.deferredSettle = steered.steeredSettle;
56020
+ steered.steeredEchoes = void 0;
56021
+ steered.steeredSettle = void 0;
56022
+ settleDeferredIfDrained();
56023
+ }
55643
56024
  } else if (!session.cancelled && session.activeTurn && !session.activeTurn.settled) {
55644
56025
  this.logger.error(`Session ${params.sessionId}: SDK went idle without emitting a result for the active turn; failing the in-flight prompt (issue #825)`);
55645
56026
  failActive(RequestError.internalError(errorKindData("no_result"), TURN_NO_RESULT_MESSAGE));
@@ -55704,6 +56085,10 @@ Compacting failed${reason}`
55704
56085
  break;
55705
56086
  }
55706
56087
  case "permission_denied": {
56088
+ if (!session.emittedToolCalls.has(message.tool_use_id)) {
56089
+ break;
56090
+ }
56091
+ const parentToolUseId = message.agent_id ? session.liveBackgroundTasks.get(message.agent_id)?.parentToolUseId : void 0;
55707
56092
  const reason = message.decision_reason ?? message.message;
55708
56093
  await sendUpdate({
55709
56094
  sessionId: message.session_id,
@@ -55723,6 +56108,9 @@ Compacting failed${reason}`
55723
56108
  _meta: {
55724
56109
  claudeCode: {
55725
56110
  toolName: message.tool_name,
56111
+ ...parentToolUseId ? {
56112
+ parentToolUseId
56113
+ } : {},
55726
56114
  toolResponse: {
55727
56115
  decisionReasonType: message.decision_reason_type,
55728
56116
  decisionReason: message.decision_reason,
@@ -55849,14 +56237,23 @@ ${message.api_refusal_explanation}` : "";
55849
56237
  const isAutonomousResult = message.origin != null && AUTONOMOUS_RESULT_ORIGINS.has(message.origin.kind);
55850
56238
  try {
55851
56239
  if (!isAutonomousResult) {
55852
- await this.syncFastModeState(params.sessionId, session, message.fast_mode_state);
56240
+ await this.syncFastModeState(params.sessionId, session, message.fast_mode_state, message.fast_mode_disabled_reason);
55853
56241
  }
55854
56242
  if (!isAutonomousResult) {
55855
56243
  recordResultForOrphanCommands();
55856
56244
  await ensureActiveTurn();
56245
+ if (session.pendingGoalUpdate?.started) {
56246
+ const pendingGoalUpdate = session.pendingGoalUpdate;
56247
+ session.pendingGoalUpdate = void 0;
56248
+ const goalCommandFailed = message.is_error || message.stop_reason === "refusal" || "result" in message && message.result.includes("Please run /login");
56249
+ if (goalCommandFailed) {
56250
+ await this.publishGoal(params.sessionId, pendingGoalUpdate.previous ?? null);
56251
+ }
56252
+ }
55857
56253
  }
55858
56254
  const deliveredAssistantText = session.emittedAssistantText;
55859
- if (isAutonomousResult || !session.cancelled || !session.activeTurn) {
56255
+ const owesTrailingIdle = isAutonomousResult || !isSteering(session.activeTurn);
56256
+ if (owesTrailingIdle && (isAutonomousResult || !session.cancelled || !session.activeTurn)) {
55860
56257
  session.owedTrailingIdles++;
55861
56258
  }
55862
56259
  if (!isAutonomousResult) {
@@ -55954,6 +56351,13 @@ ${message.api_refusal_explanation}` : "";
55954
56351
  });
55955
56352
  break;
55956
56353
  }
56354
+ if (message.is_error && isSteering(session.activeTurn) && session.activeTurn.steeredEchoes.size > 0) {
56355
+ settleOrDefer({
56356
+ stopReason: "end_turn",
56357
+ usage: sessionUsage(session)
56358
+ });
56359
+ break;
56360
+ }
55957
56361
  switch (message.subtype) {
55958
56362
  case "success": {
55959
56363
  if (message.result.includes("Please run /login")) {
@@ -56094,6 +56498,9 @@ ${message.api_refusal_explanation}` : "";
56094
56498
  case "user":
56095
56499
  case "assistant": {
56096
56500
  if (message.type === "user" && "uuid" in message && message.uuid) {
56501
+ if (session.pendingGoalUpdate?.commandUuid === message.uuid) {
56502
+ session.pendingGoalUpdate.started = true;
56503
+ }
56097
56504
  const queued = findUnsettledTurn(message.uuid);
56098
56505
  if (queued) {
56099
56506
  if (session.activeTurn !== queued) {
@@ -56106,6 +56513,9 @@ ${message.api_refusal_explanation}` : "";
56106
56513
  });
56107
56514
  } else if (isHeldOpen(session.activeTurn)) {
56108
56515
  settleActive(session.activeTurn.deferredSettle);
56516
+ } else if (isSteering(session.activeTurn) && session.activeTurn.steeredSettle !== void 0) {
56517
+ session.owedTrailingIdles++;
56518
+ settleActive(session.activeTurn.steeredSettle);
56109
56519
  } else {
56110
56520
  settleActive({
56111
56521
  stopReason: "end_turn",
@@ -56118,6 +56528,9 @@ ${message.api_refusal_explanation}` : "";
56118
56528
  break;
56119
56529
  }
56120
56530
  if ("isReplay" in message && message.isReplay) {
56531
+ if (isSteering(session.activeTurn)) {
56532
+ session.activeTurn.steeredEchoes.delete(message.uuid);
56533
+ }
56121
56534
  break;
56122
56535
  }
56123
56536
  }
@@ -56201,7 +56614,7 @@ ${message.api_refusal_explanation}` : "";
56201
56614
  }
56202
56615
  content = kept;
56203
56616
  streamedBlocks.length = 0;
56204
- } else if (message.type === "assistant") {
56617
+ } else if (message.type === "assistant" && !(session.forwardSubagentText || supportsSubagentTranscript(this.clientCapabilities))) {
56205
56618
  content = message.message.content.filter((item) => item.type !== "text" && item.type !== "thinking");
56206
56619
  } else {
56207
56620
  content = message.message.content;
@@ -56224,11 +56637,15 @@ ${message.api_refusal_explanation}` : "";
56224
56637
  break;
56225
56638
  }
56226
56639
  case "tool_progress": {
56640
+ const toolCallId = session.emittedToolCalls.has(message.tool_use_id) ? message.tool_use_id : message.parent_tool_use_id;
56641
+ if (toolCallId === null || !session.emittedToolCalls.has(toolCallId)) {
56642
+ break;
56643
+ }
56227
56644
  await sendUpdate({
56228
56645
  sessionId: message.session_id,
56229
56646
  update: {
56230
56647
  sessionUpdate: "tool_call_update",
56231
- toolCallId: message.tool_use_id,
56648
+ toolCallId,
56232
56649
  status: "in_progress",
56233
56650
  _meta: {
56234
56651
  claudeCode: {
@@ -56264,10 +56681,14 @@ ${message.api_refusal_explanation}` : "";
56264
56681
  }
56265
56682
  break;
56266
56683
  }
56684
+ case "conversation_reset": {
56685
+ session.taskState.clear();
56686
+ await this.publishTaskPlan(params.sessionId, session.taskState);
56687
+ break;
56688
+ }
56267
56689
  case "tool_use_summary":
56268
56690
  case "auth_status":
56269
56691
  case "prompt_suggestion":
56270
- case "conversation_reset":
56271
56692
  break;
56272
56693
  default:
56273
56694
  unreachable(message, this.logger);
@@ -56306,6 +56727,11 @@ ${message.api_refusal_explanation}` : "";
56306
56727
  return;
56307
56728
  }
56308
56729
  session.cancelled = true;
56730
+ if (isSteering(session.activeTurn)) {
56731
+ for (const uuid of session.activeTurn.steeredEchoes) {
56732
+ this.trackOrphanCommand(session, uuid, "pending");
56733
+ }
56734
+ }
56309
56735
  const lifecycleLane = session.msgLifecycleV1 === true;
56310
56736
  const orphanedTurns = [];
56311
56737
  if (session.turnQueue) {
@@ -56352,6 +56778,9 @@ ${message.api_refusal_explanation}` : "";
56352
56778
  });
56353
56779
  }
56354
56780
  }
56781
+ if (isSteering(session.activeTurn) && session.activeTurn.steeredSettle !== void 0) {
56782
+ session.owedTrailingIdles++;
56783
+ }
56355
56784
  if (session.activeTurn && session.cancelController && !session.cancelController.signal.aborted && !session.forceCancelTimer) {
56356
56785
  const cancelController = session.cancelController;
56357
56786
  session.forceCancelTimer = setTimeout(() => {
@@ -56529,12 +56958,17 @@ ${message.api_refusal_explanation}` : "";
56529
56958
  async replaySessionHistory(sessionId) {
56530
56959
  const toolUseCache = {};
56531
56960
  const messages = await Rkt(sessionId);
56961
+ const forwardSubagentText = this.sessions[sessionId]?.forwardSubagentText ?? supportsSubagentTranscript(this.clientCapabilities);
56532
56962
  for (const message of messages) {
56533
56963
  const replayMessageId = messageIdForGrouping(message);
56534
56964
  if (message.type === "assistant" && isSyntheticLoginMessage(message.message)) {
56535
56965
  continue;
56536
56966
  }
56537
56967
  let content = message.message.content;
56968
+ const parentToolUseId = parentToolUseIdOf(message);
56969
+ if (message.type === "assistant" && parentToolUseId && !forwardSubagentText) {
56970
+ content = stripSubagentTextAndThinking(content);
56971
+ }
56538
56972
  if (message.message.role === "user") {
56539
56973
  content = stripLocalCommandMetadata(content);
56540
56974
  if (content === null) continue;
@@ -56544,7 +56978,8 @@ ${message.api_refusal_explanation}` : "";
56544
56978
  clientCapabilities: this.clientCapabilities,
56545
56979
  cwd: this.sessions[sessionId]?.cwd,
56546
56980
  taskState: this.sessions[sessionId]?.taskState,
56547
- messageId: replayMessageId
56981
+ messageId: replayMessageId,
56982
+ parentToolUseId
56548
56983
  })) {
56549
56984
  await this.client.sessionUpdate(notification);
56550
56985
  }
@@ -56605,7 +57040,6 @@ ${message.api_refusal_explanation}` : "";
56605
57040
  }
56606
57041
  canUseTool(sessionId) {
56607
57042
  return async (toolName, toolInput, { signal, suggestions, toolUseID, agentID, matchedAskRule }) => {
56608
- const alwaysAllowLabel = describeAlwaysAllow(suggestions, toolName);
56609
57043
  const supportsTerminalOutput = this.clientCapabilities?._meta?.["terminal_output"] === true;
56610
57044
  const session = this.sessions[sessionId];
56611
57045
  if (!session) {
@@ -56616,7 +57050,7 @@ ${message.api_refusal_explanation}` : "";
56616
57050
  }
56617
57051
  const parentToolUseId = agentID ? session.liveBackgroundTasks.get(agentID)?.parentToolUseId : void 0;
56618
57052
  if (agentID && !parentToolUseId) {
56619
- this.logger.log(`[claude-agent-acp] No parent tool_use recorded for subagent ${agentID}; sending the ${toolName} permission request unattributed`);
57053
+ this.logger.log(`[acp-extension-claude] No parent tool_use recorded for subagent ${agentID}; sending the ${toolName} permission request unattributed`);
56620
57054
  }
56621
57055
  if (toolName === "AskUserQuestion" && this.clientCapabilities?.elicitation?.form) {
56622
57056
  await this.ensureToolCallEmitted(sessionId, toolName, toolUseID, toolInput, parentToolUseId);
@@ -56727,19 +57161,22 @@ ${message.api_refusal_explanation}` : "";
56727
57161
  const response = await this.requestPermissionFromClient({
56728
57162
  options: [
56729
57163
  {
56730
- kind: "allow_always",
56731
- name: alwaysAllowLabel,
56732
- optionId: "allow_always"
57164
+ kind: "reject_once",
57165
+ name: "Deny",
57166
+ optionId: "reject"
56733
57167
  },
56734
57168
  {
56735
57169
  kind: "allow_once",
56736
- name: "Allow",
57170
+ name: "Allow Once",
56737
57171
  optionId: "allow"
56738
57172
  },
56739
57173
  {
56740
- kind: "reject_once",
56741
- name: "Reject",
56742
- optionId: "reject"
57174
+ kind: "allow_always",
57175
+ name: "Always Allow",
57176
+ optionId: "allow_always",
57177
+ _meta: {
57178
+ permission: permissionMetadataForAlwaysAllow(suggestions, toolName)
57179
+ }
56743
57180
  }
56744
57181
  ],
56745
57182
  sessionId,
@@ -56970,12 +57407,16 @@ ${message.api_refusal_explanation}` : "";
56970
57407
  availableModes: newAvailableModes
56971
57408
  };
56972
57409
  }
57410
+ if (session.fastModeDisabledReason === "model_not_allowed") {
57411
+ session.fastModeDisabledReason = void 0;
57412
+ }
56973
57413
  const effortOpt = session.configOptions.find((o) => o.id === EFFORT_CONFIG_ID);
56974
57414
  const currentEffort = typeof effortOpt?.currentValue === "string" ? effortOpt.currentValue : void 0;
56975
57415
  session.configOptions = buildConfigOptions(session.modes, session.models, session.modelInfos, currentEffort, session.agents, session.currentAgent, {
56976
57416
  supported: newModelInfo?.supportsFastMode ?? false,
56977
57417
  enabled: session.fastModeEnabled,
56978
- useBooleanOption: clientSupportsBooleanConfigOptions(this.clientCapabilities)
57418
+ useBooleanOption: clientSupportsBooleanConfigOptions(this.clientCapabilities),
57419
+ disabledReason: session.fastModeDisabledReason
56979
57420
  });
56980
57421
  const newEffortOpt = session.configOptions.find((o) => o.id === EFFORT_CONFIG_ID);
56981
57422
  const newEffort = typeof newEffortOpt?.currentValue === "string" ? newEffortOpt.currentValue : void 0;
@@ -57025,7 +57466,7 @@ ${message.api_refusal_explanation}` : "";
57025
57466
  }
57026
57467
  }
57027
57468
  refreshFastModeOption(session, enabled) {
57028
- const refreshed = createFastModeConfigOption(enabled, clientSupportsBooleanConfigOptions(this.clientCapabilities));
57469
+ const refreshed = createFastModeConfigOption(enabled, clientSupportsBooleanConfigOptions(this.clientCapabilities), session.fastModeDisabledReason);
57029
57470
  session.configOptions = session.configOptions.map((o) => o.id === FAST_MODE_CONFIG_ID ? refreshed : o);
57030
57471
  }
57031
57472
  async applyFastMode(session, enabled) {
@@ -57035,7 +57476,7 @@ ${message.api_refusal_explanation}` : "";
57035
57476
  session.fastModeEnabled = enabled;
57036
57477
  this.refreshFastModeOption(session, enabled);
57037
57478
  }
57038
- async syncFastModeState(sessionId, session, state) {
57479
+ async syncFastModeState(sessionId, session, state, reason) {
57039
57480
  if (state === void 0) {
57040
57481
  return;
57041
57482
  }
@@ -57046,11 +57487,26 @@ ${message.api_refusal_explanation}` : "";
57046
57487
  return;
57047
57488
  }
57048
57489
  const enabled = state === "on";
57049
- if (enabled === session.fastModeEnabled) {
57490
+ const nextReason = enabled ? void 0 : normalizeFastModeDisabledReason(reason);
57491
+ if (enabled === session.fastModeEnabled && nextReason === session.fastModeDisabledReason) {
57050
57492
  return;
57051
57493
  }
57494
+ const explain = session.fastModeEnabled && !enabled && nextReason !== void 0;
57052
57495
  session.fastModeEnabled = enabled;
57496
+ session.fastModeDisabledReason = nextReason;
57053
57497
  this.refreshFastModeOption(session, enabled);
57498
+ if (explain) {
57499
+ await this.client.sessionUpdate({
57500
+ sessionId,
57501
+ update: {
57502
+ sessionUpdate: "agent_message_chunk",
57503
+ content: {
57504
+ type: "text",
57505
+ text: `**Fast mode turned off:** ${FAST_MODE_UNAVAILABLE_EXPLANATIONS[nextReason]}.`
57506
+ }
57507
+ }
57508
+ });
57509
+ }
57054
57510
  await this.client.sessionUpdate({
57055
57511
  sessionId,
57056
57512
  update: {
@@ -57165,6 +57621,7 @@ ${message.api_refusal_explanation}` : "";
57165
57621
  const permissionMode = resolvePermissionMode(settingsManager.getSettings().permissions?.defaultMode, this.logger);
57166
57622
  const sessionMeta = params._meta;
57167
57623
  const userProvidedOptions = sessionMeta?.claudeCode?.options;
57624
+ const forwardSubagentText = supportsSubagentTranscript(this.clientCapabilities) || userProvidedOptions?.forwardSubagentText === true;
57168
57625
  const thinking = resolveThinkingConfig(process.env.MAX_THINKING_TOKENS, this.logger);
57169
57626
  const modelConfig = parseModelConfig(process.env.CLAUDE_MODEL_CONFIG);
57170
57627
  const elicitationSupport = {
@@ -57211,6 +57668,7 @@ ${message.api_refusal_explanation}` : "";
57211
57668
  env,
57212
57669
  cwd: params.cwd,
57213
57670
  includePartialMessages: true,
57671
+ forwardSubagentText,
57214
57672
  mcpServers: {
57215
57673
  ...userProvidedOptions?.mcpServers || {},
57216
57674
  ...mcpServers
@@ -57264,15 +57722,7 @@ ${message.api_refusal_explanation}` : "";
57264
57722
  hooks: [
57265
57723
  createTaskHook({
57266
57724
  taskState,
57267
- onChange: async () => {
57268
- await this.client.sessionUpdate({
57269
- sessionId,
57270
- update: {
57271
- sessionUpdate: "plan",
57272
- entries: taskStateToPlanEntries(taskState)
57273
- }
57274
- });
57275
- }
57725
+ onChange: () => this.publishTaskPlan(sessionId, taskState)
57276
57726
  })
57277
57727
  ]
57278
57728
  }
@@ -57283,15 +57733,7 @@ ${message.api_refusal_explanation}` : "";
57283
57733
  hooks: [
57284
57734
  createTaskHook({
57285
57735
  taskState,
57286
- onChange: async () => {
57287
- await this.client.sessionUpdate({
57288
- sessionId,
57289
- update: {
57290
- sessionUpdate: "plan",
57291
- entries: taskStateToPlanEntries(taskState)
57292
- }
57293
- });
57294
- }
57736
+ onChange: () => this.publishTaskPlan(sessionId, taskState)
57295
57737
  })
57296
57738
  ]
57297
57739
  }
@@ -57367,10 +57809,12 @@ ${message.api_refusal_explanation}` : "";
57367
57809
  const requestedAgent = userProvidedOptions?.agent;
57368
57810
  const currentAgent = requestedAgent && agents.some((a) => a.name === requestedAgent) ? requestedAgent : DEFAULT_AGENT_ID;
57369
57811
  const fastModeEnabled = initializationResult.fast_mode_state !== void 0 && fastModeStateEnabled(initializationResult.fast_mode_state);
57812
+ const fastModeDisabledReason = fastModeEnabled ? void 0 : normalizeFastModeDisabledReason(initializationResult.fast_mode_disabled_reason);
57370
57813
  const fastMode = {
57371
57814
  supported: currentModelInfo?.supportsFastMode ?? false,
57372
57815
  enabled: fastModeEnabled,
57373
- useBooleanOption: clientSupportsBooleanConfigOptions(this.clientCapabilities)
57816
+ useBooleanOption: clientSupportsBooleanConfigOptions(this.clientCapabilities),
57817
+ disabledReason: fastModeDisabledReason
57374
57818
  };
57375
57819
  const configOptions = buildConfigOptions(modes, models, modelInfos, settingsManager.getSettings().effortLevel, agents, currentAgent, fastMode);
57376
57820
  const initialEffort = configOptions.find((o) => o.id === EFFORT_CONFIG_ID);
@@ -57403,8 +57847,10 @@ ${message.api_refusal_explanation}` : "";
57403
57847
  agents,
57404
57848
  currentAgent,
57405
57849
  fastModeEnabled,
57850
+ fastModeDisabledReason,
57406
57851
  abortController,
57407
57852
  emitRawSDKMessages: sessionMeta?.claudeCode?.emitRawSDKMessages ?? false,
57853
+ forwardSubagentText,
57408
57854
  contextWindowSize: seededWindow.size,
57409
57855
  contextWindowAuthoritative: seededWindow.authoritative,
57410
57856
  providerCacheKey,
@@ -57567,14 +58013,26 @@ ${message.api_refusal_explanation}` : "";
57567
58013
  function fastModeStateEnabled(state) {
57568
58014
  return state !== "off";
57569
58015
  }
58016
+ const FAST_MODE_UNAVAILABLE_EXPLANATIONS = {
58017
+ free: "not available on the free plan",
58018
+ extra_usage_disabled: "requires extra usage to be enabled for this account",
58019
+ model_not_allowed: "not available for the selected model",
58020
+ not_first_party: "not available on this API provider",
58021
+ disabled_by_env: "disabled by environment configuration",
58022
+ network_error: "eligibility could not be verified (network error)"
58023
+ };
58024
+ function normalizeFastModeDisabledReason(reason) {
58025
+ return reason && FAST_MODE_UNAVAILABLE_EXPLANATIONS[reason] ? reason : void 0;
58026
+ }
57570
58027
  function clientSupportsBooleanConfigOptions(clientCapabilities) {
57571
58028
  return clientCapabilities?.session?.configOptions?.boolean != null;
57572
58029
  }
57573
- function createFastModeConfigOption(enabled, useBooleanOption) {
58030
+ function createFastModeConfigOption(enabled, useBooleanOption, disabledReason) {
58031
+ const explanation = enabled ? void 0 : disabledReason && FAST_MODE_UNAVAILABLE_EXPLANATIONS[disabledReason];
57574
58032
  const base = {
57575
58033
  id: FAST_MODE_CONFIG_ID,
57576
58034
  name: "Fast mode",
57577
- description: FAST_MODE_DESCRIPTION,
58035
+ description: explanation ? `${FAST_MODE_DESCRIPTION} \u2014 ${explanation}` : FAST_MODE_DESCRIPTION,
57578
58036
  category: "model_config"
57579
58037
  };
57580
58038
  if (useBooleanOption) {
@@ -57668,7 +58126,7 @@ ${message.api_refusal_explanation}` : "";
57668
58126
  });
57669
58127
  }
57670
58128
  if (fastMode?.supported) {
57671
- options.push(createFastModeConfigOption(fastMode.enabled, fastMode.useBooleanOption));
58129
+ options.push(createFastModeConfigOption(fastMode.enabled, fastMode.useBooleanOption, fastMode.disabledReason));
57672
58130
  }
57673
58131
  if (agents.length > 0) {
57674
58132
  options.push({
@@ -58069,13 +58527,23 @@ ${chunk.resource.text}
58069
58527
  function shouldEmitToolCall(toolName) {
58070
58528
  return toolName !== "TodoWrite" && !isTaskTool(toolName);
58071
58529
  }
58530
+ function claudeCodeMetaFromToolUse(toolUse) {
58531
+ const description = toolUse.name === "Bash" && toolUse.input !== null && typeof toolUse.input === "object" && "description" in toolUse.input && typeof toolUse.input.description === "string" ? toolUse.input.description : void 0;
58532
+ return {
58533
+ toolName: toolUse.name,
58534
+ ...description ? {
58535
+ title: description
58536
+ } : {},
58537
+ ...(toolUse.name === "Agent" || toolUse.name === "Task") && {
58538
+ subagent: true
58539
+ }
58540
+ };
58541
+ }
58072
58542
  function toolCallNotification(toolUse, rawInput, supportsTerminalOutput, cwd2, refine = false) {
58073
58543
  if (refine) {
58074
58544
  return {
58075
58545
  _meta: {
58076
- claudeCode: {
58077
- toolName: toolUse.name
58078
- }
58546
+ claudeCode: claudeCodeMetaFromToolUse(toolUse)
58079
58547
  },
58080
58548
  toolCallId: toolUse.id,
58081
58549
  sessionUpdate: "tool_call_update",
@@ -58085,9 +58553,7 @@ ${chunk.resource.text}
58085
58553
  }
58086
58554
  return {
58087
58555
  _meta: {
58088
- claudeCode: {
58089
- toolName: toolUse.name
58090
- },
58556
+ claudeCode: claudeCodeMetaFromToolUse(toolUse),
58091
58557
  ...toolUse.name === "Bash" && supportsTerminalOutput ? {
58092
58558
  terminal_info: {
58093
58559
  terminal_id: toolUse.id
@@ -58111,9 +58577,10 @@ ${chunk.resource.text}
58111
58577
  }, supportsTerminalOutput, cwd2);
58112
58578
  return {
58113
58579
  _meta: {
58114
- claudeCode: {
58115
- toolName: toolUse.name
58116
- }
58580
+ claudeCode: claudeCodeMetaFromToolUse({
58581
+ ...toolUse,
58582
+ input
58583
+ })
58117
58584
  },
58118
58585
  toolCallId: toolUse.id,
58119
58586
  sessionUpdate: "tool_call_update",
@@ -58299,7 +58766,7 @@ ${chunk.resource.text}
58299
58766
  }
58300
58767
  });
58301
58768
  }
58302
- logger.error(`[claude-agent-acp] Got a tool result for tool use that wasn't tracked: ${chunk.tool_use_id}`);
58769
+ logger.error(`[acp-extension-claude] Got a tool result for tool use that wasn't tracked: ${chunk.tool_use_id}`);
58303
58770
  break;
58304
58771
  }
58305
58772
  if (wasEmitted && !shouldEmitToolCall(toolUse.name)) {
@@ -58324,14 +58791,27 @@ ${chunk.resource.text}
58324
58791
  }
58325
58792
  if (isTaskTool(toolUse.name)) {
58326
58793
  const isError = "is_error" in chunk && chunk.is_error;
58794
+ let shouldEmitTaskPlan = false;
58327
58795
  if (!isError) {
58328
58796
  if (toolUse.name === "TaskCreate") {
58329
- applyTaskCreate(taskState, toolUse.input, parseTaskCreateOutput(chunk.content));
58797
+ applyTaskCreate(taskState, toolUse.input, parseTaskCreateOutput(toolUseResult) ?? parseTaskCreateOutput(chunk.content));
58798
+ shouldEmitTaskPlan = true;
58330
58799
  } else if (toolUse.name === "TaskUpdate") {
58331
- applyTaskUpdate(taskState, toolUse.input);
58800
+ const input = toolUse.input;
58801
+ const output2 = parseTaskUpdateOutput(toolUseResult, input?.taskId) ?? parseTaskUpdateOutput(chunk.content, input?.taskId);
58802
+ if (!output2 || output2.success && output2.taskId === input?.taskId) {
58803
+ applyTaskUpdate(taskState, input);
58804
+ shouldEmitTaskPlan = true;
58805
+ }
58806
+ } else if (toolUse.name === "TaskList") {
58807
+ const output2 = parseTaskListOutput(toolUseResult) ?? parseTaskListOutput(chunk.content);
58808
+ if (output2) {
58809
+ applyTaskList(taskState, output2);
58810
+ shouldEmitTaskPlan = true;
58811
+ }
58332
58812
  }
58333
58813
  }
58334
- if (!isError && (toolUse.name === "TaskCreate" || toolUse.name === "TaskUpdate")) {
58814
+ if (shouldEmitTaskPlan) {
58335
58815
  update = {
58336
58816
  sessionUpdate: "plan",
58337
58817
  entries: taskStateToPlanEntries(taskState)
@@ -58535,7 +59015,9 @@ ${chunk.resource.text}
58535
59015
  name: "claude-code-acp"
58536
59016
  }).onRequest(methods.agent.initialize, (ctx) => agent2.initialize(ctx.params)).onRequest(methods.agent.session.new, (ctx) => agent2.newSession(ctx.params)).onRequest(methods.agent.session.load, (ctx) => agent2.loadSession(ctx.params)).onRequest(methods.agent.session.fork, (ctx) => agent2.unstable_forkSession(ctx.params)).onRequest(methods.agent.session.list, (ctx) => agent2.listSessions(ctx.params)).onRequest(methods.agent.session.delete, (ctx) => agent2.deleteSession(ctx.params)).onRequest(methods.agent.session.resume, (ctx) => agent2.resumeSession(ctx.params)).onRequest(methods.agent.session.close, (ctx) => agent2.closeSession(ctx.params)).onRequest(methods.agent.session.setMode, (ctx) => agent2.setSessionMode(ctx.params)).onRequest(methods.agent.session.setConfigOption, (ctx) => agent2.setSessionConfigOption(ctx.params)).onRequest(methods.agent.authenticate, (ctx) => agent2.authenticate(ctx.params)).onRequest(methods.agent.providers.list, (ctx) => agent2.unstable_listProviders(ctx.params)).onRequest(methods.agent.providers.set, (ctx) => agent2.unstable_setProvider(ctx.params)).onRequest(methods.agent.providers.disable, (ctx) => agent2.unstable_disableProvider(ctx.params)).onRequest(methods.agent.logout, (ctx) => agent2.logout(ctx.params)).onRequest(methods.agent.session.prompt, (ctx) => runPromptWithCancellation(agent2, ctx.params, ctx.signal)).onNotification(methods.agent.session.cancel, (ctx) => agent2.cancel(ctx.params)).onRequest(STEER_METHOD, {
58537
59017
  parse: parseSteerRequest
58538
- }, (ctx) => agent2.steer(ctx.params)).connect(stream);
59018
+ }, (ctx) => agent2.steer(ctx.params)).onRequest(GOAL_CONTROL_METHOD, {
59019
+ parse: parseGoalRequest
59020
+ }, (ctx) => agent2.goal(ctx.params)).connect(stream);
58539
59021
  agent2 = new ClaudeAcpAgent(new ClientConnection(connection2.client));
58540
59022
  return {
58541
59023
  connection: connection2,