@sideboard-ai/core 0.1.310 → 0.1.312

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) {
@@ -13854,18 +13869,18 @@ function mcpUiContentSecurityPolicy(csp) {
13854
13869
  const connect = (csp?.connectDomains ?? []).join(" ");
13855
13870
  const frames = csp?.frameDomains?.length ? csp.frameDomains.join(" ") : "'none'";
13856
13871
  const base = csp?.baseUriDomains?.length ? csp.baseUriDomains.join(" ") : "'none'";
13872
+ const connectSrc = connect ? `'self' ${connect}`.trim() : "'none'";
13857
13873
  return [
13858
13874
  "default-src 'none'",
13859
- `script-src 'self' 'unsafe-inline' 'unsafe-eval' ${resource}`.trim(),
13875
+ `script-src 'self' 'unsafe-inline' ${resource}`.trim(),
13860
13876
  `style-src 'self' 'unsafe-inline' ${resource}`.trim(),
13861
- `img-src 'self' data: blob: ${resource}`.trim(),
13862
- `font-src 'self' data: ${resource}`.trim(),
13863
- `connect-src 'self' ${connect}`.trim(),
13864
- `media-src 'self' data: blob: ${resource}`.trim(),
13877
+ `img-src 'self' data: ${resource}`.trim(),
13878
+ `font-src 'self' ${resource}`.trim(),
13879
+ `connect-src ${connectSrc}`,
13880
+ `media-src 'self' data: ${resource}`.trim(),
13865
13881
  `frame-src ${frames}`,
13866
13882
  `base-uri ${base}`,
13867
- "object-src 'none'",
13868
- "form-action 'self'"
13883
+ "object-src 'none'"
13869
13884
  ].join("; ");
13870
13885
  }
13871
13886
  function htmlText(text7, blob) {
@@ -13902,8 +13917,10 @@ function originList(value) {
13902
13917
  return out;
13903
13918
  }
13904
13919
  function originToken(value) {
13920
+ const trimmed = value.trim();
13921
+ if (/^(https?|wss?):\/\/\*\.[a-z0-9.-]+(?::\d+)?$/i.test(trimmed)) return trimmed;
13905
13922
  try {
13906
- const url = new URL(value.trim());
13923
+ const url = new URL(trimmed);
13907
13924
  if (url.protocol !== "https:" && url.protocol !== "http:" && url.protocol !== "wss:" && url.protocol !== "ws:") {
13908
13925
  return null;
13909
13926
  }
@@ -15264,6 +15281,524 @@ var init_orch_mcp_isolation = __esm({
15264
15281
  }
15265
15282
  });
15266
15283
 
15284
+ // src/mcp-ui/visibility.ts
15285
+ function visibilityFromMeta(meta) {
15286
+ const rec = asRecord4(meta);
15287
+ const ui = asRecord4(rec.ui);
15288
+ const raw = ui.visibility;
15289
+ if (!Array.isArray(raw)) return ["model", "app"];
15290
+ const out = [];
15291
+ for (const item of raw) {
15292
+ if (item !== "model" && item !== "app") continue;
15293
+ if (!out.includes(item)) out.push(item);
15294
+ }
15295
+ return out.length ? out : ["model", "app"];
15296
+ }
15297
+ function toolVisibleTo(visibility, audience) {
15298
+ const vis = visibility?.length ? visibility : ["model", "app"];
15299
+ return vis.includes(audience);
15300
+ }
15301
+ function asRecord4(value) {
15302
+ if (!value || typeof value !== "object" || Array.isArray(value)) return {};
15303
+ return value;
15304
+ }
15305
+ var init_visibility = __esm({
15306
+ "src/mcp-ui/visibility.ts"() {
15307
+ "use strict";
15308
+ }
15309
+ });
15310
+
15311
+ // src/mcp-ui/proxy-server.ts
15312
+ function attachMcpUiProxyHandlers(server, session) {
15313
+ server.setRequestHandler(import_types.ListToolsRequestSchema, async () => {
15314
+ const tools = await session.listTools();
15315
+ return { tools: tools.filter((tool) => toolVisibleTo(tool.visibility, "model")).map(listedTool) };
15316
+ });
15317
+ server.setRequestHandler(import_types.CallToolRequestSchema, async (request) => {
15318
+ const name = request.params.name;
15319
+ const tools = await session.listTools();
15320
+ const tool = tools.find((item) => item.name === name);
15321
+ if (!tool || !toolVisibleTo(tool.visibility, "model")) {
15322
+ throw new Error(`Tool ${name} is not available to the model`);
15323
+ }
15324
+ return await session.callTool(name, request.params.arguments ?? {});
15325
+ });
15326
+ server.setRequestHandler(import_types.ReadResourceRequestSchema, async (request) => {
15327
+ const resource = await session.readResource(request.params.uri);
15328
+ if (!resource) throw new Error(`Resource ${request.params.uri} was empty`);
15329
+ return {
15330
+ contents: [
15331
+ {
15332
+ uri: resource.uri,
15333
+ ...resource.mimeType ? { mimeType: resource.mimeType } : {},
15334
+ ...resource.text != null ? { text: resource.text } : {},
15335
+ ...resource.blob != null ? { blob: resource.blob } : {}
15336
+ }
15337
+ ]
15338
+ };
15339
+ });
15340
+ server.setRequestHandler(import_types.ListResourcesRequestSchema, async () => session.listResources());
15341
+ server.setRequestHandler(
15342
+ import_types.ListResourceTemplatesRequestSchema,
15343
+ async () => session.listResourceTemplates()
15344
+ );
15345
+ server.setRequestHandler(import_types.ListPromptsRequestSchema, async () => session.listPrompts());
15346
+ server.setRequestHandler(import_types.GetPromptRequestSchema, async (request) => {
15347
+ return await session.getPrompt(request.params.name, request.params.arguments);
15348
+ });
15349
+ server.fallbackRequestHandler = async (request) => {
15350
+ return await session.forward(request.method, request.params);
15351
+ };
15352
+ }
15353
+ function listedTool(tool) {
15354
+ return {
15355
+ name: tool.name,
15356
+ ...tool.description ? { description: tool.description } : {},
15357
+ inputSchema: tool.inputSchema ?? { type: "object", properties: {} },
15358
+ _meta: {
15359
+ ui: {
15360
+ ...tool.resourceUri ? { resourceUri: tool.resourceUri } : {},
15361
+ visibility: tool.visibility
15362
+ }
15363
+ }
15364
+ };
15365
+ }
15366
+ var import_server, import_types;
15367
+ var init_proxy_server = __esm({
15368
+ "src/mcp-ui/proxy-server.ts"() {
15369
+ "use strict";
15370
+ import_server = require("@modelcontextprotocol/sdk/server/index.js");
15371
+ import_types = require("@modelcontextprotocol/sdk/types.js");
15372
+ init_visibility();
15373
+ }
15374
+ });
15375
+
15376
+ // src/mcp-ui/proxy-http.ts
15377
+ async function listenMcpUiProxy(opts) {
15378
+ const token = (0, import_node_crypto11.randomBytes)(24).toString("hex");
15379
+ const transports = /* @__PURE__ */ new Map();
15380
+ const httpServer = (0, import_node_http.createServer)((req, res) => {
15381
+ void handle(req, res);
15382
+ });
15383
+ await new Promise((resolve3, reject) => {
15384
+ httpServer.once("error", reject);
15385
+ httpServer.listen(0, "127.0.0.1", () => resolve3());
15386
+ });
15387
+ const addr = httpServer.address();
15388
+ if (!addr || typeof addr === "string") throw new Error("mcp-ui proxy failed to bind");
15389
+ const origin = `http://127.0.0.1:${addr.port}`;
15390
+ async function handle(req, res) {
15391
+ if (req.headers.authorization !== `Bearer ${token}`) {
15392
+ res.writeHead(401).end();
15393
+ return;
15394
+ }
15395
+ const target = parseMcpUiProxyPath(req.url);
15396
+ if (!target) {
15397
+ res.writeHead(404).end();
15398
+ return;
15399
+ }
15400
+ try {
15401
+ const session = await opts.sessionFor(target.server, target.dirsKey);
15402
+ if (!session) {
15403
+ res.writeHead(404).end();
15404
+ return;
15405
+ }
15406
+ const header = req.headers["mcp-session-id"];
15407
+ const sid = typeof header === "string" ? header : "";
15408
+ const sessionKey = `${target.server}:${target.dirsKey}`;
15409
+ let transport = sid ? transports.get(`${sessionKey}:${sid}`) : void 0;
15410
+ if (!transport) {
15411
+ if (req.method !== "POST") {
15412
+ res.writeHead(400).end();
15413
+ return;
15414
+ }
15415
+ const created = new import_streamableHttp.StreamableHTTPServerTransport({
15416
+ sessionIdGenerator: () => (0, import_node_crypto11.randomUUID)(),
15417
+ allowedHosts: ["127.0.0.1", "localhost"],
15418
+ onsessioninitialized: (id) => {
15419
+ transports.set(`${sessionKey}:${id}`, created);
15420
+ },
15421
+ onsessionclosed: (id) => {
15422
+ transports.delete(`${sessionKey}:${id}`);
15423
+ }
15424
+ });
15425
+ transport = created;
15426
+ const mcp = new import_server2.Server(
15427
+ { name: `sideboard-ui-proxy-${target.server}`, version: "1.0.0" },
15428
+ { capabilities: session.capabilities() }
15429
+ );
15430
+ attachMcpUiProxyHandlers(mcp, session);
15431
+ await mcp.connect(created);
15432
+ }
15433
+ await transport.handleRequest(req, res);
15434
+ } catch {
15435
+ if (!res.headersSent) res.writeHead(500).end();
15436
+ }
15437
+ }
15438
+ return {
15439
+ urlFor(server, dirsKey) {
15440
+ const base = `${origin}/s/${encodeURIComponent(server)}`;
15441
+ return dirsKey ? `${base}/d/${dirsKey}` : base;
15442
+ },
15443
+ headers: { Authorization: `Bearer ${token}` },
15444
+ async close() {
15445
+ await Promise.all([...transports.values()].map((item) => item.close().catch(() => void 0)));
15446
+ transports.clear();
15447
+ await new Promise((resolve3) => httpServer.close(() => resolve3()));
15448
+ }
15449
+ };
15450
+ }
15451
+ function parseMcpUiProxyPath(url) {
15452
+ const path2 = (url ?? "").split("?")[0] ?? "";
15453
+ if (!path2.startsWith("/s/")) return null;
15454
+ const rest = path2.slice(3).replace(/\/$/, "");
15455
+ const split = rest.indexOf("/d/");
15456
+ try {
15457
+ if (split < 0) {
15458
+ const server2 = decodeURIComponent(rest).trim();
15459
+ return server2 ? { server: server2, dirsKey: "" } : null;
15460
+ }
15461
+ const server = decodeURIComponent(rest.slice(0, split)).trim();
15462
+ const dirsKey = rest.slice(split + 3);
15463
+ if (!server || !/^[a-f0-9]{16}$/.test(dirsKey)) return null;
15464
+ return { server, dirsKey };
15465
+ } catch {
15466
+ return null;
15467
+ }
15468
+ }
15469
+ var import_node_crypto11, import_node_http, import_server2, import_streamableHttp;
15470
+ var init_proxy_http = __esm({
15471
+ "src/mcp-ui/proxy-http.ts"() {
15472
+ "use strict";
15473
+ import_node_crypto11 = require("crypto");
15474
+ import_node_http = require("http");
15475
+ import_server2 = require("@modelcontextprotocol/sdk/server/index.js");
15476
+ import_streamableHttp = require("@modelcontextprotocol/sdk/server/streamableHttp.js");
15477
+ init_proxy_server();
15478
+ }
15479
+ });
15480
+
15481
+ // src/mcp-ui/session.ts
15482
+ async function orEmpty(run2, fallback) {
15483
+ try {
15484
+ return await run2();
15485
+ } catch {
15486
+ return fallback;
15487
+ }
15488
+ }
15489
+ async function openMcpUiSession(launch) {
15490
+ return openMcpUiSessionFromTransport(transportForLaunch(launch));
15491
+ }
15492
+ async function openMcpUiSessionFromTransport(transport) {
15493
+ const client = new import_client.Client(
15494
+ { name: "sideboard", version: "1.0.0" },
15495
+ { capabilities: UI_CAPABILITIES }
15496
+ );
15497
+ await client.connect(transport, { timeout: REQUEST_TIMEOUT_MS });
15498
+ return {
15499
+ async listTools() {
15500
+ const listed = await client.listTools(void 0, { timeout: REQUEST_TIMEOUT_MS });
15501
+ return listed.tools.map((tool) => {
15502
+ const meta = tool._meta;
15503
+ return {
15504
+ name: tool.name,
15505
+ ...tool.description ? { description: tool.description } : {},
15506
+ ...tool.inputSchema ? { inputSchema: tool.inputSchema } : {},
15507
+ resourceUri: uiResourceUriFromMeta(meta),
15508
+ visibility: visibilityFromMeta(meta),
15509
+ ...cspFromMeta(meta) ? { csp: cspFromMeta(meta) } : {}
15510
+ };
15511
+ });
15512
+ },
15513
+ listResources: () => orEmpty(
15514
+ () => client.listResources(void 0, { timeout: REQUEST_TIMEOUT_MS }),
15515
+ { resources: [] }
15516
+ ),
15517
+ listResourceTemplates: () => orEmpty(
15518
+ () => client.listResourceTemplates(void 0, { timeout: REQUEST_TIMEOUT_MS }),
15519
+ { resourceTemplates: [] }
15520
+ ),
15521
+ listPrompts: () => orEmpty(
15522
+ () => client.listPrompts(void 0, { timeout: REQUEST_TIMEOUT_MS }),
15523
+ { prompts: [] }
15524
+ ),
15525
+ getPrompt(name, args) {
15526
+ return client.getPrompt({ name, arguments: args }, { timeout: REQUEST_TIMEOUT_MS });
15527
+ },
15528
+ async readResource(uri) {
15529
+ const result = await client.readResource({ uri }, { timeout: REQUEST_TIMEOUT_MS });
15530
+ const content = result.contents?.[0];
15531
+ if (!content) return null;
15532
+ const text7 = "text" in content && typeof content.text === "string" ? content.text : void 0;
15533
+ const blob = "blob" in content && typeof content.blob === "string" ? content.blob : void 0;
15534
+ return {
15535
+ uri: content.uri,
15536
+ ...content.mimeType ? { mimeType: content.mimeType } : {},
15537
+ ...text7 != null ? { text: text7 } : {},
15538
+ ...blob != null ? { blob } : {},
15539
+ ...cspFromMeta(content._meta) ? { csp: cspFromMeta(content._meta) } : {}
15540
+ };
15541
+ },
15542
+ async callTool(name, args) {
15543
+ return client.callTool({ name, arguments: args }, void 0, { timeout: REQUEST_TIMEOUT_MS });
15544
+ },
15545
+ capabilities() {
15546
+ const caps = client.getServerCapabilities() ?? {};
15547
+ return {
15548
+ tools: caps.tools ?? {},
15549
+ resources: caps.resources ?? {},
15550
+ prompts: caps.prompts ?? {},
15551
+ completions: caps.completions ?? {},
15552
+ ...caps.logging ? { logging: caps.logging } : {}
15553
+ };
15554
+ },
15555
+ forward(method, params) {
15556
+ return client.request(
15557
+ { method, params },
15558
+ import_types2.ResultSchema,
15559
+ { timeout: REQUEST_TIMEOUT_MS }
15560
+ );
15561
+ },
15562
+ async close() {
15563
+ await client.close();
15564
+ }
15565
+ };
15566
+ }
15567
+ function transportForLaunch(launch) {
15568
+ if (launch.kind === "stdio") {
15569
+ return new import_stdio.StdioClientTransport({
15570
+ command: launch.command,
15571
+ args: launch.args,
15572
+ env: { ...(0, import_stdio.getDefaultEnvironment)(), ...launch.env },
15573
+ stderr: "ignore",
15574
+ ...launch.cwd ? { cwd: launch.cwd } : {}
15575
+ });
15576
+ }
15577
+ const url = new URL(launch.url);
15578
+ const requestInit = launch.headers ? { headers: launch.headers } : void 0;
15579
+ if (launch.kind === "sse") {
15580
+ return new import_sse.SSEClientTransport(url, requestInit ? { requestInit } : void 0);
15581
+ }
15582
+ return new import_streamableHttp2.StreamableHTTPClientTransport(url, requestInit ? { requestInit } : void 0);
15583
+ }
15584
+ var import_client, import_sse, import_stdio, import_streamableHttp2, import_types2, REQUEST_TIMEOUT_MS, UI_CAPABILITIES;
15585
+ var init_session = __esm({
15586
+ "src/mcp-ui/session.ts"() {
15587
+ "use strict";
15588
+ import_client = require("@modelcontextprotocol/sdk/client/index.js");
15589
+ import_sse = require("@modelcontextprotocol/sdk/client/sse.js");
15590
+ import_stdio = require("@modelcontextprotocol/sdk/client/stdio.js");
15591
+ import_streamableHttp2 = require("@modelcontextprotocol/sdk/client/streamableHttp.js");
15592
+ import_types2 = require("@modelcontextprotocol/sdk/types.js");
15593
+ init_meta();
15594
+ init_visibility();
15595
+ REQUEST_TIMEOUT_MS = 2e4;
15596
+ UI_CAPABILITIES = {
15597
+ extensions: {
15598
+ "io.modelcontextprotocol/ui": {
15599
+ mimeTypes: ["text/html;profile=mcp-app"]
15600
+ }
15601
+ }
15602
+ };
15603
+ }
15604
+ });
15605
+
15606
+ // src/mcp-ui/host.ts
15607
+ function getMcpUiHost() {
15608
+ if (!singleton) {
15609
+ singleton = new McpUiHost({
15610
+ entries: (projectDirs) => listUserClaudeMcpServerEntries((0, import_node_os16.homedir)(), projectDirs)
15611
+ });
15612
+ }
15613
+ return singleton;
15614
+ }
15615
+ async function proxyClaudeUserMcp(orchestrator, projectDirs) {
15616
+ if (orchestrator) return {};
15617
+ const dirs = projectDirs.filter((d) => typeof d === "string" && d.length > 0);
15618
+ return getMcpUiHost().proxyEntries(listUserClaudeMcpServerEntries((0, import_node_os16.homedir)(), dirs), dirs);
15619
+ }
15620
+ function closeMcpUiHost() {
15621
+ const host = singleton;
15622
+ singleton = void 0;
15623
+ if (host) void host.closeAll();
15624
+ }
15625
+ function dirsKeyFor(projectDirs) {
15626
+ if (!projectDirs?.length) return "";
15627
+ return (0, import_node_crypto12.createHash)("sha256").update(projectDirs.join("\0")).digest("hex").slice(0, 16);
15628
+ }
15629
+ var import_node_crypto12, import_node_os16, TOOL_TTL_MS, McpUiHost, singleton;
15630
+ var init_host = __esm({
15631
+ "src/mcp-ui/host.ts"() {
15632
+ "use strict";
15633
+ import_node_crypto12 = require("crypto");
15634
+ import_node_os16 = require("os");
15635
+ init_orch_mcp_isolation();
15636
+ init_meta();
15637
+ init_proxy_http();
15638
+ init_session();
15639
+ init_visibility();
15640
+ TOOL_TTL_MS = 5 * 60 * 1e3;
15641
+ McpUiHost = class {
15642
+ constructor(opts) {
15643
+ this.opts = opts;
15644
+ }
15645
+ opts;
15646
+ sessions = /* @__PURE__ */ new Map();
15647
+ toolLists = /* @__PURE__ */ new Map();
15648
+ proxy;
15649
+ proxyDirs = /* @__PURE__ */ new Map();
15650
+ async viewForClaudeTool(toolName, projectDirs) {
15651
+ const entries = this.userEntries(projectDirs);
15652
+ const match = matchClaudeMcpTool(toolName, Object.keys(entries));
15653
+ if (!match) return null;
15654
+ const launch = parseMcpServerLaunch(entries[match.server] ?? {});
15655
+ if (!launch) return null;
15656
+ try {
15657
+ const session = await this.sessionFor(match.server, launch);
15658
+ const tools = await this.toolsFor(match.server, launch, session);
15659
+ const tool = tools.find((item) => item.name === match.tool);
15660
+ if (!tool?.resourceUri) return null;
15661
+ const resource = await session.readResource(tool.resourceUri);
15662
+ if (!resource) return null;
15663
+ const html = htmlFromResourceContent(resource);
15664
+ if (!html) return null;
15665
+ const csp = resource.csp ?? tool.csp;
15666
+ return {
15667
+ server: match.server,
15668
+ tool: match.tool,
15669
+ uri: html.uri,
15670
+ mimeType: html.mimeType,
15671
+ html: html.html,
15672
+ csp: mcpUiContentSecurityPolicy(csp)
15673
+ };
15674
+ } catch (err) {
15675
+ console.error(
15676
+ `[mcp-ui] ${match.server}/${match.tool}:`,
15677
+ err instanceof Error ? err.message : err
15678
+ );
15679
+ return null;
15680
+ }
15681
+ }
15682
+ /**
15683
+ * Point Claude at loopback HTTP so it shares this host's upstream session
15684
+ * and never sees `visibility: ["app"]` tools.
15685
+ */
15686
+ async proxyEntries(entries, projectDirs) {
15687
+ const names = Object.keys(entries).filter((name) => name.trim());
15688
+ if (names.length === 0) return {};
15689
+ const dirsKey = dirsKeyFor(projectDirs);
15690
+ this.proxyDirs.set(dirsKey, projectDirs);
15691
+ try {
15692
+ const listen = await this.ensureProxy();
15693
+ const out = {};
15694
+ for (const name of names) {
15695
+ out[name] = {
15696
+ type: "http",
15697
+ url: listen.urlFor(name, dirsKey),
15698
+ headers: listen.headers
15699
+ };
15700
+ }
15701
+ return out;
15702
+ } catch (err) {
15703
+ console.error("[mcp-ui] proxy:", err instanceof Error ? err.message : err);
15704
+ return { ...entries };
15705
+ }
15706
+ }
15707
+ async callTool(server, tool, args, projectDirs) {
15708
+ const entry = this.userEntries(projectDirs)[server];
15709
+ if (!entry) throw new Error(`MCP server ${server} is not available`);
15710
+ const launch = parseMcpServerLaunch(entry);
15711
+ if (!launch) throw new Error(`MCP server ${server} is not available`);
15712
+ const session = await this.sessionFor(server, launch);
15713
+ const tools = await this.toolsFor(server, launch, session);
15714
+ const info = tools.find((item) => item.name === tool);
15715
+ if (!info || !toolVisibleTo(info.visibility, "app")) {
15716
+ throw new Error(`Tool ${tool} is not available to the app`);
15717
+ }
15718
+ return session.callTool(tool, args);
15719
+ }
15720
+ async readResource(server, uri, projectDirs) {
15721
+ const session = await this.sessionForName(server, projectDirs);
15722
+ if (!session) throw new Error(`MCP server ${server} is not available`);
15723
+ const resource = await session.readResource(uri);
15724
+ if (!resource) throw new Error(`Resource ${uri} was empty`);
15725
+ return {
15726
+ contents: [
15727
+ {
15728
+ uri: resource.uri,
15729
+ ...resource.mimeType ? { mimeType: resource.mimeType } : {},
15730
+ ...resource.text != null ? { text: resource.text } : {},
15731
+ ...resource.blob != null ? { blob: resource.blob } : {}
15732
+ }
15733
+ ]
15734
+ };
15735
+ }
15736
+ async closeAll() {
15737
+ const pending = [...this.sessions.values()];
15738
+ const proxy = this.proxy;
15739
+ this.sessions.clear();
15740
+ this.toolLists.clear();
15741
+ this.proxyDirs.clear();
15742
+ this.proxy = void 0;
15743
+ await Promise.all([
15744
+ ...pending.map((session) => session.then((open) => open.close()).catch(() => void 0)),
15745
+ proxy ? proxy.then((listen) => listen.close()).catch(() => void 0) : Promise.resolve()
15746
+ ]);
15747
+ }
15748
+ ensureProxy() {
15749
+ if (this.proxy) return this.proxy;
15750
+ this.proxy = listenMcpUiProxy({
15751
+ sessionFor: (server, dirsKey) => {
15752
+ if (dirsKey && !this.proxyDirs.has(dirsKey)) return Promise.resolve(null);
15753
+ return this.sessionForName(server, this.proxyDirs.get(dirsKey));
15754
+ }
15755
+ }).catch((err) => {
15756
+ this.proxy = void 0;
15757
+ throw err;
15758
+ });
15759
+ return this.proxy;
15760
+ }
15761
+ userEntries(projectDirs) {
15762
+ const out = {};
15763
+ for (const [name, entry] of Object.entries(this.opts.entries(projectDirs))) {
15764
+ if (!name.trim() || isInjectedOrchMcpName(name) || !entry) continue;
15765
+ out[name] = entry;
15766
+ }
15767
+ return out;
15768
+ }
15769
+ async sessionForName(server, projectDirs) {
15770
+ const entry = this.userEntries(projectDirs)[server];
15771
+ if (!entry) return null;
15772
+ const launch = parseMcpServerLaunch(entry);
15773
+ if (!launch) return null;
15774
+ return this.sessionFor(server, launch);
15775
+ }
15776
+ sessionFor(server, launch) {
15777
+ const key = `${server}
15778
+ ${JSON.stringify(launch)}`;
15779
+ const existing = this.sessions.get(key);
15780
+ if (existing) return existing;
15781
+ const open = this.opts.openSession ?? openMcpUiSession;
15782
+ const pending = open(launch).catch((err) => {
15783
+ this.sessions.delete(key);
15784
+ throw err;
15785
+ });
15786
+ this.sessions.set(key, pending);
15787
+ return pending;
15788
+ }
15789
+ async toolsFor(server, launch, session) {
15790
+ const key = `${server}
15791
+ ${JSON.stringify(launch)}`;
15792
+ const cached2 = this.toolLists.get(key);
15793
+ if (cached2 && cached2.key === key && Date.now() - cached2.at < TOOL_TTL_MS) return cached2.tools;
15794
+ const tools = await session.listTools();
15795
+ this.toolLists.set(key, { at: Date.now(), key, tools });
15796
+ return tools;
15797
+ }
15798
+ };
15799
+ }
15800
+ });
15801
+
15267
15802
  // src/agents/types.ts
15268
15803
  function planModeTurnInstruction(planMode) {
15269
15804
  return planMode ? PLAN_MODE_INSTRUCTION : PLAN_MODE_OFF_INSTRUCTION;
@@ -15459,7 +15994,7 @@ function entryDir() {
15459
15994
  const cjsDir = typeof __dirname !== "undefined" ? __dirname : "";
15460
15995
  if (cjsDir) return cjsDir;
15461
15996
  try {
15462
- return (0, import_node_path41.dirname)((0, import_node_url2.fileURLToPath)(import_meta3.url));
15997
+ return (0, import_node_path41.dirname)((0, import_node_url2.fileURLToPath)(import_meta5.url));
15463
15998
  } catch {
15464
15999
  try {
15465
16000
  const req = (0, import_node_module2.createRequire)(process.cwd() + "/");
@@ -15509,7 +16044,7 @@ async function buildClaudeRpcTurnCommand(req) {
15509
16044
  }
15510
16045
  };
15511
16046
  }
15512
- var import_node_fs38, import_node_module2, import_node_path41, import_node_url2, import_meta3;
16047
+ var import_node_fs38, import_node_module2, import_node_path41, import_node_url2, import_meta5;
15513
16048
  var init_claude_host = __esm({
15514
16049
  "src/agents/claude-host.ts"() {
15515
16050
  "use strict";
@@ -15521,7 +16056,7 @@ var init_claude_host = __esm({
15521
16056
  init_pilot_tools();
15522
16057
  init_node_launch();
15523
16058
  init_packaged_runtime();
15524
- import_meta3 = {};
16059
+ import_meta5 = {};
15525
16060
  }
15526
16061
  });
15527
16062
 
@@ -15924,16 +16459,15 @@ function parseIssuesJson(raw) {
15924
16459
  }
15925
16460
  return [];
15926
16461
  }
15927
- var import_node_fs39, import_node_os16, CLAUDE_PROMPT_ARG_MAX, claudeAdapter;
16462
+ var import_node_fs39, CLAUDE_PROMPT_ARG_MAX, claudeAdapter;
15928
16463
  var init_claude = __esm({
15929
16464
  "src/agents/claude.ts"() {
15930
16465
  "use strict";
15931
16466
  import_node_fs39 = require("fs");
15932
- import_node_os16 = require("os");
15933
16467
  init_run();
15934
16468
  init_app_settings();
15935
16469
  init_claude_mcp();
15936
- init_orch_mcp_isolation();
16470
+ init_host();
15937
16471
  init_error_detail();
15938
16472
  init_message_parts();
15939
16473
  init_injected_mcp();
@@ -16010,7 +16544,7 @@ var init_claude = __esm({
16010
16544
  });
16011
16545
  const injectedBrightsyNames = injectedServers.filter((s) => s.name === "brightsy" || s.name.startsWith("brightsy_")).map((s) => s.name);
16012
16546
  const chromeOn = claudeChromeEnabled();
16013
- const userMcpEntries = isOrchestrator ? {} : listUserClaudeMcpServerEntries((0, import_node_os16.homedir)(), [thread.repoPath, thread.worktreePath]);
16547
+ const userMcpEntries = await proxyClaudeUserMcp(isOrchestrator, [thread.repoPath, thread.worktreePath]);
16014
16548
  let allowedTools;
16015
16549
  if (isOrchestrator) {
16016
16550
  allowedTools = [
@@ -16312,7 +16846,7 @@ function unwrapCodexMcpResult(result) {
16312
16846
  return String(result);
16313
16847
  }
16314
16848
  }
16315
- function asRecord4(value) {
16849
+ function asRecord5(value) {
16316
16850
  if (value && typeof value === "object" && !Array.isArray(value)) {
16317
16851
  return value;
16318
16852
  }
@@ -16492,7 +17026,7 @@ var init_codex = __esm({
16492
17026
  }
16493
17027
  if (itemType === "mcp_tool_call" && item.id && item.server && item.tool) {
16494
17028
  const name = `mcp__${item.server}__${item.tool}`;
16495
- const input = asRecord4(item.arguments);
17029
+ const input = asRecord5(item.arguments);
16496
17030
  const events = [
16497
17031
  { type: "tool_use", id: item.id, name, input }
16498
17032
  ];
@@ -16639,7 +17173,7 @@ function thisModuleFile() {
16639
17173
  const cjsDir = typeof __dirname !== "undefined" ? __dirname : "";
16640
17174
  if (cjsDir) return (0, import_node_path43.join)(cjsDir, "cursor-sdk-resolve.js");
16641
17175
  try {
16642
- return (0, import_node_url3.fileURLToPath)(import_meta4.url);
17176
+ return (0, import_node_url3.fileURLToPath)(import_meta6.url);
16643
17177
  } catch {
16644
17178
  return (0, import_node_path43.join)(process.cwd(), "package.json");
16645
17179
  }
@@ -16738,7 +17272,7 @@ function cursorSdkRipgrepCandidate(opts) {
16738
17272
  const nested = (0, import_node_path43.join)(root, "node_modules", pkg, "bin", bin);
16739
17273
  return (0, import_node_fs41.existsSync)(nested) ? nested : null;
16740
17274
  }
16741
- var import_node_fs41, import_node_module3, import_node_path43, import_node_url3, import_meta4, CURSOR_SDK_INSTALL_HINT;
17275
+ var import_node_fs41, import_node_module3, import_node_path43, import_node_url3, import_meta6, CURSOR_SDK_INSTALL_HINT;
16742
17276
  var init_cursor_sdk_resolve = __esm({
16743
17277
  "src/agents/cursor-sdk-resolve.ts"() {
16744
17278
  "use strict";
@@ -16747,7 +17281,7 @@ var init_cursor_sdk_resolve = __esm({
16747
17281
  import_node_path43 = require("path");
16748
17282
  import_node_url3 = require("url");
16749
17283
  init_path();
16750
- import_meta4 = {};
17284
+ import_meta6 = {};
16751
17285
  CURSOR_SDK_INSTALL_HINT = "Cursor SDK is not installed. Settings \u2192 Agents \u2192 Cursor \u2192 Install (`npm i -g @cursor/sdk`). Sideboard does not ship the SDK \u2014 update it anytime without a new Sideboard build.";
16752
17286
  }
16753
17287
  });
@@ -16797,20 +17331,20 @@ function turnCostUsdFromCursorUsage(before, after) {
16797
17331
  if (!(delta >= 0) || !Number.isFinite(delta)) return void 0;
16798
17332
  return delta / 100;
16799
17333
  }
16800
- function asRecord5(value) {
17334
+ function asRecord6(value) {
16801
17335
  if (value && typeof value === "object" && !Array.isArray(value)) {
16802
17336
  return value;
16803
17337
  }
16804
17338
  return void 0;
16805
17339
  }
16806
17340
  function normalizeCursorToolCall(name, args) {
16807
- const raw = asRecord5(args);
17341
+ const raw = asRecord6(args);
16808
17342
  const toolName = typeof raw?.toolName === "string" && raw.toolName.trim() ? raw.toolName.trim() : null;
16809
- const looksLikeMcp = name === "mcp" || toolName != null && (typeof raw?.providerIdentifier === "string" || asRecord5(raw?.args) != null);
17343
+ const looksLikeMcp = name === "mcp" || toolName != null && (typeof raw?.providerIdentifier === "string" || asRecord6(raw?.args) != null);
16810
17344
  if (looksLikeMcp && toolName) {
16811
17345
  const providerRaw = typeof raw.providerIdentifier === "string" && raw.providerIdentifier.trim() ? raw.providerIdentifier.trim() : "sideboard";
16812
17346
  const provider = providerRaw.replace(/[^a-zA-Z0-9_-]/g, "_");
16813
- const nested = asRecord5(raw.args);
17347
+ const nested = asRecord6(raw.args);
16814
17348
  return {
16815
17349
  name: `mcp__${provider}__${toolName}`,
16816
17350
  input: nested ?? { toolName }
@@ -16821,7 +17355,7 @@ function normalizeCursorToolCall(name, args) {
16821
17355
  function unwrapCursorToolResult(result) {
16822
17356
  if (result == null) return void 0;
16823
17357
  if (typeof result === "string") return result;
16824
- const rec = asRecord5(result);
17358
+ const rec = asRecord6(result);
16825
17359
  if (!rec) {
16826
17360
  try {
16827
17361
  return JSON.stringify(result);
@@ -16832,18 +17366,18 @@ function unwrapCursorToolResult(result) {
16832
17366
  const collectTexts = (items) => {
16833
17367
  const texts = [];
16834
17368
  for (const item of items) {
16835
- const row2 = asRecord5(item);
17369
+ const row2 = asRecord6(item);
16836
17370
  if (!row2) continue;
16837
17371
  if (typeof row2.text === "string") {
16838
17372
  texts.push(row2.text);
16839
17373
  continue;
16840
17374
  }
16841
- const nested = asRecord5(row2.text);
17375
+ const nested = asRecord6(row2.text);
16842
17376
  if (typeof nested?.text === "string") texts.push(nested.text);
16843
17377
  }
16844
17378
  return texts;
16845
17379
  };
16846
- const value = asRecord5(rec.value);
17380
+ const value = asRecord6(rec.value);
16847
17381
  if (value && Array.isArray(value.content)) {
16848
17382
  const texts = collectTexts(value.content);
16849
17383
  if (texts.length) return texts.join("\n");
@@ -16860,10 +17394,10 @@ function unwrapCursorToolResult(result) {
16860
17394
  }
16861
17395
  function cursorToolResultIsError(status, result) {
16862
17396
  if (status === "error") return true;
16863
- const rec = asRecord5(result);
17397
+ const rec = asRecord6(result);
16864
17398
  if (!rec) return false;
16865
17399
  if (rec.status === "error") return true;
16866
- const value = asRecord5(rec.value);
17400
+ const value = asRecord6(rec.value);
16867
17401
  return value?.isError === true;
16868
17402
  }
16869
17403
  function cursorSdkMessageToEvents(msg) {
@@ -17082,7 +17616,7 @@ function entryDir2() {
17082
17616
  const cjsDir = typeof __dirname !== "undefined" ? __dirname : "";
17083
17617
  if (cjsDir) return cjsDir;
17084
17618
  try {
17085
- return (0, import_node_path45.dirname)((0, import_node_url4.fileURLToPath)(import_meta5.url));
17619
+ return (0, import_node_path45.dirname)((0, import_node_url4.fileURLToPath)(import_meta7.url));
17086
17620
  } catch {
17087
17621
  try {
17088
17622
  const req = (0, import_node_module5.createRequire)(process.cwd() + "/");
@@ -17111,7 +17645,7 @@ function cursorRunnerPath() {
17111
17645
  }
17112
17646
  return candidates[0];
17113
17647
  }
17114
- var import_node_fs43, import_node_module5, import_node_path45, import_node_url4, import_meta5, FALLBACK_CURSOR_MODELS, cachedModels, MODEL_CACHE_MS, cursorAdapter;
17648
+ var import_node_fs43, import_node_module5, import_node_path45, import_node_url4, import_meta7, FALLBACK_CURSOR_MODELS, cachedModels, MODEL_CACHE_MS, cursorAdapter;
17115
17649
  var init_cursor = __esm({
17116
17650
  "src/agents/cursor.ts"() {
17117
17651
  "use strict";
@@ -17131,7 +17665,7 @@ var init_cursor = __esm({
17131
17665
  init_packaged_runtime();
17132
17666
  init_turn_input();
17133
17667
  init_cursor_events();
17134
- import_meta5 = {};
17668
+ import_meta7 = {};
17135
17669
  FALLBACK_CURSOR_MODELS = [
17136
17670
  { id: "default", displayName: "Auto" },
17137
17671
  { id: "composer-2.5", displayName: "Composer 2.5" },
@@ -17405,7 +17939,7 @@ var init_opencode_host = __esm({
17405
17939
  });
17406
17940
 
17407
17941
  // src/agents/opencode.ts
17408
- function asRecord6(value) {
17942
+ function asRecord7(value) {
17409
17943
  if (value && typeof value === "object" && !Array.isArray(value)) {
17410
17944
  return value;
17411
17945
  }
@@ -17601,7 +18135,7 @@ var init_opencode = __esm({
17601
18135
  const name = part?.tool ?? part?.name ?? obj.tool ?? obj.name ?? "tool";
17602
18136
  const state = part?.state;
17603
18137
  const input = (state?.input && typeof state.input === "object" ? state.input : void 0) ?? part?.input ?? obj.input;
17604
- const metadata = asRecord6(state?.metadata);
18138
+ const metadata = asRecord7(state?.metadata);
17605
18139
  const id = opencodeToolId(
17606
18140
  name,
17607
18141
  part?.callID ?? part?.id ?? obj.id,
@@ -17636,7 +18170,7 @@ var init_opencode = __esm({
17636
18170
  }
17637
18171
  if (obj.type === "subtask_event") {
17638
18172
  const parentId = str4(obj.childSessionID) ?? str4(obj.childSessionId);
17639
- const part = asRecord6(obj.part);
18173
+ const part = asRecord7(obj.part);
17640
18174
  if (!parentId || !part) return null;
17641
18175
  if (part.type === "text" && str4(part.text)) {
17642
18176
  return withTaskParent(
@@ -17647,8 +18181,8 @@ var init_opencode = __esm({
17647
18181
  if (part.type === "tool" || str4(part.tool)) {
17648
18182
  const name = str4(part.tool) ?? str4(part.name) ?? "tool";
17649
18183
  const id = str4(part.callID) ?? str4(part.id) ?? `${parentId}-${name}`;
17650
- const state = asRecord6(part.state);
17651
- const input = asRecord6(state?.input) ?? asRecord6(part.input);
18184
+ const state = asRecord7(part.state);
18185
+ const input = asRecord7(state?.input) ?? asRecord7(part.input);
17652
18186
  const nested = [
17653
18187
  withEventParentId({ type: "tool_use", id, name, input }, parentId)
17654
18188
  ];
@@ -20066,7 +20600,7 @@ function forkMessageSlice(from, throughIndex) {
20066
20600
  function buildForkTranscriptAttachment(baseTitle, messages) {
20067
20601
  const title = baseTitle || "Chat";
20068
20602
  return {
20069
- id: (0, import_node_crypto11.randomUUID)(),
20603
+ id: (0, import_node_crypto13.randomUUID)(),
20070
20604
  name: `Transcript of ${title}.md`,
20071
20605
  kind: "transcript",
20072
20606
  content: formatTranscriptMarkdown(title, messages)
@@ -20125,11 +20659,11 @@ function forkChatTab(input) {
20125
20659
  }
20126
20660
  return tab;
20127
20661
  }
20128
- var import_node_crypto11;
20662
+ var import_node_crypto13;
20129
20663
  var init_chat_tabs = __esm({
20130
20664
  "src/threads/chat-tabs.ts"() {
20131
20665
  "use strict";
20132
- import_node_crypto11 = require("crypto");
20666
+ import_node_crypto13 = require("crypto");
20133
20667
  init_context_compact();
20134
20668
  init_teams();
20135
20669
  init_worktree_labels();
@@ -20428,7 +20962,7 @@ function buildReviewRequestAttachment(content, opts) {
20428
20962
  const path2 = opts?.path ?? REVIEW_SKILL_PATH;
20429
20963
  const name = opts?.name ?? (path2 === REVIEW_SKILL_PATH ? REVIEW_SKILL_NAME : path2 === REPO_REVIEW_PATH || path2 === CONTEXT_REVIEW_PATH ? REPO_REVIEW_NAME : REVIEW_REQUEST_NAME);
20430
20964
  return {
20431
- id: (0, import_node_crypto12.randomUUID)(),
20965
+ id: (0, import_node_crypto14.randomUUID)(),
20432
20966
  name,
20433
20967
  kind: "file",
20434
20968
  path: path2,
@@ -20484,11 +21018,11 @@ async function requestReview(threadRef, send3) {
20484
21018
  const started = await send3(tab.id, REVIEW_REQUEST_PREFILL);
20485
21019
  return { tab: started, from };
20486
21020
  }
20487
- var import_node_crypto12, import_node_fs49, import_node_path50, REPO_REVIEW_PATH, REPO_REVIEW_NAME, CONTEXT_REVIEW_PATH, REVIEW_REQUEST_PATH, LEGACY_REVIEW_REQUEST_PATH, REVIEW_REQUEST_NAME, REVIEW_REQUEST_PREFILL, LEGACY_REVIEW_TEMPLATE_MARKERS;
21021
+ var import_node_crypto14, import_node_fs49, import_node_path50, REPO_REVIEW_PATH, REPO_REVIEW_NAME, CONTEXT_REVIEW_PATH, REVIEW_REQUEST_PATH, LEGACY_REVIEW_REQUEST_PATH, REVIEW_REQUEST_NAME, REVIEW_REQUEST_PREFILL, LEGACY_REVIEW_TEMPLATE_MARKERS;
20488
21022
  var init_request_review = __esm({
20489
21023
  "src/review/request-review.ts"() {
20490
21024
  "use strict";
20491
- import_node_crypto12 = require("crypto");
21025
+ import_node_crypto14 = require("crypto");
20492
21026
  import_node_fs49 = require("fs");
20493
21027
  import_node_path50 = require("path");
20494
21028
  init_global_workspace();
@@ -22037,8 +22571,28 @@ var init_clone_repo = __esm({
22037
22571
  }
22038
22572
  });
22039
22573
 
22574
+ // src/mcp-ui/model-context.ts
22575
+ function stashMcpAppModelContext(threadId, text7) {
22576
+ const body = text7.trim().slice(0, 8e3);
22577
+ if (!body) return;
22578
+ updateThread(threadId, { mcpAppModelContext: body });
22579
+ }
22580
+ function takeMcpAppModelContext(threadId) {
22581
+ const thread = readThread(threadId);
22582
+ const text7 = thread?.mcpAppModelContext?.trim();
22583
+ if (!text7) return void 0;
22584
+ updateThread(threadId, { mcpAppModelContext: null });
22585
+ return text7;
22586
+ }
22587
+ var init_model_context = __esm({
22588
+ "src/mcp-ui/model-context.ts"() {
22589
+ "use strict";
22590
+ init_thread_store();
22591
+ }
22592
+ });
22593
+
22040
22594
  // src/plan/plan-present.ts
22041
- function asRecord7(v) {
22595
+ function asRecord8(v) {
22042
22596
  return v != null && typeof v === "object" && !Array.isArray(v) ? v : null;
22043
22597
  }
22044
22598
  function isPresentPlanToolName(name) {
@@ -22057,7 +22611,7 @@ function extractPresentedPlan(parts) {
22057
22611
  for (let i = parts.length - 1; i >= 0; i--) {
22058
22612
  const p = parts[i];
22059
22613
  if (p.type !== "tool" || !isPresentPlanToolName(p.name)) continue;
22060
- const input = asRecord7(p.input) ?? {};
22614
+ const input = asRecord8(p.input) ?? {};
22061
22615
  const content = typeof input.content === "string" ? input.content : typeof input.plan === "string" ? input.plan : typeof input.markdown === "string" ? input.markdown : "";
22062
22616
  if (!content.trim()) continue;
22063
22617
  const title = typeof input.title === "string" && input.title.trim() ? input.title.trim() : "Plan";
@@ -22259,6 +22813,7 @@ function decisionBlockFromParts(parts, planMode, at = (/* @__PURE__ */ new Date(
22259
22813
  const reason = pending ? formatAskUserNotifyMessage(pending.questions) : "Waiting for an answer in that chat.";
22260
22814
  return {
22261
22815
  ...makeAgentBlock("ask_user", reason, at),
22816
+ onScreen: true,
22262
22817
  ...pending ? { questionSignature: pending.signature, questions: pending.questions } : {}
22263
22818
  };
22264
22819
  }
@@ -22316,6 +22871,38 @@ function dismissAskUserQuestion(threadId, signature) {
22316
22871
  ...clearBlock ? { agentBlock: null } : {}
22317
22872
  });
22318
22873
  }
22874
+ function askBlocksEqual(a, b) {
22875
+ if (a === b) return true;
22876
+ if (!a || !b) return false;
22877
+ return a.source === b.source && a.reason === b.reason && a.at === b.at && a.onScreen === b.onScreen && a.questionSignature === b.questionSignature;
22878
+ }
22879
+ function askBlockAfterLiveParts(existing, parts) {
22880
+ const last = lastTopLevelTool(parts);
22881
+ if (last?.type === "tool" && isAskUserToolName(last.name)) {
22882
+ if (existing?.source === "ask_user" && existing.onScreen) return existing;
22883
+ const pending = extractPendingPlanQuestions(parts);
22884
+ const questions2 = pending?.questions ?? existing?.questions;
22885
+ if (!questions2?.length) {
22886
+ return existing?.source === "ask_user" ? { ...existing, onScreen: true } : existing ?? null;
22887
+ }
22888
+ const at = existing?.source === "ask_user" ? existing.at : void 0;
22889
+ return {
22890
+ ...makeAgentBlock("ask_user", formatAskUserNotifyMessage(questions2), at),
22891
+ onScreen: true,
22892
+ questionSignature: pending?.signature ?? existing?.questionSignature,
22893
+ questions: questions2
22894
+ };
22895
+ }
22896
+ if (last && existing?.source === "ask_user") return null;
22897
+ return existing ?? null;
22898
+ }
22899
+ function syncAskUserBlockFromLive(threadId, parts) {
22900
+ const thread = readThread(threadId);
22901
+ if (!thread || thread.status === "archived") return;
22902
+ const next = askBlockAfterLiveParts(thread.agentBlock, parts);
22903
+ if (askBlocksEqual(thread.agentBlock, next)) return;
22904
+ updateThread(threadId, { agentBlock: next });
22905
+ }
22319
22906
  function writeAgentBlock(threadId, block) {
22320
22907
  const thread = readThread(threadId);
22321
22908
  if (!thread || thread.status === "archived") return;
@@ -22479,7 +23066,7 @@ function isUnclaimedSteerRequest(req) {
22479
23066
  }
22480
23067
  function nextSteerRequest(existing) {
22481
23068
  if (existing?.requestId && !existing.claimedAt) return existing;
22482
- return { requestId: (0, import_node_crypto13.randomUUID)(), requestedAt: (/* @__PURE__ */ new Date()).toISOString() };
23069
+ return { requestId: (0, import_node_crypto15.randomUUID)(), requestedAt: (/* @__PURE__ */ new Date()).toISOString() };
22483
23070
  }
22484
23071
  function claimSteerRequest(threadId) {
22485
23072
  const pending = readThread(threadId)?.steerRequest;
@@ -22488,11 +23075,11 @@ function claimSteerRequest(threadId) {
22488
23075
  steerRequest: { ...pending, claimedAt: (/* @__PURE__ */ new Date()).toISOString() }
22489
23076
  });
22490
23077
  }
22491
- var import_node_crypto13;
23078
+ var import_node_crypto15;
22492
23079
  var init_steer_request = __esm({
22493
23080
  "src/orchestrator/steer-request.ts"() {
22494
23081
  "use strict";
22495
- import_node_crypto13 = require("crypto");
23082
+ import_node_crypto15 = require("crypto");
22496
23083
  init_thread_store();
22497
23084
  }
22498
23085
  });
@@ -22737,8 +23324,8 @@ function resolveAbleTimeOAuthHost(requested, saved) {
22737
23324
  return fromSaved || void 0;
22738
23325
  }
22739
23326
  function createAbleTimePkce() {
22740
- const verifier = (0, import_node_crypto14.randomBytes)(32).toString("base64url");
22741
- const challenge = (0, import_node_crypto14.createHash)("sha256").update(verifier).digest("base64url");
23327
+ const verifier = (0, import_node_crypto16.randomBytes)(32).toString("base64url");
23328
+ const challenge = (0, import_node_crypto16.createHash)("sha256").update(verifier).digest("base64url");
22742
23329
  return { verifier, challenge };
22743
23330
  }
22744
23331
  function ableTimeOAuthAuthorizeUrl(clientId, state, codeChallenge, host) {
@@ -22843,7 +23430,7 @@ async function startAbleTimeOAuth(opts) {
22843
23430
  opts?.host,
22844
23431
  loadAppSettings().integrations.abletimeHost
22845
23432
  );
22846
- const state = (0, import_node_crypto14.randomBytes)(16).toString("hex");
23433
+ const state = (0, import_node_crypto16.randomBytes)(16).toString("hex");
22847
23434
  const pkce = createAbleTimePkce();
22848
23435
  const authorizeUrl = ableTimeOAuthAuthorizeUrl(clientId, state, pkce.challenge, host);
22849
23436
  const timeoutMs = opts?.timeoutMs ?? 5 * 6e4;
@@ -22856,7 +23443,7 @@ async function startAbleTimeOAuth(opts) {
22856
23443
  if (err) reject(err);
22857
23444
  else resolve3(value);
22858
23445
  };
22859
- const server = (0, import_node_http.createServer)((req, res) => {
23446
+ const server = (0, import_node_http2.createServer)((req, res) => {
22860
23447
  try {
22861
23448
  const url = new URL(req.url || "/", `http://127.0.0.1:${ABLETIME_OAUTH_PORT}`);
22862
23449
  if (url.pathname !== "/callback") {
@@ -22943,12 +23530,12 @@ async function startAbleTimeOAuth(opts) {
22943
23530
  return loadAppSettings();
22944
23531
  }
22945
23532
  }
22946
- var import_node_crypto14, import_node_http, ABLETIME_OAUTH_CALLBACK_PATH, ABLETIME_OAUTH_PORT, ABLETIME_OAUTH_LOCAL_CALLBACK, ABLETIME_OAUTH_REDIRECT, BOUNCE_QUERY_KEYS, BAKED_ABLETIME_OAUTH_CLIENT_ID, ABLETIME_OAUTH_RESOURCE, REFRESH_SKEW_MS2, refreshInFlight2, ABLETIME_OAUTH_CANCELLED, AbleTimeOAuthCancelledError;
23533
+ var import_node_crypto16, import_node_http2, ABLETIME_OAUTH_CALLBACK_PATH, ABLETIME_OAUTH_PORT, ABLETIME_OAUTH_LOCAL_CALLBACK, ABLETIME_OAUTH_REDIRECT, BOUNCE_QUERY_KEYS, BAKED_ABLETIME_OAUTH_CLIENT_ID, ABLETIME_OAUTH_RESOURCE, REFRESH_SKEW_MS2, refreshInFlight2, ABLETIME_OAUTH_CANCELLED, AbleTimeOAuthCancelledError;
22947
23534
  var init_abletime_oauth = __esm({
22948
23535
  "src/integrations/abletime-oauth.ts"() {
22949
23536
  "use strict";
22950
- import_node_crypto14 = require("crypto");
22951
- import_node_http = require("http");
23537
+ import_node_crypto16 = require("crypto");
23538
+ import_node_http2 = require("http");
22952
23539
  init_fetch();
22953
23540
  init_app_settings();
22954
23541
  init_abletime_mcp();
@@ -22981,7 +23568,7 @@ __export(abletime_rest_exports, {
22981
23568
  looksLikeAbleTimeUlid: () => looksLikeAbleTimeUlid,
22982
23569
  textFromAbleTimeDoc: () => textFromAbleTimeDoc
22983
23570
  });
22984
- function asRecord8(value) {
23571
+ function asRecord9(value) {
22985
23572
  return value && typeof value === "object" && !Array.isArray(value) ? value : null;
22986
23573
  }
22987
23574
  function asString(value) {
@@ -22989,7 +23576,7 @@ function asString(value) {
22989
23576
  }
22990
23577
  function asList(value) {
22991
23578
  if (Array.isArray(value)) return value;
22992
- const record = asRecord8(value);
23579
+ const record = asRecord9(value);
22993
23580
  if (!record) return [];
22994
23581
  for (const key of ["data", "tasks", "projects", "users", "items", "results"]) {
22995
23582
  if (Array.isArray(record[key])) return record[key];
@@ -23006,12 +23593,12 @@ function ableTimeDocFromText(text7) {
23006
23593
  }
23007
23594
  function textFromAbleTimeDoc(value) {
23008
23595
  if (typeof value === "string") return value.trim();
23009
- const record = asRecord8(value);
23596
+ const record = asRecord9(value);
23010
23597
  if (!record) return "";
23011
23598
  if (typeof record.text === "string" && record.text.trim()) return record.text.trim();
23012
23599
  const chunks = [];
23013
23600
  const walk = (node) => {
23014
- const rec = asRecord8(node);
23601
+ const rec = asRecord9(node);
23015
23602
  if (!rec) return;
23016
23603
  if (typeof rec.text === "string" && rec.text) chunks.push(rec.text);
23017
23604
  if (Array.isArray(rec.content)) rec.content.forEach(walk);
@@ -23073,7 +23660,7 @@ async function restPages(path2, opts, maxPages = 20) {
23073
23660
  query: { ...opts.query, ...cursor ? { cursor } : {} }
23074
23661
  });
23075
23662
  items.push(...asList(raw));
23076
- const page = asRecord8(asRecord8(raw)?.page);
23663
+ const page = asRecord9(asRecord9(raw)?.page);
23077
23664
  const next = page ? asString(page.nextCursor) : "";
23078
23665
  if (!next) break;
23079
23666
  cursor = next;
@@ -23081,7 +23668,7 @@ async function restPages(path2, opts, maxPages = 20) {
23081
23668
  return items;
23082
23669
  }
23083
23670
  function userDisplayName(raw) {
23084
- const rec = asRecord8(raw);
23671
+ const rec = asRecord9(raw);
23085
23672
  if (!rec) return null;
23086
23673
  const id = asString(rec.userId) || asString(rec.id);
23087
23674
  const name = [asString(rec.firstName), asString(rec.lastName)].filter(Boolean).join(" ") || asString(rec.username) || asString(rec.email) || asString(rec.name);
@@ -23089,7 +23676,7 @@ function userDisplayName(raw) {
23089
23676
  return { id: id || void 0, name };
23090
23677
  }
23091
23678
  function restTaskToRaw(raw, users) {
23092
- const rec = asRecord8(raw);
23679
+ const rec = asRecord9(raw);
23093
23680
  if (!rec) return null;
23094
23681
  const id = asString(rec.timeflowTaskId) || asString(rec.taskId) || asString(rec.id);
23095
23682
  const identifier = asString(rec.taskRef) || asString(rec.reference) || id;
@@ -23097,7 +23684,7 @@ function restTaskToRaw(raw, users) {
23097
23684
  if (!id && !identifier && !title) return null;
23098
23685
  const assignee = users.get(asString(rec.assignedUserId));
23099
23686
  const comments = asList(rec.comments).map((item) => {
23100
- const comment = asRecord8(item) ?? {};
23687
+ const comment = asRecord9(item) ?? {};
23101
23688
  const user = userDisplayName(comment);
23102
23689
  return {
23103
23690
  id: asString(comment.commentId) || asString(comment.id),
@@ -23127,13 +23714,13 @@ function restTaskToRaw(raw, users) {
23127
23714
  };
23128
23715
  }
23129
23716
  function restProjectToRaw(raw) {
23130
- const rec = asRecord8(raw);
23717
+ const rec = asRecord9(raw);
23131
23718
  if (!rec) return null;
23132
23719
  const id = asString(rec.projectId) || asString(rec.id);
23133
23720
  const name = asString(rec.projectName) || asString(rec.name);
23134
23721
  if (!id && !name) return null;
23135
23722
  const categories = asList(rec.categories).map((item) => {
23136
- const cat = asRecord8(item) ?? {};
23723
+ const cat = asRecord9(item) ?? {};
23137
23724
  return {
23138
23725
  id: asString(cat.projectCategoryId) || asString(cat.categoryId) || asString(cat.id),
23139
23726
  name: asString(cat.categoryName) || asString(cat.name)
@@ -23145,7 +23732,7 @@ async function listUsers(opts) {
23145
23732
  const users = /* @__PURE__ */ new Map();
23146
23733
  for (const item of await restPages("/users", opts).catch(() => [])) {
23147
23734
  const user = userDisplayName(item);
23148
- const rec = asRecord8(item);
23735
+ const rec = asRecord9(item);
23149
23736
  const id = user?.id || (rec ? asString(rec.userId) : "");
23150
23737
  if (user && id) users.set(id, user);
23151
23738
  }
@@ -23271,10 +23858,10 @@ async function callAbleTimeRestTool(name, args = {}, opts) {
23271
23858
  if (!project) throw new Error("AbleTime has no projects to create a task in");
23272
23859
  const categories = asList(project.categories);
23273
23860
  const wantedCategory = firstStringArg(args, ["category_id", "categoryId", "category"]);
23274
- const category = categories.map((item) => asRecord8(item)).find((item) => {
23861
+ const category = categories.map((item) => asRecord9(item)).find((item) => {
23275
23862
  if (!item || !wantedCategory) return false;
23276
23863
  return asString(item.id).toLowerCase() === wantedCategory.toLowerCase() || asString(item.name).toLowerCase() === wantedCategory.toLowerCase();
23277
- }) ?? asRecord8(categories[0]);
23864
+ }) ?? asRecord9(categories[0]);
23278
23865
  const parentArg = firstStringArg(args, ["parent", "parent_id", "parentId", "related_task_id"]);
23279
23866
  const parentTaskId = parentArg ? await resolveRestParentTaskId(parentArg, requestOpts) : void 0;
23280
23867
  const created = await abletimeRestRequest("/tasks", {
@@ -23288,7 +23875,7 @@ async function callAbleTimeRestTool(name, args = {}, opts) {
23288
23875
  }
23289
23876
  });
23290
23877
  const state = firstStringArg(args, ["state"]);
23291
- const createdId = asString(asRecord8(created)?.timeflowTaskId);
23878
+ const createdId = asString(asRecord9(created)?.timeflowTaskId);
23292
23879
  const description = asString(args.description);
23293
23880
  if (createdId && description) {
23294
23881
  await abletimeRestRequest(`/tasks/${encodeURIComponent(createdId)}`, {
@@ -23361,7 +23948,7 @@ async function callAbleTimeRestTool(name, args = {}, opts) {
23361
23948
  method: "POST",
23362
23949
  body: { content: ableTimeDocFromText(body) }
23363
23950
  });
23364
- const rec = asRecord8(created) ?? {};
23951
+ const rec = asRecord9(created) ?? {};
23365
23952
  return {
23366
23953
  id: asString(rec.commentId) || void 0,
23367
23954
  body: textFromAbleTimeDoc(rec.content) || body
@@ -23456,7 +24043,7 @@ function rewriteAbleTimeError(message) {
23456
24043
  }
23457
24044
  return message;
23458
24045
  }
23459
- function asRecord9(value) {
24046
+ function asRecord10(value) {
23460
24047
  return value && typeof value === "object" && !Array.isArray(value) ? value : null;
23461
24048
  }
23462
24049
  function parseSseJson(body) {
@@ -23478,12 +24065,12 @@ function parseSseJson(body) {
23478
24065
  }
23479
24066
  }
23480
24067
  function unwrapToolResult(result) {
23481
- const record = asRecord9(result);
24068
+ const record = asRecord10(result);
23482
24069
  if (!record) return result;
23483
24070
  const content = record.content;
23484
24071
  if (Array.isArray(content)) {
23485
24072
  const texts = content.map((part) => {
23486
- const item = asRecord9(part);
24073
+ const item = asRecord10(part);
23487
24074
  if (!item) return "";
23488
24075
  return typeof item.text === "string" ? item.text : "";
23489
24076
  }).filter(Boolean);
@@ -23505,7 +24092,7 @@ function unwrapToolResult(result) {
23505
24092
  return result;
23506
24093
  }
23507
24094
  function textsFromUnknown(value) {
23508
- const record = asRecord9(value);
24095
+ const record = asRecord10(value);
23509
24096
  if (!record) return "";
23510
24097
  if (typeof record.message === "string") return record.message;
23511
24098
  if (typeof record.error === "string") return record.error;
@@ -23552,7 +24139,7 @@ async function abletimeMcpRequest(method, params, opts) {
23552
24139
  return parseSseJson(body);
23553
24140
  }
23554
24141
  })();
23555
- const rpc = asRecord9(parsed);
24142
+ const rpc = asRecord10(parsed);
23556
24143
  if (rpc?.error) {
23557
24144
  const detail = typeof rpc.error.message === "string" && rpc.error.message.trim() ? rpc.error.message : `AbleTime MCP error ${rpc.error.code ?? ""}`.trim();
23558
24145
  throw new Error(rewriteAbleTimeError(detail));
@@ -23707,7 +24294,7 @@ function uniqueAttachmentFileName(dir, originalName) {
23707
24294
  const candidate = `${stem}-${i}${ext}`;
23708
24295
  if (!(0, import_node_fs55.existsSync)((0, import_node_path56.join)(dir, candidate))) return candidate;
23709
24296
  }
23710
- return `${stem}-${(0, import_node_crypto15.randomUUID)()}${ext}`;
24297
+ return `${stem}-${(0, import_node_crypto17.randomUUID)()}${ext}`;
23711
24298
  }
23712
24299
  function extractHttpUrls(markdown) {
23713
24300
  const text7 = markdown ?? "";
@@ -23813,13 +24400,13 @@ async function downloadAuthenticatedFile(opts) {
23813
24400
  ...contentType ? { contentType } : {}
23814
24401
  };
23815
24402
  }
23816
- var import_node_fs55, import_node_path56, import_node_crypto15, ISSUE_ATTACHMENT_MAX_BYTES, MARKDOWN_IMAGE_RE, MARKDOWN_LINK_RE, HTML_SRC_RE, BARE_URL_RE, EXT_BY_MIME;
24403
+ var import_node_fs55, import_node_path56, import_node_crypto17, ISSUE_ATTACHMENT_MAX_BYTES, MARKDOWN_IMAGE_RE, MARKDOWN_LINK_RE, HTML_SRC_RE, BARE_URL_RE, EXT_BY_MIME;
23817
24404
  var init_issue_attachments = __esm({
23818
24405
  "src/integrations/issue-attachments.ts"() {
23819
24406
  "use strict";
23820
24407
  import_node_fs55 = require("fs");
23821
24408
  import_node_path56 = require("path");
23822
- import_node_crypto15 = require("crypto");
24409
+ import_node_crypto17 = require("crypto");
23823
24410
  init_fetch();
23824
24411
  init_workspace_scratch();
23825
24412
  ISSUE_ATTACHMENT_MAX_BYTES = 25 * 1024 * 1024;
@@ -23844,7 +24431,7 @@ var init_issue_attachments = __esm({
23844
24431
  });
23845
24432
 
23846
24433
  // src/integrations/abletime-attachments.ts
23847
- function asRecord10(value) {
24434
+ function asRecord11(value) {
23848
24435
  return value && typeof value === "object" && !Array.isArray(value) ? value : null;
23849
24436
  }
23850
24437
  function asString2(value) {
@@ -23852,7 +24439,7 @@ function asString2(value) {
23852
24439
  }
23853
24440
  function asList2(value) {
23854
24441
  if (Array.isArray(value)) return value;
23855
- const record = asRecord10(value);
24442
+ const record = asRecord11(value);
23856
24443
  if (!record) return [];
23857
24444
  for (const key of ["data", "tasks", "projects", "items", "results", "nodes"]) {
23858
24445
  if (Array.isArray(record[key])) return record[key];
@@ -23871,9 +24458,9 @@ function filesFromAbleTimeDoc(value) {
23871
24458
  const out = [];
23872
24459
  const seen = /* @__PURE__ */ new Set();
23873
24460
  const walk = (node) => {
23874
- const rec = asRecord10(node);
24461
+ const rec = asRecord11(node);
23875
24462
  if (!rec) return;
23876
- const attrs = asRecord10(rec.attrs) ?? rec;
24463
+ const attrs = asRecord11(rec.attrs) ?? rec;
23877
24464
  const url = asString2(attrs.src) || asString2(attrs.href) || asString2(attrs.url) || asString2(attrs.fileUrl) || asString2(attrs.downloadUrl);
23878
24465
  if (url && !seen.has(url)) {
23879
24466
  seen.add(url);
@@ -23891,7 +24478,7 @@ function filesFromAbleTimeDoc(value) {
23891
24478
  function listedAbleTimeFiles(raw) {
23892
24479
  const out = [];
23893
24480
  for (const item of asList2(raw)) {
23894
- const rec = asRecord10(item);
24481
+ const rec = asRecord11(item);
23895
24482
  if (!rec) continue;
23896
24483
  const url = firstString(rec, ["url", "href", "src", "fileUrl", "downloadUrl", "permalink"]);
23897
24484
  if (!url) continue;
@@ -23911,7 +24498,7 @@ function mapAbleTimeAttachments(record) {
23911
24498
  ...filesFromAbleTimeDoc(record.description),
23912
24499
  ...filesFromAbleTimeDoc(record.content),
23913
24500
  ...asList2(record.comments).flatMap((item) => {
23914
- const rec = asRecord10(item);
24501
+ const rec = asRecord11(item);
23915
24502
  return rec ? filesFromAbleTimeDoc(rec.content ?? rec.body) : [];
23916
24503
  })
23917
24504
  ].map((file) => ({
@@ -23953,7 +24540,7 @@ async function resolveAbleTimeAttachmentUrl(id, opts) {
23953
24540
  const json = await res.json().catch(() => null);
23954
24541
  const rec = json && typeof json === "object" && !Array.isArray(json) ? json.data && typeof json.data === "object" ? json.data : json : null;
23955
24542
  if (!rec) continue;
23956
- const url = firstString(rec, ["url", "href", "src", "fileUrl", "downloadUrl"]) || firstString(asRecord10(rec.file), ["url", "href"]);
24543
+ const url = firstString(rec, ["url", "href", "src", "fileUrl", "downloadUrl"]) || firstString(asRecord11(rec.file), ["url", "href"]);
23957
24544
  if (url) {
23958
24545
  return {
23959
24546
  url,
@@ -23995,7 +24582,7 @@ var init_abletime_attachments = __esm({
23995
24582
  });
23996
24583
 
23997
24584
  // src/integrations/abletime-projects.ts
23998
- function asRecord11(value) {
24585
+ function asRecord12(value) {
23999
24586
  return value && typeof value === "object" && !Array.isArray(value) ? value : null;
24000
24587
  }
24001
24588
  function firstString2(record, keys) {
@@ -24008,7 +24595,7 @@ function firstString2(record, keys) {
24008
24595
  }
24009
24596
  function asList3(value) {
24010
24597
  if (Array.isArray(value)) return value;
24011
- const record = asRecord11(value);
24598
+ const record = asRecord12(value);
24012
24599
  if (!record) return [];
24013
24600
  for (const key of ["data", "tasks", "projects", "items", "results", "nodes"]) {
24014
24601
  if (Array.isArray(record[key])) return record[key];
@@ -24016,7 +24603,7 @@ function asList3(value) {
24016
24603
  return [];
24017
24604
  }
24018
24605
  function ableTimeProjectFields(nested) {
24019
- const projectRecord = asRecord11(nested.project);
24606
+ const projectRecord = asRecord12(nested.project);
24020
24607
  const projectId = firstString2(nested, ["project_id", "projectId"]) || firstString2(projectRecord, ["id"]) || void 0;
24021
24608
  const projectName = firstString2(nested, ["project_name", "projectName"]) || firstString2(projectRecord, ["name", "title"]) || void 0;
24022
24609
  if (!projectId && !projectName) return {};
@@ -24029,13 +24616,13 @@ function ableTimeProjectFields(nested) {
24029
24616
  };
24030
24617
  }
24031
24618
  function mapAbleTimeProject(raw) {
24032
- const record = asRecord11(raw);
24619
+ const record = asRecord12(raw);
24033
24620
  if (!record) return null;
24034
24621
  const id = firstString2(record, ["id", "project_id", "projectId"]);
24035
24622
  const name = firstString2(record, ["name", "title", "projectName"]);
24036
24623
  if (!id && !name) return null;
24037
24624
  const categories = asList3(record.categories ?? record.category).map((item) => {
24038
- const rec = asRecord11(item);
24625
+ const rec = asRecord12(item);
24039
24626
  if (!rec) return null;
24040
24627
  const categoryId = firstString2(rec, ["id", "category_id", "projectCategoryId", "categoryId"]);
24041
24628
  const categoryName = firstString2(rec, ["name", "title", "categoryName"]);
@@ -24071,7 +24658,7 @@ __export(abletime_exports, {
24071
24658
  updateAbleTimeTask: () => updateAbleTimeTask,
24072
24659
  verifyAbleTimeConnection: () => verifyAbleTimeConnection
24073
24660
  });
24074
- function asRecord12(value) {
24661
+ function asRecord13(value) {
24075
24662
  return value && typeof value === "object" && !Array.isArray(value) ? value : null;
24076
24663
  }
24077
24664
  function asString3(value) {
@@ -24088,14 +24675,14 @@ function firstString3(record, keys) {
24088
24675
  function firstRecord(record, keys) {
24089
24676
  if (!record) return null;
24090
24677
  for (const key of keys) {
24091
- const value = asRecord12(record[key]);
24678
+ const value = asRecord13(record[key]);
24092
24679
  if (value) return value;
24093
24680
  }
24094
24681
  return null;
24095
24682
  }
24096
24683
  function asList4(value) {
24097
24684
  if (Array.isArray(value)) return value;
24098
- const record = asRecord12(value);
24685
+ const record = asRecord13(value);
24099
24686
  if (!record) return [];
24100
24687
  for (const key of ["data", "tasks", "projects", "items", "results", "nodes"]) {
24101
24688
  if (Array.isArray(record[key])) return record[key];
@@ -24107,18 +24694,18 @@ function labelsOf(record) {
24107
24694
  if (!Array.isArray(raw)) return [];
24108
24695
  return raw.map((item) => {
24109
24696
  if (typeof item === "string") return item.trim();
24110
- const rec = asRecord12(item);
24697
+ const rec = asRecord13(item);
24111
24698
  return rec ? firstString3(rec, ["name", "title", "label"]) : "";
24112
24699
  }).filter(Boolean);
24113
24700
  }
24114
24701
  function commentsOf(record) {
24115
24702
  const out = [];
24116
24703
  for (const item of asList4(record.comments ?? record.notes ?? record.discussion)) {
24117
- const rec = asRecord12(item);
24704
+ const rec = asRecord13(item);
24118
24705
  if (!rec) continue;
24119
24706
  const body = firstString3(rec, ["body", "text", "comment", "message", "contentSanitized"]) || textFromAbleTimeDoc(rec.content);
24120
24707
  if (!body) continue;
24121
- const user = firstString3(asRecord12(rec.user) ?? asRecord12(rec.author), ["name", "display_name", "username"]) || firstString3(rec, ["user_name", "author", "username"]);
24708
+ const user = firstString3(asRecord13(rec.user) ?? asRecord13(rec.author), ["name", "display_name", "username"]) || firstString3(rec, ["user_name", "author", "username"]);
24122
24709
  const id = firstString3(rec, ["id", "comment_id", "commentId"]);
24123
24710
  const url = firstString3(rec, ["url", "permalink"]);
24124
24711
  const createdAt = firstString3(rec, ["created_at", "createdAt", "created"]);
@@ -24145,7 +24732,7 @@ function taskUrl(task, host) {
24145
24732
  return `${base}/tasks/${slug}`;
24146
24733
  }
24147
24734
  function mapAbleTimeTask(raw, host) {
24148
- const record = asRecord12(raw);
24735
+ const record = asRecord13(raw);
24149
24736
  if (!record) return null;
24150
24737
  const nested = firstRecord(record, ["task", "data"]) ?? record;
24151
24738
  const id = firstString3(nested, ["id", "task_id", "taskId", "timeflowTaskId"]);
@@ -24163,7 +24750,7 @@ function mapAbleTimeTask(raw, host) {
24163
24750
  description: firstString3(nested, ["description", "body", "details", "descriptionSanitized"]) || textFromAbleTimeDoc(nested.description) || void 0,
24164
24751
  state: firstString3(nested, ["state", "board_state", "boardState", "status", "taskState"]) || void 0,
24165
24752
  ...ableTimeProjectFields(nested),
24166
- categoryId: firstString3(nested, ["category_id", "categoryId", "projectCategoryId"]) || firstString3(asRecord12(nested.category), ["id"]) || void 0,
24753
+ categoryId: firstString3(nested, ["category_id", "categoryId", "projectCategoryId"]) || firstString3(asRecord13(nested.category), ["id"]) || void 0,
24167
24754
  assignee: assigneeOf(nested),
24168
24755
  labels: labelsOf(nested),
24169
24756
  comments: commentsOf(nested),
@@ -24213,7 +24800,7 @@ function isOpenTask(task) {
24213
24800
  }
24214
24801
  async function getAbleTimeOrientation(opts) {
24215
24802
  const raw = await callAbleTimeTool("orientation", {}, opts);
24216
- const record = asRecord12(raw);
24803
+ const record = asRecord13(raw);
24217
24804
  const viewerRec = firstRecord(record, ["viewer", "principal", "user", "actor", "me", "person"]) ?? record;
24218
24805
  const viewer = {
24219
24806
  id: firstString3(viewerRec, ["id", "user_id"]) || void 0,
@@ -24292,7 +24879,7 @@ async function commentAbleTimeTask(input, opts) {
24292
24879
  { id, task_id: id, task: id, body, comment: body, text: body },
24293
24880
  opts
24294
24881
  );
24295
- const rec = asRecord12(raw);
24882
+ const rec = asRecord13(raw);
24296
24883
  return {
24297
24884
  id: rec ? firstString3(rec, ["id", "comment_id"]) || void 0 : void 0,
24298
24885
  body: rec ? firstString3(rec, ["body", "text", "comment"]) || body : body
@@ -25168,6 +25755,7 @@ function noteTurnLiveEvent(threadId, event) {
25168
25755
  const prev = buffers.get(threadId) ?? { parts: [], timer: null };
25169
25756
  prev.parts = trimParts(applyAgentEvent(prev.parts, event));
25170
25757
  buffers.set(threadId, prev);
25758
+ syncAskUserBlockFromLive(threadId, prev.parts);
25171
25759
  if (event.type === "exit") {
25172
25760
  flush(threadId);
25173
25761
  const cur = buffers.get(threadId);
@@ -25224,6 +25812,7 @@ var init_turn_live = __esm({
25224
25812
  import_node_fs57 = require("fs");
25225
25813
  init_message_parts();
25226
25814
  init_paths();
25815
+ init_agent_block();
25227
25816
  buffers = /* @__PURE__ */ new Map();
25228
25817
  FLUSH_MS = 800;
25229
25818
  MAX_PARTS = 80;
@@ -25443,7 +26032,7 @@ function buildQuotaHandoffAttachment(from, limitText, fallbackAgent) {
25443
26032
  ...instructions
25444
26033
  ].join("\n");
25445
26034
  return {
25446
- id: (0, import_node_crypto16.randomUUID)(),
26035
+ id: (0, import_node_crypto18.randomUUID)(),
25447
26036
  name: orch ? "Orchestration quota handoff.md" : "Quota handoff.md",
25448
26037
  kind: "transcript",
25449
26038
  content: body
@@ -25475,11 +26064,11 @@ function createQuotaFailoverChat(from, fallbackAgent, limitText, opts) {
25475
26064
  }
25476
26065
  return updateThread(tab.id, patch);
25477
26066
  }
25478
- var import_node_crypto16, QUOTA_CONTINUE_PROMPT, QUOTA_CONTINUE_ACCOUNT_PROMPT, QUOTA_RESUME_PROMPT;
26067
+ var import_node_crypto18, QUOTA_CONTINUE_PROMPT, QUOTA_CONTINUE_ACCOUNT_PROMPT, QUOTA_RESUME_PROMPT;
25479
26068
  var init_quota_failover = __esm({
25480
26069
  "src/orchestrator/quota-failover.ts"() {
25481
26070
  "use strict";
25482
- import_node_crypto16 = require("crypto");
26071
+ import_node_crypto18 = require("crypto");
25483
26072
  init_session_quota();
25484
26073
  init_app_settings();
25485
26074
  init_managed_accounts();
@@ -27555,7 +28144,7 @@ function compiledModuleDir() {
27555
28144
  const cjsDir = typeof __dirname !== "undefined" ? __dirname : "";
27556
28145
  if (cjsDir) return cjsDir;
27557
28146
  try {
27558
- const url = import_meta6.url;
28147
+ const url = import_meta8.url;
27559
28148
  if (typeof url === "string" && url.length > 0) {
27560
28149
  return (0, import_node_path62.dirname)((0, import_node_url5.fileURLToPath)(url));
27561
28150
  }
@@ -27594,7 +28183,7 @@ function formatDetachedJobInvoke(scriptPath) {
27594
28183
  if (resolved) return `node ${JSON.stringify(resolved)}`;
27595
28184
  return "node scripts/detached-job.cjs";
27596
28185
  }
27597
- var import_node_fs63, import_node_path62, import_node_url5, import_meta6, DETACHED_JOB_FILENAMES;
28186
+ var import_node_fs63, import_node_path62, import_node_url5, import_meta8, DETACHED_JOB_FILENAMES;
27598
28187
  var init_detached_job_path = __esm({
27599
28188
  "src/skills/detached-job-path.ts"() {
27600
28189
  "use strict";
@@ -27602,7 +28191,7 @@ var init_detached_job_path = __esm({
27602
28191
  import_node_path62 = require("path");
27603
28192
  import_node_url5 = require("url");
27604
28193
  init_packaged_runtime();
27605
- import_meta6 = {};
28194
+ import_meta8 = {};
27606
28195
  DETACHED_JOB_FILENAMES = ["detached-job.cjs", "detached-job.js"];
27607
28196
  }
27608
28197
  });
@@ -28002,7 +28591,7 @@ function normalizeServiceOrigin(raw, fallback) {
28002
28591
  return fallback;
28003
28592
  }
28004
28593
  }
28005
- function asRecord13(value) {
28594
+ function asRecord14(value) {
28006
28595
  return value && typeof value === "object" && !Array.isArray(value) ? value : null;
28007
28596
  }
28008
28597
  function asString4(value) {
@@ -28035,7 +28624,7 @@ async function authorizedGet(url, token) {
28035
28624
  });
28036
28625
  const body = await readJson2(res);
28037
28626
  if (!res.ok) {
28038
- const record = asRecord13(body);
28627
+ const record = asRecord14(body);
28039
28628
  const message = firstString4(record, ["message", "error", "error_description", "detail"]) || (typeof body === "string" ? body.trim().slice(0, 160) : "");
28040
28629
  throw new Error(
28041
28630
  message ? `${res.status}: ${message}` : `Request failed (${res.status})`
@@ -28049,28 +28638,28 @@ async function verifyOptionalService(input) {
28049
28638
  const spec = optionalServiceSpec(input.id);
28050
28639
  try {
28051
28640
  if (input.id === "vercel") {
28052
- const body2 = asRecord13(await authorizedGet("https://api.vercel.com/v2/user", token));
28053
- const user = asRecord13(body2?.user) ?? body2;
28641
+ const body2 = asRecord14(await authorizedGet("https://api.vercel.com/v2/user", token));
28642
+ const user = asRecord14(body2?.user) ?? body2;
28054
28643
  const name2 = firstString4(user, ["username", "name", "email"]) || "Vercel user";
28055
28644
  return { viewerName: name2 };
28056
28645
  }
28057
28646
  if (input.id === "supabase") {
28058
28647
  const body2 = await authorizedGet("https://api.supabase.com/v1/organizations", token);
28059
28648
  const list2 = Array.isArray(body2) ? body2 : [];
28060
- const first2 = asRecord13(list2[0]);
28649
+ const first2 = asRecord14(list2[0]);
28061
28650
  const name2 = firstString4(first2, ["name", "slug"]) || "Supabase";
28062
28651
  return { viewerName: list2.length > 1 ? `${name2} +${list2.length - 1}` : name2 };
28063
28652
  }
28064
28653
  if (input.id === "posthog") {
28065
28654
  const host2 = normalizeServiceOrigin(input.host, spec.defaultHost ?? "https://us.posthog.com");
28066
- const body2 = asRecord13(await authorizedGet(`${host2}/api/users/@me/`, token));
28655
+ const body2 = asRecord14(await authorizedGet(`${host2}/api/users/@me/`, token));
28067
28656
  const name2 = firstString4(body2, ["email", "distinct_id"]) || [firstString4(body2, ["first_name"]), firstString4(body2, ["last_name"])].filter(Boolean).join(" ") || "PostHog user";
28068
28657
  return { viewerName: name2, host: host2 };
28069
28658
  }
28070
28659
  const host = normalizeServiceOrigin(input.host, spec.defaultHost ?? "https://sentry.io");
28071
28660
  const body = await authorizedGet(`${host}/api/0/organizations/`, token);
28072
28661
  const list = Array.isArray(body) ? body : [];
28073
- const first = asRecord13(list[0]);
28662
+ const first = asRecord14(list[0]);
28074
28663
  const name = firstString4(first, ["slug", "name"]) || "Sentry";
28075
28664
  return { viewerName: list.length > 1 ? `${name} +${list.length - 1}` : name, host };
28076
28665
  } catch (err) {
@@ -28944,10 +29533,10 @@ function collectActiveRunPorts(runs) {
28944
29533
  return [...ports];
28945
29534
  }
28946
29535
  function getOrchestrator() {
28947
- if (!singleton) {
28948
- singleton = new Orchestrator();
29536
+ if (!singleton2) {
29537
+ singleton2 = new Orchestrator();
28949
29538
  }
28950
- return singleton;
29539
+ return singleton2;
28951
29540
  }
28952
29541
  async function startOrchestration(opts) {
28953
29542
  const repoPath = opts.repoPath?.trim();
@@ -29007,7 +29596,7 @@ async function startOrchestration(opts) {
29007
29596
  }
29008
29597
  return updated;
29009
29598
  }
29010
- var import_node_events, import_node_crypto17, import_node_fs67, LIVE_TURN_SPAWN_GRACE_MS, RUN_SCRIPT_DESKTOP_ADOPT_MS, STALE_AGENT_PID_WAIT_MS, LIGHT_RECONCILE_THROTTLE_MS, Orchestrator, singleton;
29599
+ var import_node_events, import_node_crypto19, import_node_fs67, LIVE_TURN_SPAWN_GRACE_MS, RUN_SCRIPT_DESKTOP_ADOPT_MS, STALE_AGENT_PID_WAIT_MS, LIGHT_RECONCILE_THROTTLE_MS, Orchestrator, singleton2;
29011
29600
  var init_orchestrator = __esm({
29012
29601
  "src/orchestrator/orchestrator.ts"() {
29013
29602
  "use strict";
@@ -29015,7 +29604,7 @@ var init_orchestrator = __esm({
29015
29604
  init_injected_notices();
29016
29605
  init_task_state();
29017
29606
  init_wait_for_turn();
29018
- import_node_crypto17 = require("crypto");
29607
+ import_node_crypto19 = require("crypto");
29019
29608
  import_node_fs67 = require("fs");
29020
29609
  init_error_detail();
29021
29610
  init_run();
@@ -29041,6 +29630,7 @@ var init_orchestrator = __esm({
29041
29630
  init_usage();
29042
29631
  init_thread_store();
29043
29632
  init_desktop_host();
29633
+ init_model_context();
29044
29634
  init_agent_block();
29045
29635
  init_child_halt();
29046
29636
  init_stop_reason();
@@ -30039,6 +30629,7 @@ ${formatEnvReminder(projectNameForRepoPath(thread.repoPath || thread.worktreePat
30039
30629
  orchestrationReminder,
30040
30630
  prGateDirective,
30041
30631
  injectedNoticeContext,
30632
+ takeMcpAppModelContext(threadId),
30042
30633
  expandedPrompt
30043
30634
  ].filter(Boolean).join("\n\n");
30044
30635
  if (!autoContinue && sentAttachments) {
@@ -30667,7 +31258,7 @@ ${formatEnvReminder(projectNameForRepoPath(thread.repoPath || thread.worktreePat
30667
31258
  const request = sameIntent ? pending : {
30668
31259
  op,
30669
31260
  scriptName: scriptName ?? null,
30670
- requestId: (0, import_node_crypto17.randomUUID)(),
31261
+ requestId: (0, import_node_crypto19.randomUUID)(),
30671
31262
  requestedAt: (/* @__PURE__ */ new Date()).toISOString()
30672
31263
  };
30673
31264
  if (!sameIntent) {
@@ -31788,7 +32379,7 @@ ${formatEnvReminder(projectNameForRepoPath(thread.repoPath || thread.worktreePat
31788
32379
  return thread;
31789
32380
  }
31790
32381
  };
31791
- singleton = null;
32382
+ singleton2 = null;
31792
32383
  }
31793
32384
  });
31794
32385
 
@@ -32117,6 +32708,7 @@ __export(index_exports, {
32117
32708
  archiveRemovedWorkspaceChats: () => archiveRemovedWorkspaceChats,
32118
32709
  archivesWithRemovedWorkspace: () => archivesWithRemovedWorkspace,
32119
32710
  armSchedules: () => armSchedules,
32711
+ askBlockStillWaiting: () => askBlockStillWaiting,
32120
32712
  assertAbleTimeCredential: () => assertAbleTimeCredential,
32121
32713
  assertAbleTimeMcpCredential: () => assertAbleTimeMcpCredential,
32122
32714
  assertOrchestratorCapableAgent: () => assertOrchestratorCapableAgent,
@@ -32557,6 +33149,7 @@ __export(index_exports, {
32557
33149
  lastAgentReply: () => lastAgentReply,
32558
33150
  lastAssistantMessageText: () => lastAssistantMessageText,
32559
33151
  lastRequestOccupancy: () => lastRequestOccupancy,
33152
+ lastTopLevelToolIsAskUser: () => lastTopLevelToolIsAskUser,
32560
33153
  latestPendingPlanQuestions: () => latestPendingPlanQuestions,
32561
33154
  linearAuthorizationHeader: () => linearAuthorizationHeader,
32562
33155
  linearCycleIsActive: () => linearCycleIsActive,
@@ -32903,6 +33496,7 @@ __export(index_exports, {
32903
33496
  startRelayServer: () => startRelayServer,
32904
33497
  startRemoteAccountLogin: () => startRemoteAccountLogin,
32905
33498
  startSlackOAuth: () => startSlackOAuth,
33499
+ stashMcpAppModelContext: () => stashMcpAppModelContext,
32906
33500
  statWorktreePath: () => statWorktreePath,
32907
33501
  stopAgentRpcServer: () => stopAgentRpcServer,
32908
33502
  stripBrightsyNdjsonNoise: () => stripBrightsyNdjsonNoise,
@@ -33469,7 +34063,7 @@ init_schedule_runner();
33469
34063
 
33470
34064
  // src/host/serve.ts
33471
34065
  var import_node_child_process7 = require("child_process");
33472
- var import_node_os22 = require("os");
34066
+ var import_node_os21 = require("os");
33473
34067
  init_system_ca();
33474
34068
  init_app_settings();
33475
34069
  init_desktop_host();
@@ -33482,7 +34076,7 @@ init_system_ca();
33482
34076
 
33483
34077
  // src/slack/public-dns.ts
33484
34078
  var import_node_dns = require("dns");
33485
- var import_node_http2 = require("http");
34079
+ var import_node_http3 = require("http");
33486
34080
  var import_node_https = require("https");
33487
34081
  var PUBLIC_DNS = ["1.1.1.1", "8.8.8.8"];
33488
34082
  function finishLookup(options, callback, address, family) {
@@ -33612,213 +34206,12 @@ function buildPathRefAttachment(input) {
33612
34206
  init_stage_files();
33613
34207
  init_orchestrator();
33614
34208
 
33615
- // src/mcp-ui/host.ts
33616
- var import_node_os21 = require("os");
33617
- init_orch_mcp_isolation();
33618
- init_meta();
33619
-
33620
- // src/mcp-ui/session.ts
33621
- var import_client2 = require("@modelcontextprotocol/sdk/client/index.js");
33622
- var import_sse = require("@modelcontextprotocol/sdk/client/sse.js");
33623
- var import_stdio = require("@modelcontextprotocol/sdk/client/stdio.js");
33624
- var import_streamableHttp = require("@modelcontextprotocol/sdk/client/streamableHttp.js");
33625
- init_meta();
33626
- var REQUEST_TIMEOUT_MS = 2e4;
33627
- var UI_CAPABILITIES = {
33628
- extensions: {
33629
- "io.modelcontextprotocol/ui": {
33630
- mimeTypes: ["text/html;profile=mcp-app"]
33631
- }
33632
- }
33633
- };
33634
- async function openMcpUiSession(launch) {
33635
- return openMcpUiSessionFromTransport(transportForLaunch(launch));
33636
- }
33637
- async function openMcpUiSessionFromTransport(transport) {
33638
- const client = new import_client2.Client(
33639
- { name: "sideboard", version: "1.0.0" },
33640
- { capabilities: UI_CAPABILITIES }
33641
- );
33642
- await client.connect(transport, { timeout: REQUEST_TIMEOUT_MS });
33643
- return {
33644
- async listTools() {
33645
- const listed = await client.listTools(void 0, { timeout: REQUEST_TIMEOUT_MS });
33646
- return listed.tools.map((tool) => {
33647
- const meta = tool._meta;
33648
- return {
33649
- name: tool.name,
33650
- ...tool.description ? { description: tool.description } : {},
33651
- ...tool.inputSchema ? { inputSchema: tool.inputSchema } : {},
33652
- resourceUri: uiResourceUriFromMeta(meta),
33653
- ...cspFromMeta(meta) ? { csp: cspFromMeta(meta) } : {}
33654
- };
33655
- });
33656
- },
33657
- async readResource(uri) {
33658
- const result = await client.readResource({ uri }, { timeout: REQUEST_TIMEOUT_MS });
33659
- const content = result.contents?.[0];
33660
- if (!content) return null;
33661
- const text7 = "text" in content && typeof content.text === "string" ? content.text : void 0;
33662
- const blob = "blob" in content && typeof content.blob === "string" ? content.blob : void 0;
33663
- return {
33664
- uri: content.uri,
33665
- ...content.mimeType ? { mimeType: content.mimeType } : {},
33666
- ...text7 != null ? { text: text7 } : {},
33667
- ...blob != null ? { blob } : {},
33668
- ...cspFromMeta(content._meta) ? { csp: cspFromMeta(content._meta) } : {}
33669
- };
33670
- },
33671
- async callTool(name, args) {
33672
- return client.callTool({ name, arguments: args }, void 0, { timeout: REQUEST_TIMEOUT_MS });
33673
- },
33674
- async close() {
33675
- await client.close();
33676
- }
33677
- };
33678
- }
33679
- function transportForLaunch(launch) {
33680
- if (launch.kind === "stdio") {
33681
- return new import_stdio.StdioClientTransport({
33682
- command: launch.command,
33683
- args: launch.args,
33684
- env: { ...(0, import_stdio.getDefaultEnvironment)(), ...launch.env },
33685
- stderr: "ignore",
33686
- ...launch.cwd ? { cwd: launch.cwd } : {}
33687
- });
33688
- }
33689
- const url = new URL(launch.url);
33690
- const requestInit = launch.headers ? { headers: launch.headers } : void 0;
33691
- if (launch.kind === "sse") {
33692
- return new import_sse.SSEClientTransport(url, requestInit ? { requestInit } : void 0);
33693
- }
33694
- return new import_streamableHttp.StreamableHTTPClientTransport(url, requestInit ? { requestInit } : void 0);
33695
- }
33696
-
33697
- // src/mcp-ui/host.ts
33698
- var TOOL_TTL_MS = 5 * 60 * 1e3;
33699
- var McpUiHost = class {
33700
- constructor(opts) {
33701
- this.opts = opts;
33702
- }
33703
- opts;
33704
- sessions = /* @__PURE__ */ new Map();
33705
- toolLists = /* @__PURE__ */ new Map();
33706
- async viewForClaudeTool(toolName, projectDirs) {
33707
- const entries = this.userEntries(projectDirs);
33708
- const match = matchClaudeMcpTool(toolName, Object.keys(entries));
33709
- if (!match) return null;
33710
- const launch = parseMcpServerLaunch(entries[match.server] ?? {});
33711
- if (!launch) return null;
33712
- try {
33713
- const session = await this.sessionFor(match.server, launch);
33714
- const tools = await this.toolsFor(match.server, launch, session);
33715
- const tool = tools.find((item) => item.name === match.tool);
33716
- if (!tool?.resourceUri) return null;
33717
- const resource = await session.readResource(tool.resourceUri);
33718
- if (!resource) return null;
33719
- const html = htmlFromResourceContent(resource);
33720
- if (!html) return null;
33721
- const csp = resource.csp ?? tool.csp;
33722
- return {
33723
- server: match.server,
33724
- tool: match.tool,
33725
- uri: html.uri,
33726
- mimeType: html.mimeType,
33727
- html: html.html,
33728
- csp: mcpUiContentSecurityPolicy(csp)
33729
- };
33730
- } catch (err) {
33731
- console.error(
33732
- `[mcp-ui] ${match.server}/${match.tool}:`,
33733
- err instanceof Error ? err.message : err
33734
- );
33735
- return null;
33736
- }
33737
- }
33738
- async callTool(server, tool, args, projectDirs) {
33739
- const session = await this.sessionForName(server, projectDirs);
33740
- if (!session) throw new Error(`MCP server ${server} is not available`);
33741
- return session.callTool(tool, args);
33742
- }
33743
- async readResource(server, uri, projectDirs) {
33744
- const session = await this.sessionForName(server, projectDirs);
33745
- if (!session) throw new Error(`MCP server ${server} is not available`);
33746
- const resource = await session.readResource(uri);
33747
- if (!resource) throw new Error(`Resource ${uri} was empty`);
33748
- return {
33749
- contents: [
33750
- {
33751
- uri: resource.uri,
33752
- ...resource.mimeType ? { mimeType: resource.mimeType } : {},
33753
- ...resource.text != null ? { text: resource.text } : {},
33754
- ...resource.blob != null ? { blob: resource.blob } : {}
33755
- }
33756
- ]
33757
- };
33758
- }
33759
- async closeAll() {
33760
- const pending = [...this.sessions.values()];
33761
- this.sessions.clear();
33762
- this.toolLists.clear();
33763
- await Promise.all(
33764
- pending.map((session) => session.then((open) => open.close()).catch(() => void 0))
33765
- );
33766
- }
33767
- userEntries(projectDirs) {
33768
- const out = {};
33769
- for (const [name, entry] of Object.entries(this.opts.entries(projectDirs))) {
33770
- if (!name.trim() || isInjectedOrchMcpName(name) || !entry) continue;
33771
- out[name] = entry;
33772
- }
33773
- return out;
33774
- }
33775
- async sessionForName(server, projectDirs) {
33776
- const entry = this.userEntries(projectDirs)[server];
33777
- if (!entry) return null;
33778
- const launch = parseMcpServerLaunch(entry);
33779
- if (!launch) return null;
33780
- return this.sessionFor(server, launch);
33781
- }
33782
- sessionFor(server, launch) {
33783
- const key = `${server}
33784
- ${JSON.stringify(launch)}`;
33785
- const existing = this.sessions.get(key);
33786
- if (existing) return existing;
33787
- const open = this.opts.openSession ?? openMcpUiSession;
33788
- const pending = open(launch).catch((err) => {
33789
- this.sessions.delete(key);
33790
- throw err;
33791
- });
33792
- this.sessions.set(key, pending);
33793
- return pending;
33794
- }
33795
- async toolsFor(server, launch, session) {
33796
- const key = `${server}
33797
- ${JSON.stringify(launch)}`;
33798
- const cached2 = this.toolLists.get(key);
33799
- if (cached2 && cached2.key === key && Date.now() - cached2.at < TOOL_TTL_MS) return cached2.tools;
33800
- const tools = await session.listTools();
33801
- this.toolLists.set(key, { at: Date.now(), key, tools });
33802
- return tools;
33803
- }
33804
- };
33805
- var singleton2;
33806
- function getMcpUiHost() {
33807
- if (!singleton2) {
33808
- singleton2 = new McpUiHost({
33809
- entries: (projectDirs) => listUserClaudeMcpServerEntries((0, import_node_os21.homedir)(), projectDirs)
33810
- });
33811
- }
33812
- return singleton2;
33813
- }
33814
- function closeMcpUiHost() {
33815
- const host = singleton2;
33816
- singleton2 = void 0;
33817
- if (host) void host.closeAll();
33818
- }
34209
+ // src/remote/phone-mcp-ui-listen.ts
34210
+ init_host();
34211
+ init_model_context();
33819
34212
 
33820
34213
  // src/remote/phone-chats.ts
33821
- var import_node_crypto18 = require("crypto");
34214
+ var import_node_crypto20 = require("crypto");
33822
34215
  init_list_models();
33823
34216
  init_home_board();
33824
34217
  init_stage_files();
@@ -33840,10 +34233,10 @@ var MIN_MD_CHARS = 120;
33840
34233
  function oneLine2(value, max) {
33841
34234
  return value.replace(/[`\r\n]/g, " ").replace(/\s+/g, " ").trim().slice(0, max);
33842
34235
  }
33843
- function asRecord14(value) {
34236
+ function asRecord15(value) {
33844
34237
  if (typeof value === "string") {
33845
34238
  try {
33846
- return asRecord14(JSON.parse(value));
34239
+ return asRecord15(JSON.parse(value));
33847
34240
  } catch {
33848
34241
  return void 0;
33849
34242
  }
@@ -33918,7 +34311,7 @@ function toolContent(input) {
33918
34311
  if (!input) return "";
33919
34312
  const direct = input.content;
33920
34313
  if (typeof direct === "string") return direct;
33921
- const nested = asRecord14(direct);
34314
+ const nested = asRecord15(direct);
33922
34315
  if (!nested) return "";
33923
34316
  for (const key of ["html", "markup", "text", "source", "content", "code"]) {
33924
34317
  if (typeof nested[key] === "string") return nested[key];
@@ -33941,7 +34334,7 @@ function phoneArtifactText(text7, parts, limit = Number.POSITIVE_INFINITY) {
33941
34334
  const extras = [];
33942
34335
  for (const part of parts ?? []) {
33943
34336
  if (part.type !== "tool" || part.parentId || !isArtifactTool(part.name)) continue;
33944
- const input = asRecord14(part.input);
34337
+ const input = asRecord15(part.input);
33945
34338
  const content = toolContent(input);
33946
34339
  const hint = artifactHint(content);
33947
34340
  if (hint && hints.has(hint)) continue;
@@ -33960,7 +34353,7 @@ function phoneArtifactText(text7, parts, limit = Number.POSITIVE_INFINITY) {
33960
34353
  ${tail}` : tail;
33961
34354
  }
33962
34355
  function parseOpenArtifact(value, chatId) {
33963
- const record = asRecord14(value);
34356
+ const record = asRecord15(value);
33964
34357
  if (!record) return "invalid";
33965
34358
  const title = oneLine2(str5(record.title), 200);
33966
34359
  if (!title) return "invalid";
@@ -33983,7 +34376,7 @@ function phoneArtifactDocuments(sources) {
33983
34376
  }
33984
34377
  for (const part of source.parts ?? []) {
33985
34378
  if (part.type !== "tool" || part.parentId || !isArtifactTool(part.name)) continue;
33986
- const input = asRecord14(part.input);
34379
+ const input = asRecord15(part.input);
33987
34380
  const content = toolContent(input);
33988
34381
  const hint = artifactHint(content);
33989
34382
  if (hint && hints.has(hint)) continue;
@@ -34428,13 +34821,21 @@ function parsePhoneMcpUi(value, op, chatId) {
34428
34821
  }
34429
34822
  return { op: "mcp-ui", chatId, tool: tool2, callId, reqId: reqId2 };
34430
34823
  }
34824
+ if (op === "mcp-ui-context") {
34825
+ const reqId2 = controlText(value, "reqId");
34826
+ const text7 = controlText(value, "text");
34827
+ if (!reqId2 || reqId2.length > 40 || !text7 || text7.length > 8e3) return "invalid";
34828
+ return { op, chatId, reqId: reqId2, text: text7 };
34829
+ }
34431
34830
  if (op !== "mcp-ui-call" && op !== "mcp-ui-read") return "invalid";
34432
34831
  const reqId = controlText(value, "reqId");
34433
34832
  const server = controlText(value, "server");
34434
34833
  if (!reqId || reqId.length > 40 || !server || server.length > 120) return "invalid";
34435
34834
  if (op === "mcp-ui-read") {
34436
34835
  const uri = controlText(value, "uri");
34437
- if (!uri.startsWith("ui://") || uri.length > 500) return "invalid";
34836
+ if (!uri || uri.length > 500 || /\s/.test(uri) || /^(javascript|data):/i.test(uri)) {
34837
+ return "invalid";
34838
+ }
34438
34839
  return { op, chatId, reqId, server, uri };
34439
34840
  }
34440
34841
  const tool = controlText(value, "tool");
@@ -34656,7 +35057,7 @@ function parsePhoneControl(value) {
34656
35057
  }
34657
35058
  if (op === "pane") return parsePhonePane(value, chatId);
34658
35059
  if (op === "open-artifact") return parseOpenArtifact(value, chatId);
34659
- if (op === "mcp-ui" || op === "mcp-ui-call" || op === "mcp-ui-read") return parsePhoneMcpUi(value, op, chatId);
35060
+ if (op === "mcp-ui" || op === "mcp-ui-call" || op === "mcp-ui-read" || op === "mcp-ui-context") return parsePhoneMcpUi(value, op, chatId);
34660
35061
  if (op === "open-file" || op === "media") {
34661
35062
  const path2 = textField(value, "path");
34662
35063
  if (!path2 || path2.length > 2e3) return "invalid";
@@ -34828,6 +35229,7 @@ function parsePhoneCreate(value) {
34828
35229
  }
34829
35230
  function summarize(thread) {
34830
35231
  const pr = phonePrPill(thread);
35232
+ const block = visibleAgentBlock(thread);
34831
35233
  return {
34832
35234
  id: thread.id,
34833
35235
  title: thread.title?.trim() || "Untitled",
@@ -34838,14 +35240,12 @@ function summarize(thread) {
34838
35240
  ...pr?.url ? { prUrl: pr.url } : {},
34839
35241
  ...pr?.number ? { prNumber: pr.number } : {},
34840
35242
  ...pr?.status ? { prStatus: pr.status } : {},
34841
- ...thread.agentBlock ? { needsYou: true, blockedReason: thread.agentBlock.reason } : {}
35243
+ ...block ? { needsYou: true, blockedReason: block.reason } : {}
34842
35244
  };
34843
35245
  }
34844
35246
  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);
35247
+ const last = listPhoneMessages(thread).at(-1);
35248
+ return last ? clip(last.text.replace(/\s+/g, " ").trim(), PREVIEW_LIMIT2) : "";
34849
35249
  }
34850
35250
  function repoName2(repoPath) {
34851
35251
  return repoPath.replace(/\/$/, "").split("/").pop() || repoPath;
@@ -34924,13 +35324,13 @@ function phoneComposerOptions(thread) {
34924
35324
  }
34925
35325
  function phoneTurnAttachments(draft) {
34926
35326
  const links = (draft.links ?? []).map((link) => ({
34927
- id: (0, import_node_crypto18.randomUUID)(),
35327
+ id: (0, import_node_crypto20.randomUUID)(),
34928
35328
  name: link.ref,
34929
35329
  kind: "issue",
34930
35330
  content: [`Linked issue: ${link.ref} \u2014 ${link.title}`, link.url ? `URL: ${link.url}` : null].filter(Boolean).join("\n")
34931
35331
  }));
34932
35332
  const files = (draft.files ?? []).map((file) => ({
34933
- id: (0, import_node_crypto18.randomUUID)(),
35333
+ id: (0, import_node_crypto20.randomUUID)(),
34934
35334
  name: file.name,
34935
35335
  kind: "file",
34936
35336
  previewDataUrl: `data:application/octet-stream;base64,${file.dataBase64}`,
@@ -35201,7 +35601,8 @@ function emitChatTurn(opts, chatId, threadId) {
35201
35601
  const pending = latestPendingPlanQuestions({
35202
35602
  messages: thread.messages,
35203
35603
  agentBlock: thread.agentBlock,
35204
- dismissedQuestionSignature: thread.dismissedQuestionSignature
35604
+ dismissedQuestionSignature: thread.dismissedQuestionSignature,
35605
+ status: thread.status
35205
35606
  });
35206
35607
  if (pending && result.taskState !== "failed" && result.taskState !== "canceled" && (result.taskState === "input-required" || thread.agentBlock?.source === "ask_user")) {
35207
35608
  emitControl(opts, {
@@ -35265,7 +35666,9 @@ function deliverPhoneTurn(opts, chatId) {
35265
35666
  // src/remote/phone-mcp-ui-listen.ts
35266
35667
  var PHONE_HTML_CAP = 7e5;
35267
35668
  function dispatchPhoneMcpUi(cmd, opts) {
35268
- if (cmd.op !== "mcp-ui" && cmd.op !== "mcp-ui-call" && cmd.op !== "mcp-ui-read") return false;
35669
+ if (cmd.op !== "mcp-ui" && cmd.op !== "mcp-ui-call" && cmd.op !== "mcp-ui-read" && cmd.op !== "mcp-ui-context") {
35670
+ return false;
35671
+ }
35269
35672
  const thread = readPhoneThread(cmd.chatId);
35270
35673
  const reqId = cmd.reqId;
35271
35674
  const chatId = cmd.chatId;
@@ -35275,6 +35678,11 @@ function dispatchPhoneMcpUi(cmd, opts) {
35275
35678
  return true;
35276
35679
  }
35277
35680
  const projectDirs = [thread.repoPath, thread.worktreePath];
35681
+ if (cmd.op === "mcp-ui-context") {
35682
+ stashMcpAppModelContext(thread.id, cmd.text);
35683
+ emitControl(opts, { op: "mcp-ui-context", chatId, reqId, result: {} });
35684
+ return true;
35685
+ }
35278
35686
  if (cmd.op === "mcp-ui-call") {
35279
35687
  void getMcpUiHost().callTool(cmd.server, cmd.tool, cmd.args, projectDirs).then((result) => emitControl(opts, { op: "mcp-ui-call", chatId, reqId, result })).catch(
35280
35688
  (err) => emitControl(opts, { op: "mcp-ui-call", chatId, reqId, error: phoneError(err) })
@@ -35572,7 +35980,8 @@ function republishPendingAsk(opts, chatId) {
35572
35980
  const pending = latestPendingPlanQuestions({
35573
35981
  messages: thread.messages,
35574
35982
  agentBlock: thread.agentBlock,
35575
- dismissedQuestionSignature: thread.dismissedQuestionSignature
35983
+ dismissedQuestionSignature: thread.dismissedQuestionSignature,
35984
+ status: thread.status
35576
35985
  });
35577
35986
  if (!pending) return;
35578
35987
  emitControl(opts, {
@@ -36110,8 +36519,8 @@ init_fetch();
36110
36519
  init_issue_attachments();
36111
36520
 
36112
36521
  // src/integrations/linear-oauth.ts
36113
- var import_node_crypto19 = require("crypto");
36114
- var import_node_http3 = require("http");
36522
+ var import_node_crypto21 = require("crypto");
36523
+ var import_node_http4 = require("http");
36115
36524
  init_app_settings();
36116
36525
  init_fetch();
36117
36526
 
@@ -36142,8 +36551,8 @@ function linearOAuthCredentials() {
36142
36551
  return { clientId, clientSecret };
36143
36552
  }
36144
36553
  function createLinearPkce() {
36145
- const verifier = (0, import_node_crypto19.randomBytes)(32).toString("base64url");
36146
- const challenge = (0, import_node_crypto19.createHash)("sha256").update(verifier).digest("base64url");
36554
+ const verifier = (0, import_node_crypto21.randomBytes)(32).toString("base64url");
36555
+ const challenge = (0, import_node_crypto21.createHash)("sha256").update(verifier).digest("base64url");
36147
36556
  return { verifier, challenge };
36148
36557
  }
36149
36558
  function linearOAuthAuthorizeUrl(clientId, state, codeChallenge) {
@@ -36274,7 +36683,7 @@ async function startLinearOAuth(opts) {
36274
36683
  throw new LinearOAuthCancelledError();
36275
36684
  }
36276
36685
  const { clientId, clientSecret } = linearOAuthCredentials();
36277
- const state = (0, import_node_crypto19.randomBytes)(16).toString("hex");
36686
+ const state = (0, import_node_crypto21.randomBytes)(16).toString("hex");
36278
36687
  const pkce = createLinearPkce();
36279
36688
  const authorizeUrl = linearOAuthAuthorizeUrl(clientId, state, pkce.challenge);
36280
36689
  const timeoutMs = opts?.timeoutMs ?? 5 * 6e4;
@@ -36287,7 +36696,7 @@ async function startLinearOAuth(opts) {
36287
36696
  if (err) reject(err);
36288
36697
  else resolve3(value);
36289
36698
  };
36290
- const server = (0, import_node_http3.createServer)((req, res) => {
36699
+ const server = (0, import_node_http4.createServer)((req, res) => {
36291
36700
  try {
36292
36701
  const url = new URL(req.url || "/", `http://127.0.0.1:${LINEAR_OAUTH_PORT}`);
36293
36702
  if (url.pathname !== "/callback") {
@@ -37835,7 +38244,8 @@ function runCoordinatorPrompt(opts, body, generation) {
37835
38244
  const pending = latestPendingPlanQuestions({
37836
38245
  messages: thread.messages,
37837
38246
  agentBlock: thread.agentBlock,
37838
- dismissedQuestionSignature: thread.dismissedQuestionSignature
38247
+ dismissedQuestionSignature: thread.dismissedQuestionSignature,
38248
+ status: thread.status
37839
38249
  });
37840
38250
  if (pending && result.taskState !== "failed" && result.taskState !== "canceled" && (result.taskState === "input-required" || thread.agentBlock?.source === "ask_user")) {
37841
38251
  opts.onOutbound({
@@ -38284,7 +38694,15 @@ init_paths();
38284
38694
  init_thread_store();
38285
38695
  var PHONE_BOARD_SYNC_MS = 300;
38286
38696
  function chatKey(row2) {
38287
- return [row2.id, row2.title, row2.status, row2.agent, row2.preview].join(" ");
38697
+ return [
38698
+ row2.id,
38699
+ row2.title,
38700
+ row2.status,
38701
+ row2.agent,
38702
+ row2.preview,
38703
+ row2.needsYou ? "1" : "0",
38704
+ row2.blockedReason ?? ""
38705
+ ].join(" ");
38288
38706
  }
38289
38707
  function phoneBoardKey(sidebar) {
38290
38708
  const orchestration = sidebar.orchestration.map(chatKey).join("\n");
@@ -38691,7 +39109,7 @@ function runRemoteHost(opts) {
38691
39109
  init_protocol();
38692
39110
 
38693
39111
  // src/relay/server.ts
38694
- var import_node_http4 = require("http");
39112
+ var import_node_http5 = require("http");
38695
39113
  var import_ws4 = require("ws");
38696
39114
 
38697
39115
  // src/slack/oauth-redirect.ts
@@ -39100,7 +39518,7 @@ function connectSession(ws, opts, log) {
39100
39518
  }
39101
39519
 
39102
39520
  // src/slack/relay-protocol.ts
39103
- var import_node_crypto20 = require("crypto");
39521
+ var import_node_crypto22 = require("crypto");
39104
39522
  var SLACK_RELAY_PING_INTERVAL_MS = 2e4;
39105
39523
  var SLACK_RELAY_PONG_TIMEOUT_MS = 15e3;
39106
39524
  function slackRelaySessionKey(teamId, userId, deviceId) {
@@ -39110,7 +39528,7 @@ function slackRelayUserKey(teamId, userId) {
39110
39528
  return `${teamId.trim()}:${userId.trim()}`;
39111
39529
  }
39112
39530
  function newSlackRelayEventId() {
39113
- return (0, import_node_crypto20.randomBytes)(12).toString("hex");
39531
+ return (0, import_node_crypto22.randomBytes)(12).toString("hex");
39114
39532
  }
39115
39533
  function parseSlackRelayClientMessage(raw) {
39116
39534
  try {
@@ -39638,7 +40056,7 @@ async function tryServeStatic(req, res, root) {
39638
40056
  }
39639
40057
 
39640
40058
  // src/remote/hub.ts
39641
- var import_node_crypto21 = require("crypto");
40059
+ var import_node_crypto23 = require("crypto");
39642
40060
  init_protocol();
39643
40061
  var CODE_ALPHABET = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789";
39644
40062
  var CODE_TTL_MS = 10 * 60 * 1e3;
@@ -39649,7 +40067,7 @@ function send(socket, msg) {
39649
40067
  }
39650
40068
  }
39651
40069
  function newCode() {
39652
- const bytes = (0, import_node_crypto21.randomBytes)(6);
40070
+ const bytes = (0, import_node_crypto23.randomBytes)(6);
39653
40071
  let code = "";
39654
40072
  for (let i = 0; i < 6; i++) code += CODE_ALPHABET[bytes[i] % CODE_ALPHABET.length];
39655
40073
  return code;
@@ -39908,7 +40326,7 @@ var RemoteHub = class {
39908
40326
  host.phone = null;
39909
40327
  }
39910
40328
  const created = sessionToken == null;
39911
- const token = sessionToken ?? (0, import_node_crypto21.randomBytes)(24).toString("hex");
40329
+ const token = sessionToken ?? (0, import_node_crypto23.randomBytes)(24).toString("hex");
39912
40330
  if (host.sessionToken && host.sessionToken !== token) {
39913
40331
  this.phonesByToken.delete(host.sessionToken);
39914
40332
  }
@@ -39960,7 +40378,7 @@ var RemoteHub = class {
39960
40378
  init_protocol();
39961
40379
 
39962
40380
  // src/relay/accounts.ts
39963
- var import_node_crypto22 = require("crypto");
40381
+ var import_node_crypto24 = require("crypto");
39964
40382
  var import_node_fs70 = require("fs");
39965
40383
  var import_node_module7 = require("module");
39966
40384
  var import_node_path68 = require("path");
@@ -39979,12 +40397,12 @@ function openDatabase(filePath) {
39979
40397
  return db;
39980
40398
  }
39981
40399
  function sha2562(value) {
39982
- return (0, import_node_crypto22.createHash)("sha256").update(value).digest("hex");
40400
+ return (0, import_node_crypto24.createHash)("sha256").update(value).digest("hex");
39983
40401
  }
39984
40402
  function sameHash(a, b) {
39985
40403
  const left = Buffer.from(a);
39986
40404
  const right = Buffer.from(b);
39987
- return left.length === right.length && (0, import_node_crypto22.timingSafeEqual)(left, right);
40405
+ return left.length === right.length && (0, import_node_crypto24.timingSafeEqual)(left, right);
39988
40406
  }
39989
40407
  function normalizeEmail(email) {
39990
40408
  const trimmed = email?.trim().toLowerCase() ?? "";
@@ -40089,7 +40507,7 @@ var RelayAccountStore = class {
40089
40507
  this.insertIdentity(issuer, subject, accountId, email, verified);
40090
40508
  } else {
40091
40509
  const byEmail = verified ? this.accountIdForVerifiedEmail(email) : void 0;
40092
- accountId = byEmail ?? (0, import_node_crypto22.randomUUID)();
40510
+ accountId = byEmail ?? (0, import_node_crypto24.randomUUID)();
40093
40511
  if (!byEmail) {
40094
40512
  this.db.prepare("INSERT INTO accounts (id, created_at, device_cap) VALUES (?, ?, ?)").run(accountId, Date.now(), RELAY_DEVICE_CAP);
40095
40513
  }
@@ -40211,7 +40629,7 @@ var RelayAccountStore = class {
40211
40629
  ).run(issuer, subject, accountId, email, verified ? 1 : 0);
40212
40630
  }
40213
40631
  mintCredential(accountId) {
40214
- const credential = (0, import_node_crypto22.randomBytes)(32).toString("hex");
40632
+ const credential = (0, import_node_crypto24.randomBytes)(32).toString("hex");
40215
40633
  this.db.prepare("INSERT INTO credentials (token_hash, account_id, created_at) VALUES (?, ?, ?)").run(sha2562(credential), accountId, Date.now());
40216
40634
  return credential;
40217
40635
  }
@@ -40686,7 +41104,7 @@ async function startRelayServer(opts) {
40686
41104
  sendJson2(res, 200, { ok: true, ...value.payload });
40687
41105
  return true;
40688
41106
  };
40689
- const httpServer = (0, import_node_http4.createServer)((req, res) => {
41107
+ const httpServer = (0, import_node_http5.createServer)((req, res) => {
40690
41108
  void (async () => {
40691
41109
  const reqUrl = req.url || "/";
40692
41110
  if (accountStore && await handleRelayAccountHttp({
@@ -41023,7 +41441,7 @@ async function bindAbort(signal, stop) {
41023
41441
  }
41024
41442
  function flatInterfaces() {
41025
41443
  const out = [];
41026
- for (const rows of Object.values((0, import_node_os22.networkInterfaces)())) {
41444
+ for (const rows of Object.values((0, import_node_os21.networkInterfaces)())) {
41027
41445
  if (!rows) continue;
41028
41446
  out.push(...rows);
41029
41447
  }
@@ -41120,7 +41538,7 @@ init_stage_files();
41120
41538
  init_consume_attachments();
41121
41539
 
41122
41540
  // src/composer/pasted-text.ts
41123
- var import_node_crypto23 = require("crypto");
41541
+ var import_node_crypto25 = require("crypto");
41124
41542
  var PASTE_ATTACH_MIN_CHARS = 1200;
41125
41543
  var PASTE_ATTACH_MIN_LINES = 15;
41126
41544
  var PASTED_NAME_RE = /^Pasted text #(\d+)\.txt$/i;
@@ -41147,7 +41565,7 @@ function nextPastedTextName(existing) {
41147
41565
  }
41148
41566
  function buildPastedTextAttachment(text7, opts) {
41149
41567
  return {
41150
- id: opts?.id ?? (0, import_node_crypto23.randomUUID)(),
41568
+ id: opts?.id ?? (0, import_node_crypto25.randomUUID)(),
41151
41569
  name: opts?.name ?? "Pasted text #1.txt",
41152
41570
  kind: "file",
41153
41571
  path: opts?.path,
@@ -41323,7 +41741,7 @@ function createClippedMcpServer() {
41323
41741
 
41324
41742
  // src/mcp/server.ts
41325
41743
  var import_zod11 = require("zod");
41326
- var import_node_crypto26 = require("crypto");
41744
+ var import_node_crypto28 = require("crypto");
41327
41745
  var import_node_path73 = require("path");
41328
41746
  init_orchestrator();
41329
41747
  init_task_state();
@@ -42915,7 +43333,7 @@ function registerScheduleTools(server) {
42915
43333
  }
42916
43334
 
42917
43335
  // src/agent-rpc/handlers.ts
42918
- var import_node_crypto24 = require("crypto");
43336
+ var import_node_crypto26 = require("crypto");
42919
43337
  var import_node_path70 = require("path");
42920
43338
  init_wait_for_job();
42921
43339
  init_wait_for_turn();
@@ -42946,7 +43364,7 @@ setToolPermissionPublisher({
42946
43364
  }
42947
43365
  }
42948
43366
  });
42949
- function asRecord15(value) {
43367
+ function asRecord16(value) {
42950
43368
  if (!value || typeof value !== "object" || Array.isArray(value)) return {};
42951
43369
  return value;
42952
43370
  }
@@ -42957,12 +43375,12 @@ function invalidParams(message) {
42957
43375
  return Object.assign(new Error(message), { rpcCode: -32602 });
42958
43376
  }
42959
43377
  var handlePermissionAsk = async (params, _ctx) => {
42960
- const rec = asRecord15(params);
43378
+ const rec = asRecord16(params);
42961
43379
  const threadId = str6(rec.threadId).trim();
42962
43380
  const toolName = str6(rec.toolName).trim();
42963
43381
  if (!threadId) throw invalidParams("threadId is required");
42964
43382
  if (!toolName) throw invalidParams("toolName is required");
42965
- const input = asRecord15(rec.input);
43383
+ const input = asRecord16(rec.input);
42966
43384
  const ask = {
42967
43385
  threadId,
42968
43386
  toolName,
@@ -42998,7 +43416,7 @@ var handlePermissionAsk = async (params, _ctx) => {
42998
43416
  // src/agent-rpc/handlers.ts
42999
43417
  init_protocol2();
43000
43418
  function presentArtifactResult(input) {
43001
- const id = input.artifact_id?.trim() || `artifact_${Date.now().toString(36)}_${(0, import_node_crypto24.randomUUID)().slice(0, 8)}`;
43419
+ const id = input.artifact_id?.trim() || `artifact_${Date.now().toString(36)}_${(0, import_node_crypto26.randomUUID)().slice(0, 8)}`;
43002
43420
  return {
43003
43421
  ok: true,
43004
43422
  artifact_id: id,
@@ -43010,7 +43428,7 @@ function presentArtifactResult(input) {
43010
43428
  message: input.type === "log" ? "Log accepted. Same artifact_id appends; send only new lines next time." : "Artifact accepted. Sideboard desktop opens it in the side column beside chat."
43011
43429
  };
43012
43430
  }
43013
- function asRecord16(value) {
43431
+ function asRecord17(value) {
43014
43432
  if (!value || typeof value !== "object" || Array.isArray(value)) return {};
43015
43433
  return value;
43016
43434
  }
@@ -43034,7 +43452,7 @@ async function handleRuntimePing(_params, _ctx) {
43034
43452
  };
43035
43453
  }
43036
43454
  async function handlePresentArtifact(params, _ctx) {
43037
- const rec = asRecord16(params);
43455
+ const rec = asRecord17(params);
43038
43456
  const title = str7(rec.title).trim();
43039
43457
  const type = str7(rec.type).trim();
43040
43458
  const allowed = ["html", "svg", "markdown", "react", "log"];
@@ -43058,7 +43476,7 @@ async function handlePresentArtifact(params, _ctx) {
43058
43476
  });
43059
43477
  }
43060
43478
  async function handleJobWait(params, ctx, waitFn = waitForDetachedJob) {
43061
- const rec = asRecord16(params);
43479
+ const rec = asRecord17(params);
43062
43480
  const id = str7(rec.id).trim();
43063
43481
  if (!id) throw invalidParams2("id is required");
43064
43482
  const cwd = jobCwd(rec);
@@ -43082,7 +43500,7 @@ async function handleJobWait(params, ctx, waitFn = waitForDetachedJob) {
43082
43500
  };
43083
43501
  }
43084
43502
  async function handleJobStop(params, _ctx) {
43085
- const rec = asRecord16(params);
43503
+ const rec = asRecord17(params);
43086
43504
  const id = str7(rec.id).trim();
43087
43505
  if (!id) throw invalidParams2("id is required");
43088
43506
  const reason = str7(rec.reason).trim() || void 0;
@@ -43110,7 +43528,7 @@ async function defaultTurnWait(ref, timeoutMs) {
43110
43528
  });
43111
43529
  }
43112
43530
  async function handleTurnWait(params, ctx, waitFn = defaultTurnWait) {
43113
- const rec = asRecord16(params);
43531
+ const rec = asRecord17(params);
43114
43532
  const ref = str7(rec.ref).trim();
43115
43533
  if (!ref) throw invalidParams2("ref is required");
43116
43534
  const requested = typeof rec.timeoutMs === "number" && Number.isFinite(rec.timeoutMs) ? rec.timeoutMs : void 0;
@@ -43162,7 +43580,7 @@ init_worktree();
43162
43580
  init_paths();
43163
43581
 
43164
43582
  // src/board/board-pins.ts
43165
- var import_node_crypto25 = require("crypto");
43583
+ var import_node_crypto27 = require("crypto");
43166
43584
  var import_node_fs72 = require("fs");
43167
43585
  var import_node_path71 = require("path");
43168
43586
  init_paths();
@@ -43194,7 +43612,7 @@ function addBoardPin(input) {
43194
43612
  const ref = input.ref.trim();
43195
43613
  if (!ref) throw new Error("Board item needs a ref");
43196
43614
  const pin = {
43197
- id: (0, import_node_crypto25.randomUUID)(),
43615
+ id: (0, import_node_crypto27.randomUUID)(),
43198
43616
  kind: input.kind,
43199
43617
  ref,
43200
43618
  repoPath: input.repoPath.trim(),
@@ -44127,7 +44545,7 @@ async function startMcpServer() {
44127
44545
  const ident = issue?.identifier ?? ref.trim();
44128
44546
  const attachments = issue ? [
44129
44547
  {
44130
- id: (0, import_node_crypto26.randomUUID)(),
44548
+ id: (0, import_node_crypto28.randomUUID)(),
44131
44549
  name: issue.identifier,
44132
44550
  kind: "issue",
44133
44551
  content: [
@@ -44689,8 +45107,8 @@ init_protocol2();
44689
45107
  init_metadata();
44690
45108
 
44691
45109
  // src/agent-rpc/server.ts
44692
- var import_node_crypto27 = require("crypto");
44693
- var import_node_http5 = require("http");
45110
+ var import_node_crypto29 = require("crypto");
45111
+ var import_node_http6 = require("http");
44694
45112
  var import_ws5 = require("ws");
44695
45113
  init_protocol2();
44696
45114
  init_metadata();
@@ -44698,7 +45116,7 @@ function tokensEqual(a, b) {
44698
45116
  const left = Buffer.from(a);
44699
45117
  const right = Buffer.from(b);
44700
45118
  if (left.length !== right.length) return false;
44701
- return (0, import_node_crypto27.timingSafeEqual)(left, right);
45119
+ return (0, import_node_crypto29.timingSafeEqual)(left, right);
44702
45120
  }
44703
45121
  function authTokenFromUpgrade(req) {
44704
45122
  try {
@@ -44731,16 +45149,16 @@ var AgentRpcServer = class {
44731
45149
  async listen(opts = {}) {
44732
45150
  const host = opts.host ?? "127.0.0.1";
44733
45151
  const port = opts.port ?? 0;
44734
- const authToken = (0, import_node_crypto27.randomBytes)(24).toString("base64url");
45152
+ const authToken = (0, import_node_crypto29.randomBytes)(24).toString("base64url");
44735
45153
  this.meta = {
44736
- runtimeId: (0, import_node_crypto27.randomUUID)(),
45154
+ runtimeId: (0, import_node_crypto29.randomUUID)(),
44737
45155
  pid: process.pid,
44738
45156
  protocolVersion: AGENT_RPC_PROTOCOL_VERSION,
44739
45157
  authToken,
44740
45158
  startedAt: Date.now(),
44741
45159
  transports: []
44742
45160
  };
44743
- const http = (0, import_node_http5.createServer)((_req, res) => {
45161
+ const http = (0, import_node_http6.createServer)((_req, res) => {
44744
45162
  res.statusCode = 404;
44745
45163
  res.end();
44746
45164
  });
@@ -45226,6 +45644,8 @@ init_oauth();
45226
45644
  init_injected_mcp();
45227
45645
  init_user_mcp_config();
45228
45646
  init_orch_mcp_isolation();
45647
+ init_host();
45648
+ init_model_context();
45229
45649
  init_meta();
45230
45650
 
45231
45651
  // src/slack/workspaces.ts
@@ -45324,7 +45744,7 @@ function slackTokenFor(ws, kind = "read") {
45324
45744
  }
45325
45745
 
45326
45746
  // src/slack/oauth.ts
45327
- var import_node_crypto28 = require("crypto");
45747
+ var import_node_crypto30 = require("crypto");
45328
45748
  init_app_settings();
45329
45749
  var SLACK_BOT_SCOPES = [
45330
45750
  "app_mentions:read",
@@ -45418,7 +45838,7 @@ async function startSlackOAuth(opts) {
45418
45838
  throw new SlackOAuthCancelledError();
45419
45839
  }
45420
45840
  const { clientId } = slackOAuthCredentials();
45421
- const state = (0, import_node_crypto28.randomBytes)(16).toString("hex");
45841
+ const state = (0, import_node_crypto30.randomBytes)(16).toString("hex");
45422
45842
  const authorizeUrl = slackOAuthAuthorizeUrl(clientId, state);
45423
45843
  const timeoutMs = opts?.timeoutMs ?? 5 * 6e4;
45424
45844
  const pollIntervalMs = opts?.pollIntervalMs ?? 400;
@@ -46327,7 +46747,7 @@ function resolveSlackListenMode(opts) {
46327
46747
  init_protocol();
46328
46748
 
46329
46749
  // src/relay/account-login.ts
46330
- var import_node_crypto29 = require("crypto");
46750
+ var import_node_crypto31 = require("crypto");
46331
46751
  init_fetch();
46332
46752
  init_protocol();
46333
46753
  var RemoteAccountLoginCancelled = class extends Error {
@@ -46395,7 +46815,7 @@ async function readJson4(res, url) {
46395
46815
  async function startRemoteAccountLogin(opts) {
46396
46816
  if (opts.signal?.aborted) throw new RemoteAccountLoginCancelled();
46397
46817
  const origin = (opts.origin ?? remoteAccountHttpOrigin()).replace(/\/+$/, "");
46398
- const state = (0, import_node_crypto29.randomBytes)(16).toString("hex");
46818
+ const state = (0, import_node_crypto31.randomBytes)(16).toString("hex");
46399
46819
  const timeoutMs = opts.timeoutMs ?? 5 * 6e4;
46400
46820
  const pollIntervalMs = opts.pollIntervalMs ?? 400;
46401
46821
  const linkToken = opts.linkToken?.trim() ?? "";
@@ -47003,6 +47423,7 @@ async function pollSlackOutboundWatches(opts) {
47003
47423
  archiveRemovedWorkspaceChats,
47004
47424
  archivesWithRemovedWorkspace,
47005
47425
  armSchedules,
47426
+ askBlockStillWaiting,
47006
47427
  assertAbleTimeCredential,
47007
47428
  assertAbleTimeMcpCredential,
47008
47429
  assertOrchestratorCapableAgent,
@@ -47443,6 +47864,7 @@ async function pollSlackOutboundWatches(opts) {
47443
47864
  lastAgentReply,
47444
47865
  lastAssistantMessageText,
47445
47866
  lastRequestOccupancy,
47867
+ lastTopLevelToolIsAskUser,
47446
47868
  latestPendingPlanQuestions,
47447
47869
  linearAuthorizationHeader,
47448
47870
  linearCycleIsActive,
@@ -47789,6 +48211,7 @@ async function pollSlackOutboundWatches(opts) {
47789
48211
  startRelayServer,
47790
48212
  startRemoteAccountLogin,
47791
48213
  startSlackOAuth,
48214
+ stashMcpAppModelContext,
47792
48215
  statWorktreePath,
47793
48216
  stopAgentRpcServer,
47794
48217
  stripBrightsyNdjsonNoise,