@sideboard-ai/core 0.1.307 → 0.1.309

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.
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  extractJsonErrorMessage,
3
3
  formatUnknownDetail
4
- } from "./chunk-HO5R3ZRH.js";
4
+ } from "./chunk-5XNT6BCG.js";
5
5
  import {
6
6
  npmGlobalNodeModules,
7
7
  run
@@ -2,7 +2,7 @@ import {
2
2
  compactSummaryPart,
3
3
  isInternalAgentStatusText,
4
4
  lastAssistantMessageText
5
- } from "./chunk-F36QRDM4.js";
5
+ } from "./chunk-7Q327QF2.js";
6
6
  import {
7
7
  isCloudCoordinatorThread,
8
8
  isGlobalThread,
@@ -29,7 +29,7 @@ import {
29
29
  } from "./chunk-2P4XKWV2.js";
30
30
  import {
31
31
  clipToolResultForStore
32
- } from "./chunk-HO5R3ZRH.js";
32
+ } from "./chunk-5XNT6BCG.js";
33
33
  import {
34
34
  ATTACHMENTS_DIR,
35
35
  DETACHED_JOBS_DIR,
@@ -1288,12 +1288,23 @@ function isAskUserToolName(name) {
1288
1288
  const base = name.replace(/^mcp__sideboard__/i, "");
1289
1289
  return ASK_USER_TOOL_RE.test(name) || /^ask_user$/i.test(base);
1290
1290
  }
1291
+ function questionsFromToolPart(part) {
1292
+ const fromInput = parsePlanQuestionsInput(part.input);
1293
+ if (fromInput.length) return fromInput;
1294
+ const raw = part.result?.trim();
1295
+ if (!raw || !raw.startsWith("{")) return [];
1296
+ try {
1297
+ return parsePlanQuestionsInput(JSON.parse(raw));
1298
+ } catch {
1299
+ return [];
1300
+ }
1301
+ }
1291
1302
  function extractPendingPlanQuestions(parts) {
1292
1303
  if (!parts?.length) return null;
1293
1304
  for (let i = parts.length - 1; i >= 0; i--) {
1294
1305
  const p = parts[i];
1295
1306
  if (p.type !== "tool" || !isAskUserToolName(p.name)) continue;
1296
- const questions = parsePlanQuestionsInput(p.input);
1307
+ const questions = questionsFromToolPart(p);
1297
1308
  if (!questions.length) continue;
1298
1309
  return {
1299
1310
  id: p.id || `ask-${i}`,
@@ -1304,13 +1315,47 @@ function extractPendingPlanQuestions(parts) {
1304
1315
  }
1305
1316
  return null;
1306
1317
  }
1318
+ function pendingFromAskBlock(block, dismissedQuestionSignature) {
1319
+ if (!block || block.source !== "ask_user" || !block.questions?.length) return null;
1320
+ const dismissed = dismissedQuestionSignature?.trim();
1321
+ if (dismissed && (!block.questionSignature || block.questionSignature === dismissed)) {
1322
+ return null;
1323
+ }
1324
+ const signature = block.questionSignature?.trim() || planQuestionsSignature(block.questions);
1325
+ return {
1326
+ id: `ask-block:${signature}`,
1327
+ signature,
1328
+ questions: block.questions,
1329
+ source: "ask_user"
1330
+ };
1331
+ }
1332
+ function askBlockStillWaiting(block, messages) {
1333
+ const askedAt = block?.at;
1334
+ if (!askedAt) return false;
1335
+ for (let i = messages.length - 1; i >= 0; i--) {
1336
+ const message = messages[i];
1337
+ if (message.role !== "user" || message.origin === "continue") continue;
1338
+ if (!message.ts) return true;
1339
+ return askedAt > message.ts;
1340
+ }
1341
+ return true;
1342
+ }
1307
1343
  function latestPendingPlanQuestions(input) {
1308
1344
  if (input.userReplied) return null;
1309
1345
  const fromLive = extractPendingPlanQuestions(input.liveParts);
1310
1346
  if (fromLive) return fromLive;
1311
1347
  const last = input.messages[input.messages.length - 1];
1312
- if (last?.role === "user") return null;
1313
- if (last?.role === "agent") return extractPendingPlanQuestions(last.parts);
1348
+ if (last?.role === "agent") {
1349
+ const fromParts = extractPendingPlanQuestions(last.parts);
1350
+ if (fromParts) return fromParts;
1351
+ }
1352
+ const fromBlock = pendingFromAskBlock(
1353
+ input.agentBlock,
1354
+ input.dismissedQuestionSignature
1355
+ );
1356
+ if (fromBlock && askBlockStillWaiting(input.agentBlock, input.messages)) {
1357
+ return fromBlock;
1358
+ }
1314
1359
  return null;
1315
1360
  }
1316
1361
  var PLAN_QUESTION_ANSWERS_PREFIX = "Answers to your questions:";
@@ -1778,7 +1823,7 @@ var PORT_RANGE_SIZE = 10;
1778
1823
  var RECLAIM_RETRY_DELAY_MS = 40;
1779
1824
  var RECLAIM_TRIES = 8;
1780
1825
  async function killReclaimable(ports, worktreePath, signal) {
1781
- const { killListenersOnPorts: killListenersOnPorts2, killStaleWorktreeListeners: killStaleWorktreeListeners2 } = await import("./conductor-YBXURAUL.js");
1826
+ const { killListenersOnPorts: killListenersOnPorts2, killStaleWorktreeListeners: killStaleWorktreeListeners2 } = await import("./conductor-OFXA5BST.js");
1782
1827
  if (worktreePath) killStaleWorktreeListeners2(ports, worktreePath, signal);
1783
1828
  else killListenersOnPorts2(ports);
1784
1829
  }
@@ -21,7 +21,7 @@ import {
21
21
  looksLikeSkillBody,
22
22
  skillCommandFromBody,
23
23
  withEventParentId
24
- } from "./chunk-5XQ43YZU.js";
24
+ } from "./chunk-I5TESHDN.js";
25
25
  import {
26
26
  isOrchestratorThread
27
27
  } from "./chunk-X3FSWWW2.js";
@@ -34,8 +34,8 @@ import {
34
34
  tryReservePort,
35
35
  tryReservePorts,
36
36
  worktreeRunPortsPath
37
- } from "./chunk-5SFA27CF.js";
38
- import "./chunk-5XQ43YZU.js";
37
+ } from "./chunk-AILQRQ26.js";
38
+ import "./chunk-I5TESHDN.js";
39
39
  import "./chunk-X3FSWWW2.js";
40
40
  import "./chunk-DLGGLV2M.js";
41
41
  import "./chunk-N2WW62LF.js";
@@ -32,14 +32,14 @@ import {
32
32
  tryReservePort,
33
33
  tryReservePorts,
34
34
  worktreeRunPortsPath
35
- } from "./chunk-OVNIP265.js";
36
- import "./chunk-F36QRDM4.js";
35
+ } from "./chunk-VBVSJUM2.js";
36
+ import "./chunk-7Q327QF2.js";
37
37
  import "./chunk-5QX2NYXL.js";
38
38
  import "./chunk-BIPXOHZI.js";
39
39
  import "./chunk-HG25AYBV.js";
40
40
  import "./chunk-2P4XKWV2.js";
41
41
  import "./chunk-F2PVRF3B.js";
42
- import "./chunk-HO5R3ZRH.js";
42
+ import "./chunk-5XNT6BCG.js";
43
43
  import "./chunk-6K64FJDD.js";
44
44
  import "./chunk-LG6RJBIY.js";
45
45
  import "./chunk-QVN2WOKJ.js";
package/dist/index.cjs CHANGED
@@ -5362,6 +5362,12 @@ var init_thread_store = __esm({
5362
5362
  function looksLikeCursorStreamCutOff(text7) {
5363
5363
  return CURSOR_STREAM_CUTOFF.test(text7.trim());
5364
5364
  }
5365
+ function looksLikeCursorStreamIdleAfterTools(text7) {
5366
+ return CURSOR_STREAM_IDLE_AFTER_TOOLS.test(text7.trim());
5367
+ }
5368
+ function looksLikeCursorStreamFailure(text7) {
5369
+ return looksLikeCursorStreamCutOff(text7) || looksLikeCursorStreamIdleAfterTools(text7);
5370
+ }
5365
5371
  function cursorStreamCutOffContinueLimit(detail) {
5366
5372
  if (looksLikeCursorStreamCutOff(detail) || /connection stalled/i.test(detail)) {
5367
5373
  return CURSOR_STREAM_CUTOFF_CONTINUE_LIMIT;
@@ -5373,11 +5379,12 @@ function nextCrashContinueCount(detail, used) {
5373
5379
  if (used >= limit) return null;
5374
5380
  return used + 1;
5375
5381
  }
5376
- var CURSOR_STREAM_CUTOFF, CURSOR_STREAM_CUTOFF_CONTINUE_LIMIT;
5382
+ var CURSOR_STREAM_CUTOFF, CURSOR_STREAM_IDLE_AFTER_TOOLS, CURSOR_STREAM_CUTOFF_CONTINUE_LIMIT;
5377
5383
  var init_cursor_stream_cutoff = __esm({
5378
5384
  "src/agents/cursor-stream-cutoff.ts"() {
5379
5385
  "use strict";
5380
5386
  CURSOR_STREAM_CUTOFF = /nghttp2|premature close|\[unavailable\]\s+error\b|http\/2 stream closed|\bcancel \(0x8\)|error code cancel\b/i;
5387
+ CURSOR_STREAM_IDLE_AFTER_TOOLS = /stopped responding after a tool call/i;
5381
5388
  CURSOR_STREAM_CUTOFF_CONTINUE_LIMIT = 3;
5382
5389
  }
5383
5390
  });
@@ -5581,7 +5588,7 @@ function looksLikeRetryableRunnerCrash(text7) {
5581
5588
  if (looksLikeInvalidAgentSession(text7)) return false;
5582
5589
  if (looksLikeV8Oom(text7)) return false;
5583
5590
  if (looksLikeHugeToolResultDump(text7)) return true;
5584
- if (looksLikeCursorStreamCutOff(text7)) return true;
5591
+ if (looksLikeCursorStreamFailure(text7)) return true;
5585
5592
  if (looksLikeBrightsyEmptyCompletion(text7)) return true;
5586
5593
  const lower = text7.trim().toLowerCase();
5587
5594
  if (/cannot find (?:package|module)|err_module_not_found/.test(lower)) return false;
@@ -5658,7 +5665,7 @@ function humanizeAgentFailDetail(detail) {
5658
5665
  if (/corrupt local agent checkpoint|missing root blob|truncated crash dump/.test(lower)) {
5659
5666
  return `${raw} \u2014 retry the turn (Sideboard will start a fresh Cursor session).`;
5660
5667
  }
5661
- if (/connection stalled/.test(lower) || looksLikeCursorStreamCutOff(raw)) {
5668
+ if (/connection stalled/.test(lower) || looksLikeCursorStreamFailure(raw)) {
5662
5669
  return /retry the turn/i.test(raw) ? raw : `${raw} \u2014 retry the turn (Sideboard will start a fresh Cursor session).`;
5663
5670
  }
5664
5671
  if (looksLikeBrightsyEmptyCompletion(raw)) {
@@ -6746,6 +6753,23 @@ function worktreeAgentBlock(group) {
6746
6753
  }
6747
6754
  return best;
6748
6755
  }
6756
+ function sidebarRowAgentBlock(group, opts) {
6757
+ if (opts.active) {
6758
+ const open = group.find((thread) => thread.id === opts.selectedId);
6759
+ if (open) return visibleAgentBlock(open);
6760
+ }
6761
+ return worktreeAgentBlock(group);
6762
+ }
6763
+ function sidebarParentSelectId(group, primaryId, opts) {
6764
+ if (opts.active) return primaryId;
6765
+ return sidebarQuestionThreadId(group, primaryId);
6766
+ }
6767
+ function sidebarQuestionThreadId(group, primaryId) {
6768
+ const block = worktreeAgentBlock(group);
6769
+ if (!block) return primaryId;
6770
+ const owner = group.find((thread) => visibleAgentBlock(thread) === block);
6771
+ return owner?.id ?? primaryId;
6772
+ }
6749
6773
  function threadCardBlockFields(group) {
6750
6774
  const block = worktreeAgentBlock(group);
6751
6775
  return block ? { blockedReason: block.reason, blockedSource: block.source } : null;
@@ -8339,12 +8363,23 @@ function isAskUserToolName(name) {
8339
8363
  const base = name.replace(/^mcp__sideboard__/i, "");
8340
8364
  return ASK_USER_TOOL_RE.test(name) || /^ask_user$/i.test(base);
8341
8365
  }
8366
+ function questionsFromToolPart(part) {
8367
+ const fromInput = parsePlanQuestionsInput(part.input);
8368
+ if (fromInput.length) return fromInput;
8369
+ const raw = part.result?.trim();
8370
+ if (!raw || !raw.startsWith("{")) return [];
8371
+ try {
8372
+ return parsePlanQuestionsInput(JSON.parse(raw));
8373
+ } catch {
8374
+ return [];
8375
+ }
8376
+ }
8342
8377
  function extractPendingPlanQuestions(parts) {
8343
8378
  if (!parts?.length) return null;
8344
8379
  for (let i = parts.length - 1; i >= 0; i--) {
8345
8380
  const p = parts[i];
8346
8381
  if (p.type !== "tool" || !isAskUserToolName(p.name)) continue;
8347
- const questions2 = parsePlanQuestionsInput(p.input);
8382
+ const questions2 = questionsFromToolPart(p);
8348
8383
  if (!questions2.length) continue;
8349
8384
  return {
8350
8385
  id: p.id || `ask-${i}`,
@@ -8355,13 +8390,47 @@ function extractPendingPlanQuestions(parts) {
8355
8390
  }
8356
8391
  return null;
8357
8392
  }
8393
+ function pendingFromAskBlock(block, dismissedQuestionSignature) {
8394
+ if (!block || block.source !== "ask_user" || !block.questions?.length) return null;
8395
+ const dismissed = dismissedQuestionSignature?.trim();
8396
+ if (dismissed && (!block.questionSignature || block.questionSignature === dismissed)) {
8397
+ return null;
8398
+ }
8399
+ const signature = block.questionSignature?.trim() || planQuestionsSignature(block.questions);
8400
+ return {
8401
+ id: `ask-block:${signature}`,
8402
+ signature,
8403
+ questions: block.questions,
8404
+ source: "ask_user"
8405
+ };
8406
+ }
8407
+ function askBlockStillWaiting(block, messages) {
8408
+ const askedAt = block?.at;
8409
+ if (!askedAt) return false;
8410
+ for (let i = messages.length - 1; i >= 0; i--) {
8411
+ const message = messages[i];
8412
+ if (message.role !== "user" || message.origin === "continue") continue;
8413
+ if (!message.ts) return true;
8414
+ return askedAt > message.ts;
8415
+ }
8416
+ return true;
8417
+ }
8358
8418
  function latestPendingPlanQuestions(input) {
8359
8419
  if (input.userReplied) return null;
8360
8420
  const fromLive = extractPendingPlanQuestions(input.liveParts);
8361
8421
  if (fromLive) return fromLive;
8362
8422
  const last = input.messages[input.messages.length - 1];
8363
- if (last?.role === "user") return null;
8364
- if (last?.role === "agent") return extractPendingPlanQuestions(last.parts);
8423
+ if (last?.role === "agent") {
8424
+ const fromParts = extractPendingPlanQuestions(last.parts);
8425
+ if (fromParts) return fromParts;
8426
+ }
8427
+ const fromBlock = pendingFromAskBlock(
8428
+ input.agentBlock,
8429
+ input.dismissedQuestionSignature
8430
+ );
8431
+ if (fromBlock && askBlockStillWaiting(input.agentBlock, input.messages)) {
8432
+ return fromBlock;
8433
+ }
8365
8434
  return null;
8366
8435
  }
8367
8436
  function isPlanQuestionAnswersMessage(text7) {
@@ -22161,7 +22230,7 @@ function decisionBlockFromParts(parts, planMode, at = (/* @__PURE__ */ new Date(
22161
22230
  const reason = pending ? formatAskUserNotifyMessage(pending.questions) : "Waiting for an answer in that chat.";
22162
22231
  return {
22163
22232
  ...makeAgentBlock("ask_user", reason, at),
22164
- ...pending ? { questionSignature: pending.signature } : {}
22233
+ ...pending ? { questionSignature: pending.signature, questions: pending.questions } : {}
22165
22234
  };
22166
22235
  }
22167
22236
  if (!planMode || last?.type !== "tool") return null;
@@ -22176,14 +22245,24 @@ function decisionBlockFromParts(parts, planMode, at = (/* @__PURE__ */ new Date(
22176
22245
  at
22177
22246
  );
22178
22247
  }
22248
+ function withStampedQuestions(decision, existing) {
22249
+ if (decision.source !== "ask_user" || decision.questions?.length) return decision;
22250
+ if (existing?.source !== "ask_user" || !existing.questions?.length) return decision;
22251
+ return {
22252
+ ...decision,
22253
+ questions: existing.questions,
22254
+ questionSignature: decision.questionSignature ?? existing.questionSignature
22255
+ };
22256
+ }
22179
22257
  function agentBlockAfterTurn(input) {
22180
22258
  if (input.failed) return null;
22181
22259
  const decision = decisionBlockFromParts(input.parts, input.planMode);
22182
22260
  if (decision) {
22183
- if (isDismissedAskUserBlock(decision, input.dismissedQuestionSignature)) {
22261
+ const next = withStampedQuestions(decision, input.existing);
22262
+ if (isDismissedAskUserBlock(next, input.dismissedQuestionSignature)) {
22184
22263
  return input.existing?.source === "reported" ? input.existing : null;
22185
22264
  }
22186
- return decision;
22265
+ return next;
22187
22266
  }
22188
22267
  if (input.existing && input.existing.source !== "reported" && lastTopLevelTool(input.parts)) {
22189
22268
  return null;
@@ -22226,7 +22305,7 @@ function settleAgentBlock(threadId, parts, failed) {
22226
22305
  });
22227
22306
  const prev = thread.agentBlock ?? null;
22228
22307
  if (prev === next) return;
22229
- if (prev && next && prev.source === next.source && prev.reason === next.reason && prev.at === next.at && prev.questionSignature === next.questionSignature) {
22308
+ if (prev && next && prev.source === next.source && prev.reason === next.reason && prev.at === next.at && prev.questionSignature === next.questionSignature && planQuestionsSignature(prev.questions ?? []) === planQuestionsSignature(next.questions ?? [])) {
22230
22309
  return;
22231
22310
  }
22232
22311
  updateThread(threadId, { agentBlock: next });
@@ -22249,7 +22328,11 @@ function stampAskUserBlock(resolveCaller, questions2) {
22249
22328
  try {
22250
22329
  writeAgentBlock(
22251
22330
  resolveCaller().id,
22252
- parsed.length ? { ...block, questionSignature: planQuestionsSignature(parsed) } : block
22331
+ parsed.length ? {
22332
+ ...block,
22333
+ questionSignature: planQuestionsSignature(parsed),
22334
+ questions: parsed
22335
+ } : block
22253
22336
  );
22254
22337
  } catch {
22255
22338
  }
@@ -27623,7 +27706,7 @@ function formatWorktreeReminder() {
27623
27706
  return "Sideboard workspace: stay in this cwd for all file and git work. Push and open PRs against origin, never upstream. Do not edit the main repo checkout. If a goal is given (Greptile 5/5, CI green), watch-fix-push until it lands \u2014 do not watch after every push. Schedules: create_schedule (at / every / cron; chatId=self for this chat). set_workspace_tags updates labels on this workspace (omit ref).";
27624
27707
  }
27625
27708
  function formatClaudeSubagentReminder() {
27626
- return 'Claude subagents: if Task/Agent workers will edit files, write a short plan in this chat and continue in the same turn. Do not ask the user whether to isolate, and do not set worktree.bgIsolation to none. One writer may edit this workspace. Every other writer is an Agent with isolation "worktree" and a disjoint file list (read-only explore agents may overlap). While those agents run, leave their files alone. Merge each returned branch into this workspace, then remove the temporary worktree. You stay in this cwd. If Claude says another write-capable agent is in this directory, or that writes to the shared checkout are blocked, re-spawn that agent with isolation "worktree" or make the edit yourself.';
27709
+ return 'Claude subagents: if Task/Agent workers will edit files, write a short plan in this chat and continue in the same turn. Do not ask the user whether to isolate, and do not set worktree.bgIsolation to none. One writer may edit this workspace. Every other writer is an Agent with isolation "worktree" and a disjoint file list (read-only explore agents may overlap). While those agents run, leave their files alone. Merge each returned branch into this workspace, then remove the temporary worktree. You stay in this cwd. If Claude says another write-capable agent is in this directory, or that writes to the shared checkout are blocked, re-spawn that agent with isolation "worktree" or make the edit yourself. That note is another worker in this chat, or a worker Claude still has marked running. Do not mention it to the user.';
27627
27710
  }
27628
27711
  function claudeSubagentTurnReminder(thread) {
27629
27712
  if (thread.agent !== "claude" || thread.planMode || isOrchestratorThread(thread)) {
@@ -32751,6 +32834,9 @@ __export(index_exports, {
32751
32834
  shouldRunWorktreeCleanup: () => shouldRunWorktreeCleanup,
32752
32835
  shouldStampSetupLastError: () => shouldStampSetupLastError,
32753
32836
  showCostEnabled: () => showCostEnabled,
32837
+ sidebarParentSelectId: () => sidebarParentSelectId,
32838
+ sidebarQuestionThreadId: () => sidebarQuestionThreadId,
32839
+ sidebarRowAgentBlock: () => sidebarRowAgentBlock,
32754
32840
  sideboardHomeDir: () => sideboardHomeDir,
32755
32841
  sideboardMcpProfile: () => sideboardMcpProfile,
32756
32842
  sideboardReposDir: () => sideboardReposDir,
@@ -34328,10 +34414,9 @@ function parsePhoneMcpUi(value, op, chatId) {
34328
34414
  }
34329
34415
  function phoneMcpToolPayload(parts, tool, callId) {
34330
34416
  if (!parts) return null;
34331
- const matches = parts.filter(
34332
- (part2) => part2.type === "tool" && part2.name === tool && !part2.parentId
34417
+ const part = parts.find(
34418
+ (row2) => row2.type === "tool" && row2.id === callId && row2.name === tool && !row2.parentId
34333
34419
  );
34334
- const part = matches.find((row2) => row2.id === callId) ?? matches[matches.length - 1];
34335
34420
  if (!part) return null;
34336
34421
  return {
34337
34422
  input: part.input ?? {},
@@ -34339,6 +34424,15 @@ function phoneMcpToolPayload(parts, tool, callId) {
34339
34424
  isError: part.status === "error"
34340
34425
  };
34341
34426
  }
34427
+ function phoneMcpToolPayloadFromMessages(messages, tool, callId) {
34428
+ for (let i = messages.length - 1; i >= 0; i--) {
34429
+ const message = messages[i];
34430
+ if (message?.role !== "agent") continue;
34431
+ const payload = phoneMcpToolPayload(message.parts, tool, callId);
34432
+ if (payload) return payload;
34433
+ }
34434
+ return null;
34435
+ }
34342
34436
 
34343
34437
  // src/remote/phone-stream.ts
34344
34438
  init_message_parts();
@@ -34398,8 +34492,8 @@ function listPhoneMessages(thread) {
34398
34492
  const names = (message.attachments ?? []).map((item) => item.name.trim()).filter(Boolean);
34399
34493
  const visible = [phoneVisibleText(message.role, message.text), names.length ? names.join(", ") : ""].filter(Boolean).join("\n");
34400
34494
  const text7 = message.role === "agent" ? phoneArtifactText(visible, message.parts, MESSAGE_LIMIT) : clip(visible, MESSAGE_LIMIT);
34401
- if (!text7) continue;
34402
34495
  const apps = message.role === "agent" ? phoneMcpApps(thread.agent, message.parts) : [];
34496
+ if (!text7 && apps.length === 0) continue;
34403
34497
  out.push({ role: message.role, text: text7, ...apps.length ? { apps } : {} });
34404
34498
  }
34405
34499
  const live = withLiveTail(thread, out);
@@ -35072,10 +35166,12 @@ function emitChatTurn(opts, chatId, threadId) {
35072
35166
  return;
35073
35167
  }
35074
35168
  const result = getOrchestrator().getTurnResult(thread.id);
35075
- const pending = extractPendingPlanQuestions(
35076
- [...thread.messages].reverse().find((m) => m.role === "agent")?.parts
35077
- );
35078
- if (result.taskState === "input-required" && pending) {
35169
+ const pending = latestPendingPlanQuestions({
35170
+ messages: thread.messages,
35171
+ agentBlock: thread.agentBlock,
35172
+ dismissedQuestionSignature: thread.dismissedQuestionSignature
35173
+ });
35174
+ if (pending && result.taskState !== "failed" && result.taskState !== "canceled" && (result.taskState === "input-required" || thread.agentBlock?.source === "ask_user")) {
35079
35175
  emitControl(opts, {
35080
35176
  op: "ask",
35081
35177
  chatId,
@@ -35159,8 +35255,7 @@ function dispatchPhoneMcpUi(cmd, opts) {
35159
35255
  );
35160
35256
  return true;
35161
35257
  }
35162
- const agentMessage = [...thread.messages].reverse().find((message) => message.role === "agent");
35163
- const payload = phoneMcpToolPayload(agentMessage?.parts, cmd.tool, cmd.callId);
35258
+ const payload = phoneMcpToolPayloadFromMessages(thread.messages, cmd.tool, cmd.callId);
35164
35259
  void getMcpUiHost().viewForClaudeTool(cmd.tool, projectDirs).then((view) => {
35165
35260
  if (!view || view.html.length > PHONE_HTML_CAP) {
35166
35261
  emitControl(opts, { op: "mcp-ui", chatId, reqId, view: null });
@@ -35442,7 +35537,11 @@ init_ask_user();
35442
35537
  function republishPendingAsk(opts, chatId) {
35443
35538
  const thread = readPhoneThread(chatId);
35444
35539
  if (!thread) return;
35445
- const pending = latestPendingPlanQuestions({ messages: thread.messages });
35540
+ const pending = latestPendingPlanQuestions({
35541
+ messages: thread.messages,
35542
+ agentBlock: thread.agentBlock,
35543
+ dismissedQuestionSignature: thread.dismissedQuestionSignature
35544
+ });
35446
35545
  if (!pending) return;
35447
35546
  emitControl(opts, {
35448
35547
  op: "ask",
@@ -37701,10 +37800,12 @@ function runCoordinatorPrompt(opts, body, generation) {
37701
37800
  thread = readThread(thread.id) ?? thread;
37702
37801
  if (thread.status === "stopped") return;
37703
37802
  const result = orch.getTurnResult(thread.id);
37704
- const pending = extractPendingPlanQuestions(
37705
- [...thread.messages].reverse().find((m) => m.role === "agent")?.parts
37706
- );
37707
- if (result.taskState === "input-required" && pending) {
37803
+ const pending = latestPendingPlanQuestions({
37804
+ messages: thread.messages,
37805
+ agentBlock: thread.agentBlock,
37806
+ dismissedQuestionSignature: thread.dismissedQuestionSignature
37807
+ });
37808
+ if (pending && result.taskState !== "failed" && result.taskState !== "canceled" && (result.taskState === "input-required" || thread.agentBlock?.source === "ask_user")) {
37708
37809
  opts.onOutbound({
37709
37810
  type: "ask_user",
37710
37811
  text: result.text.trim(),
@@ -47600,6 +47701,9 @@ async function pollSlackOutboundWatches(opts) {
47600
47701
  shouldRunWorktreeCleanup,
47601
47702
  shouldStampSetupLastError,
47602
47703
  showCostEnabled,
47704
+ sidebarParentSelectId,
47705
+ sidebarQuestionThreadId,
47706
+ sidebarRowAgentBlock,
47603
47707
  sideboardHomeDir,
47604
47708
  sideboardMcpProfile,
47605
47709
  sideboardReposDir,