@sideboard-ai/core 0.1.310 → 0.1.311

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/index.cjs CHANGED
@@ -6720,6 +6720,191 @@ var init_message_parts = __esm({
6720
6720
  }
6721
6721
  });
6722
6722
 
6723
+ // src/plan/ask-user.ts
6724
+ function planQuestionsSignature(questions2) {
6725
+ return questions2.map((q) => {
6726
+ const opts = q.options.map((o) => o.label).join("");
6727
+ return `${q.question}${opts}`;
6728
+ }).join("");
6729
+ }
6730
+ function asRecord2(v) {
6731
+ return v != null && typeof v === "object" && !Array.isArray(v) ? v : null;
6732
+ }
6733
+ function parseOptions(raw) {
6734
+ if (!Array.isArray(raw)) return [];
6735
+ const out = [];
6736
+ for (const item of raw) {
6737
+ if (typeof item === "string" && item.trim()) {
6738
+ out.push({ label: item.trim() });
6739
+ continue;
6740
+ }
6741
+ const o = asRecord2(item);
6742
+ if (!o) continue;
6743
+ const label = typeof o.label === "string" ? o.label.trim() : typeof o.text === "string" ? o.text.trim() : typeof o.title === "string" ? o.title.trim() : "";
6744
+ if (!label) continue;
6745
+ const description = typeof o.description === "string" && o.description.trim() ? o.description.trim() : void 0;
6746
+ out.push({ label, description });
6747
+ }
6748
+ return out;
6749
+ }
6750
+ function parseOneQuestion(raw) {
6751
+ const o = asRecord2(raw);
6752
+ if (!o) return null;
6753
+ const question = typeof o.question === "string" ? o.question.trim() : typeof o.text === "string" ? o.text.trim() : typeof o.prompt === "string" ? o.prompt.trim() : "";
6754
+ if (!question) return null;
6755
+ const options = parseOptions(o.options);
6756
+ if (options.length < 1) return null;
6757
+ const header = typeof o.header === "string" && o.header.trim() ? o.header.trim() : void 0;
6758
+ const multiSelect = Boolean(o.multiSelect ?? o.multi_select);
6759
+ return { question, header, multiSelect, options };
6760
+ }
6761
+ function parsePlanQuestionsInput(input) {
6762
+ const root = asRecord2(input);
6763
+ if (!root) return [];
6764
+ const list = Array.isArray(root.questions) ? root.questions : Array.isArray(root.question) ? root.question : root.question || root.prompt ? [root] : [];
6765
+ const out = [];
6766
+ for (const item of list) {
6767
+ const q = parseOneQuestion(item);
6768
+ if (q) out.push(q);
6769
+ }
6770
+ return out;
6771
+ }
6772
+ function isAskUserToolName(name) {
6773
+ if (!name) return false;
6774
+ const base = name.replace(/^mcp__sideboard__/i, "");
6775
+ return ASK_USER_TOOL_RE.test(name) || /^ask_user$/i.test(base);
6776
+ }
6777
+ function lastTopLevelToolIsAskUser(parts) {
6778
+ if (!parts?.length) return false;
6779
+ for (let i = parts.length - 1; i >= 0; i--) {
6780
+ const part = parts[i];
6781
+ if (part.type === "tool" && !part.parentId) {
6782
+ return isAskUserToolName(part.name);
6783
+ }
6784
+ }
6785
+ return false;
6786
+ }
6787
+ function hasTopLevelTool(parts) {
6788
+ return Boolean(parts?.some((part) => part.type === "tool" && !part.parentId));
6789
+ }
6790
+ function questionsFromToolPart(part) {
6791
+ const fromInput = parsePlanQuestionsInput(part.input);
6792
+ if (fromInput.length) return fromInput;
6793
+ const raw = part.result?.trim();
6794
+ if (!raw || !raw.startsWith("{")) return [];
6795
+ try {
6796
+ return parsePlanQuestionsInput(JSON.parse(raw));
6797
+ } catch {
6798
+ return [];
6799
+ }
6800
+ }
6801
+ function extractPendingPlanQuestions(parts) {
6802
+ if (!parts?.length) return null;
6803
+ for (let i = parts.length - 1; i >= 0; i--) {
6804
+ const p = parts[i];
6805
+ if (p.type !== "tool" || !isAskUserToolName(p.name)) continue;
6806
+ const questions2 = questionsFromToolPart(p);
6807
+ if (!questions2.length) continue;
6808
+ return {
6809
+ id: p.id || `ask-${i}`,
6810
+ signature: planQuestionsSignature(questions2),
6811
+ questions: questions2,
6812
+ source: p.name || "ask_user"
6813
+ };
6814
+ }
6815
+ return null;
6816
+ }
6817
+ function pendingFromAskBlock(block, dismissedQuestionSignature) {
6818
+ if (!block || block.source !== "ask_user" || !block.questions?.length) return null;
6819
+ const dismissed = dismissedQuestionSignature?.trim();
6820
+ if (dismissed && (!block.questionSignature || block.questionSignature === dismissed)) {
6821
+ return null;
6822
+ }
6823
+ const signature = block.questionSignature?.trim() || planQuestionsSignature(block.questions);
6824
+ return {
6825
+ id: `ask-block:${signature}`,
6826
+ signature,
6827
+ questions: block.questions,
6828
+ source: "ask_user"
6829
+ };
6830
+ }
6831
+ function askBlockStillWaiting(block, messages) {
6832
+ if (!messages?.length) return Boolean(block?.at);
6833
+ const askedAt = block?.at;
6834
+ if (!askedAt) return false;
6835
+ for (let i = messages.length - 1; i >= 0; i--) {
6836
+ const message = messages[i];
6837
+ if (message.role !== "user" || message.origin === "continue") continue;
6838
+ if (!message.ts) return true;
6839
+ return askedAt > message.ts;
6840
+ }
6841
+ return true;
6842
+ }
6843
+ function latestPendingPlanQuestions(input) {
6844
+ if (input.userReplied) return null;
6845
+ const fromBlock = () => pendingFromAskBlock(input.agentBlock, input.dismissedQuestionSignature);
6846
+ if (lastTopLevelToolIsAskUser(input.liveParts)) {
6847
+ return extractPendingPlanQuestions(input.liveParts) ?? fromBlock();
6848
+ }
6849
+ const last = input.messages[input.messages.length - 1];
6850
+ if (last?.role === "agent" && lastTopLevelToolIsAskUser(last.parts)) {
6851
+ return extractPendingPlanQuestions(last.parts) ?? fromBlock();
6852
+ }
6853
+ if (hasTopLevelTool(input.liveParts) || last?.role === "agent" && hasTopLevelTool(last.parts)) {
6854
+ return null;
6855
+ }
6856
+ if (input.status === "running" || input.status === "queued") return null;
6857
+ const stamped = fromBlock();
6858
+ if (stamped && askBlockStillWaiting(input.agentBlock, input.messages)) {
6859
+ return stamped;
6860
+ }
6861
+ return null;
6862
+ }
6863
+ function isPlanQuestionAnswersMessage(text7) {
6864
+ return text7.startsWith(PLAN_QUESTION_ANSWERS_PREFIX);
6865
+ }
6866
+ function formatPlanQuestionAnswers(questions2, answers) {
6867
+ const lines = [PLAN_QUESTION_ANSWERS_PREFIX, ""];
6868
+ for (let i = 0; i < questions2.length; i++) {
6869
+ const q = questions2[i];
6870
+ const a = answers.find((x) => x.questionIndex === i);
6871
+ const header = q.header ? `**${q.header}** \u2014 ` : "";
6872
+ const parts = [];
6873
+ if (a?.selected.length) parts.push(a.selected.join(", "));
6874
+ if (a?.other?.trim()) parts.push(a.other.trim());
6875
+ const body = parts.length ? parts.join(" \xB7 ") : "(no answer)";
6876
+ lines.push(`${i + 1}. ${header}${q.question} `);
6877
+ lines.push(` \u2192 ${body}`);
6878
+ }
6879
+ return lines.join("\n");
6880
+ }
6881
+ function formatPlanQuestionsForChat(questions2) {
6882
+ const lines = ["### Questions for you", ""];
6883
+ for (let i = 0; i < questions2.length; i++) {
6884
+ const q = questions2[i];
6885
+ const header = q.header ? `**${q.header}** \u2014 ` : "";
6886
+ lines.push(`${i + 1}. ${header}${q.question}`);
6887
+ for (let oi = 0; oi < q.options.length; oi++) {
6888
+ const opt = q.options[oi];
6889
+ const desc = opt.description?.trim();
6890
+ lines.push(
6891
+ desc ? ` - **${opt.label}** \u2014 ${desc}` : ` - **${opt.label}**`
6892
+ );
6893
+ }
6894
+ lines.push("");
6895
+ }
6896
+ lines.push("_Answer in the composer below._");
6897
+ return lines.join("\n").trimEnd();
6898
+ }
6899
+ var ASK_USER_TOOL_RE, PLAN_QUESTION_ANSWERS_PREFIX;
6900
+ var init_ask_user = __esm({
6901
+ "src/plan/ask-user.ts"() {
6902
+ "use strict";
6903
+ ASK_USER_TOOL_RE = /^(AskUserQuestion|ask_user|mcp__sideboard__ask_user)$/i;
6904
+ PLAN_QUESTION_ANSWERS_PREFIX = "Answers to your questions:";
6905
+ }
6906
+ });
6907
+
6723
6908
  // src/board/agent-block-view.ts
6724
6909
  function worktreeBoardStatus(group) {
6725
6910
  const order = ["running", "queued", "error", "broken"];
@@ -6742,6 +6927,11 @@ function visibleAgentBlock(thread) {
6742
6927
  const block = thread.agentBlock;
6743
6928
  if (!block?.reason?.trim()) return null;
6744
6929
  if (isDismissedAskUserBlock(block, thread.dismissedQuestionSignature)) return null;
6930
+ if (block.source === "ask_user") {
6931
+ const inFlight = thread.status === "running" || thread.status === "queued";
6932
+ if (inFlight && !block.onScreen) return null;
6933
+ if (!askBlockStillWaiting(block, thread.messages)) return null;
6934
+ }
6745
6935
  return block;
6746
6936
  }
6747
6937
  function worktreeAgentBlock(group) {
@@ -6777,6 +6967,7 @@ function threadCardBlockFields(group) {
6777
6967
  var init_agent_block_view = __esm({
6778
6968
  "src/board/agent-block-view.ts"() {
6779
6969
  "use strict";
6970
+ init_ask_user();
6780
6971
  }
6781
6972
  });
6782
6973
 
@@ -8309,175 +8500,6 @@ var init_injected_notices = __esm({
8309
8500
  }
8310
8501
  });
8311
8502
 
8312
- // src/plan/ask-user.ts
8313
- function planQuestionsSignature(questions2) {
8314
- return questions2.map((q) => {
8315
- const opts = q.options.map((o) => o.label).join("");
8316
- return `${q.question}${opts}`;
8317
- }).join("");
8318
- }
8319
- function asRecord2(v) {
8320
- return v != null && typeof v === "object" && !Array.isArray(v) ? v : null;
8321
- }
8322
- function parseOptions(raw) {
8323
- if (!Array.isArray(raw)) return [];
8324
- const out = [];
8325
- for (const item of raw) {
8326
- if (typeof item === "string" && item.trim()) {
8327
- out.push({ label: item.trim() });
8328
- continue;
8329
- }
8330
- const o = asRecord2(item);
8331
- if (!o) continue;
8332
- const label = typeof o.label === "string" ? o.label.trim() : typeof o.text === "string" ? o.text.trim() : typeof o.title === "string" ? o.title.trim() : "";
8333
- if (!label) continue;
8334
- const description = typeof o.description === "string" && o.description.trim() ? o.description.trim() : void 0;
8335
- out.push({ label, description });
8336
- }
8337
- return out;
8338
- }
8339
- function parseOneQuestion(raw) {
8340
- const o = asRecord2(raw);
8341
- if (!o) return null;
8342
- const question = typeof o.question === "string" ? o.question.trim() : typeof o.text === "string" ? o.text.trim() : typeof o.prompt === "string" ? o.prompt.trim() : "";
8343
- if (!question) return null;
8344
- const options = parseOptions(o.options);
8345
- if (options.length < 1) return null;
8346
- const header = typeof o.header === "string" && o.header.trim() ? o.header.trim() : void 0;
8347
- const multiSelect = Boolean(o.multiSelect ?? o.multi_select);
8348
- return { question, header, multiSelect, options };
8349
- }
8350
- function parsePlanQuestionsInput(input) {
8351
- const root = asRecord2(input);
8352
- if (!root) return [];
8353
- const list = Array.isArray(root.questions) ? root.questions : Array.isArray(root.question) ? root.question : root.question || root.prompt ? [root] : [];
8354
- const out = [];
8355
- for (const item of list) {
8356
- const q = parseOneQuestion(item);
8357
- if (q) out.push(q);
8358
- }
8359
- return out;
8360
- }
8361
- function isAskUserToolName(name) {
8362
- if (!name) return false;
8363
- const base = name.replace(/^mcp__sideboard__/i, "");
8364
- return ASK_USER_TOOL_RE.test(name) || /^ask_user$/i.test(base);
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
- }
8377
- function extractPendingPlanQuestions(parts) {
8378
- if (!parts?.length) return null;
8379
- for (let i = parts.length - 1; i >= 0; i--) {
8380
- const p = parts[i];
8381
- if (p.type !== "tool" || !isAskUserToolName(p.name)) continue;
8382
- const questions2 = questionsFromToolPart(p);
8383
- if (!questions2.length) continue;
8384
- return {
8385
- id: p.id || `ask-${i}`,
8386
- signature: planQuestionsSignature(questions2),
8387
- questions: questions2,
8388
- source: p.name || "ask_user"
8389
- };
8390
- }
8391
- return null;
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
- }
8418
- function latestPendingPlanQuestions(input) {
8419
- if (input.userReplied) return null;
8420
- const fromLive = extractPendingPlanQuestions(input.liveParts);
8421
- if (fromLive) return fromLive;
8422
- const last = input.messages[input.messages.length - 1];
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
- }
8434
- return null;
8435
- }
8436
- function isPlanQuestionAnswersMessage(text7) {
8437
- return text7.startsWith(PLAN_QUESTION_ANSWERS_PREFIX);
8438
- }
8439
- function formatPlanQuestionAnswers(questions2, answers) {
8440
- const lines = [PLAN_QUESTION_ANSWERS_PREFIX, ""];
8441
- for (let i = 0; i < questions2.length; i++) {
8442
- const q = questions2[i];
8443
- const a = answers.find((x) => x.questionIndex === i);
8444
- const header = q.header ? `**${q.header}** \u2014 ` : "";
8445
- const parts = [];
8446
- if (a?.selected.length) parts.push(a.selected.join(", "));
8447
- if (a?.other?.trim()) parts.push(a.other.trim());
8448
- const body = parts.length ? parts.join(" \xB7 ") : "(no answer)";
8449
- lines.push(`${i + 1}. ${header}${q.question} `);
8450
- lines.push(` \u2192 ${body}`);
8451
- }
8452
- return lines.join("\n");
8453
- }
8454
- function formatPlanQuestionsForChat(questions2) {
8455
- const lines = ["### Questions for you", ""];
8456
- for (let i = 0; i < questions2.length; i++) {
8457
- const q = questions2[i];
8458
- const header = q.header ? `**${q.header}** \u2014 ` : "";
8459
- lines.push(`${i + 1}. ${header}${q.question}`);
8460
- for (let oi = 0; oi < q.options.length; oi++) {
8461
- const opt = q.options[oi];
8462
- const desc = opt.description?.trim();
8463
- lines.push(
8464
- desc ? ` - **${opt.label}** \u2014 ${desc}` : ` - **${opt.label}**`
8465
- );
8466
- }
8467
- lines.push("");
8468
- }
8469
- lines.push("_Answer in the composer below._");
8470
- return lines.join("\n").trimEnd();
8471
- }
8472
- var ASK_USER_TOOL_RE, PLAN_QUESTION_ANSWERS_PREFIX;
8473
- var init_ask_user = __esm({
8474
- "src/plan/ask-user.ts"() {
8475
- "use strict";
8476
- ASK_USER_TOOL_RE = /^(AskUserQuestion|ask_user|mcp__sideboard__ask_user)$/i;
8477
- PLAN_QUESTION_ANSWERS_PREFIX = "Answers to your questions:";
8478
- }
8479
- });
8480
-
8481
8503
  // src/orchestrator/task-state.ts
8482
8504
  function isTerminalTaskState(state) {
8483
8505
  return state !== "submitted" && state !== "working";
@@ -8489,14 +8511,7 @@ function needsCoordinatorAction(state) {
8489
8511
  return isIncompleteTaskState(state) || state === "input-required";
8490
8512
  }
8491
8513
  function endedOnAskUser(parts) {
8492
- if (!parts?.length) return false;
8493
- for (let i = parts.length - 1; i >= 0; i--) {
8494
- const p = parts[i];
8495
- if (p.type === "tool" && !p.parentId) {
8496
- return isAskUserToolName(p.name);
8497
- }
8498
- }
8499
- return false;
8514
+ return lastTopLevelToolIsAskUser(parts);
8500
8515
  }
8501
8516
  function deriveTaskState(input) {
8502
8517
  if (input.stillRunning) {
@@ -22259,6 +22274,7 @@ function decisionBlockFromParts(parts, planMode, at = (/* @__PURE__ */ new Date(
22259
22274
  const reason = pending ? formatAskUserNotifyMessage(pending.questions) : "Waiting for an answer in that chat.";
22260
22275
  return {
22261
22276
  ...makeAgentBlock("ask_user", reason, at),
22277
+ onScreen: true,
22262
22278
  ...pending ? { questionSignature: pending.signature, questions: pending.questions } : {}
22263
22279
  };
22264
22280
  }
@@ -22316,6 +22332,38 @@ function dismissAskUserQuestion(threadId, signature) {
22316
22332
  ...clearBlock ? { agentBlock: null } : {}
22317
22333
  });
22318
22334
  }
22335
+ function askBlocksEqual(a, b) {
22336
+ if (a === b) return true;
22337
+ if (!a || !b) return false;
22338
+ return a.source === b.source && a.reason === b.reason && a.at === b.at && a.onScreen === b.onScreen && a.questionSignature === b.questionSignature;
22339
+ }
22340
+ function askBlockAfterLiveParts(existing, parts) {
22341
+ const last = lastTopLevelTool(parts);
22342
+ if (last?.type === "tool" && isAskUserToolName(last.name)) {
22343
+ if (existing?.source === "ask_user" && existing.onScreen) return existing;
22344
+ const pending = extractPendingPlanQuestions(parts);
22345
+ const questions2 = pending?.questions ?? existing?.questions;
22346
+ if (!questions2?.length) {
22347
+ return existing?.source === "ask_user" ? { ...existing, onScreen: true } : existing ?? null;
22348
+ }
22349
+ const at = existing?.source === "ask_user" ? existing.at : void 0;
22350
+ return {
22351
+ ...makeAgentBlock("ask_user", formatAskUserNotifyMessage(questions2), at),
22352
+ onScreen: true,
22353
+ questionSignature: pending?.signature ?? existing?.questionSignature,
22354
+ questions: questions2
22355
+ };
22356
+ }
22357
+ if (last && existing?.source === "ask_user") return null;
22358
+ return existing ?? null;
22359
+ }
22360
+ function syncAskUserBlockFromLive(threadId, parts) {
22361
+ const thread = readThread(threadId);
22362
+ if (!thread || thread.status === "archived") return;
22363
+ const next = askBlockAfterLiveParts(thread.agentBlock, parts);
22364
+ if (askBlocksEqual(thread.agentBlock, next)) return;
22365
+ updateThread(threadId, { agentBlock: next });
22366
+ }
22319
22367
  function writeAgentBlock(threadId, block) {
22320
22368
  const thread = readThread(threadId);
22321
22369
  if (!thread || thread.status === "archived") return;
@@ -25168,6 +25216,7 @@ function noteTurnLiveEvent(threadId, event) {
25168
25216
  const prev = buffers.get(threadId) ?? { parts: [], timer: null };
25169
25217
  prev.parts = trimParts(applyAgentEvent(prev.parts, event));
25170
25218
  buffers.set(threadId, prev);
25219
+ syncAskUserBlockFromLive(threadId, prev.parts);
25171
25220
  if (event.type === "exit") {
25172
25221
  flush(threadId);
25173
25222
  const cur = buffers.get(threadId);
@@ -25224,6 +25273,7 @@ var init_turn_live = __esm({
25224
25273
  import_node_fs57 = require("fs");
25225
25274
  init_message_parts();
25226
25275
  init_paths();
25276
+ init_agent_block();
25227
25277
  buffers = /* @__PURE__ */ new Map();
25228
25278
  FLUSH_MS = 800;
25229
25279
  MAX_PARTS = 80;
@@ -32117,6 +32167,7 @@ __export(index_exports, {
32117
32167
  archiveRemovedWorkspaceChats: () => archiveRemovedWorkspaceChats,
32118
32168
  archivesWithRemovedWorkspace: () => archivesWithRemovedWorkspace,
32119
32169
  armSchedules: () => armSchedules,
32170
+ askBlockStillWaiting: () => askBlockStillWaiting,
32120
32171
  assertAbleTimeCredential: () => assertAbleTimeCredential,
32121
32172
  assertAbleTimeMcpCredential: () => assertAbleTimeMcpCredential,
32122
32173
  assertOrchestratorCapableAgent: () => assertOrchestratorCapableAgent,
@@ -32557,6 +32608,7 @@ __export(index_exports, {
32557
32608
  lastAgentReply: () => lastAgentReply,
32558
32609
  lastAssistantMessageText: () => lastAssistantMessageText,
32559
32610
  lastRequestOccupancy: () => lastRequestOccupancy,
32611
+ lastTopLevelToolIsAskUser: () => lastTopLevelToolIsAskUser,
32560
32612
  latestPendingPlanQuestions: () => latestPendingPlanQuestions,
32561
32613
  linearAuthorizationHeader: () => linearAuthorizationHeader,
32562
32614
  linearCycleIsActive: () => linearCycleIsActive,
@@ -34828,6 +34880,7 @@ function parsePhoneCreate(value) {
34828
34880
  }
34829
34881
  function summarize(thread) {
34830
34882
  const pr = phonePrPill(thread);
34883
+ const block = visibleAgentBlock(thread);
34831
34884
  return {
34832
34885
  id: thread.id,
34833
34886
  title: thread.title?.trim() || "Untitled",
@@ -34838,14 +34891,12 @@ function summarize(thread) {
34838
34891
  ...pr?.url ? { prUrl: pr.url } : {},
34839
34892
  ...pr?.number ? { prNumber: pr.number } : {},
34840
34893
  ...pr?.status ? { prStatus: pr.status } : {},
34841
- ...thread.agentBlock ? { needsYou: true, blockedReason: thread.agentBlock.reason } : {}
34894
+ ...block ? { needsYou: true, blockedReason: block.reason } : {}
34842
34895
  };
34843
34896
  }
34844
34897
  function previewOf2(thread) {
34845
- const messages = listPhoneMessages(thread);
34846
- const last = messages[messages.length - 1];
34847
- if (!last) return "";
34848
- return clip(last.text.replace(/\s+/g, " ").trim(), PREVIEW_LIMIT2);
34898
+ const last = listPhoneMessages(thread).at(-1);
34899
+ return last ? clip(last.text.replace(/\s+/g, " ").trim(), PREVIEW_LIMIT2) : "";
34849
34900
  }
34850
34901
  function repoName2(repoPath) {
34851
34902
  return repoPath.replace(/\/$/, "").split("/").pop() || repoPath;
@@ -35201,7 +35252,8 @@ function emitChatTurn(opts, chatId, threadId) {
35201
35252
  const pending = latestPendingPlanQuestions({
35202
35253
  messages: thread.messages,
35203
35254
  agentBlock: thread.agentBlock,
35204
- dismissedQuestionSignature: thread.dismissedQuestionSignature
35255
+ dismissedQuestionSignature: thread.dismissedQuestionSignature,
35256
+ status: thread.status
35205
35257
  });
35206
35258
  if (pending && result.taskState !== "failed" && result.taskState !== "canceled" && (result.taskState === "input-required" || thread.agentBlock?.source === "ask_user")) {
35207
35259
  emitControl(opts, {
@@ -35572,7 +35624,8 @@ function republishPendingAsk(opts, chatId) {
35572
35624
  const pending = latestPendingPlanQuestions({
35573
35625
  messages: thread.messages,
35574
35626
  agentBlock: thread.agentBlock,
35575
- dismissedQuestionSignature: thread.dismissedQuestionSignature
35627
+ dismissedQuestionSignature: thread.dismissedQuestionSignature,
35628
+ status: thread.status
35576
35629
  });
35577
35630
  if (!pending) return;
35578
35631
  emitControl(opts, {
@@ -37835,7 +37888,8 @@ function runCoordinatorPrompt(opts, body, generation) {
37835
37888
  const pending = latestPendingPlanQuestions({
37836
37889
  messages: thread.messages,
37837
37890
  agentBlock: thread.agentBlock,
37838
- dismissedQuestionSignature: thread.dismissedQuestionSignature
37891
+ dismissedQuestionSignature: thread.dismissedQuestionSignature,
37892
+ status: thread.status
37839
37893
  });
37840
37894
  if (pending && result.taskState !== "failed" && result.taskState !== "canceled" && (result.taskState === "input-required" || thread.agentBlock?.source === "ask_user")) {
37841
37895
  opts.onOutbound({
@@ -38284,7 +38338,15 @@ init_paths();
38284
38338
  init_thread_store();
38285
38339
  var PHONE_BOARD_SYNC_MS = 300;
38286
38340
  function chatKey(row2) {
38287
- return [row2.id, row2.title, row2.status, row2.agent, row2.preview].join(" ");
38341
+ return [
38342
+ row2.id,
38343
+ row2.title,
38344
+ row2.status,
38345
+ row2.agent,
38346
+ row2.preview,
38347
+ row2.needsYou ? "1" : "0",
38348
+ row2.blockedReason ?? ""
38349
+ ].join(" ");
38288
38350
  }
38289
38351
  function phoneBoardKey(sidebar) {
38290
38352
  const orchestration = sidebar.orchestration.map(chatKey).join("\n");
@@ -47003,6 +47065,7 @@ async function pollSlackOutboundWatches(opts) {
47003
47065
  archiveRemovedWorkspaceChats,
47004
47066
  archivesWithRemovedWorkspace,
47005
47067
  armSchedules,
47068
+ askBlockStillWaiting,
47006
47069
  assertAbleTimeCredential,
47007
47070
  assertAbleTimeMcpCredential,
47008
47071
  assertOrchestratorCapableAgent,
@@ -47443,6 +47506,7 @@ async function pollSlackOutboundWatches(opts) {
47443
47506
  lastAgentReply,
47444
47507
  lastAssistantMessageText,
47445
47508
  lastRequestOccupancy,
47509
+ lastTopLevelToolIsAskUser,
47446
47510
  latestPendingPlanQuestions,
47447
47511
  linearAuthorizationHeader,
47448
47512
  linearCycleIsActive,