@sideboard-ai/core 0.1.311 → 0.1.313

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.
@@ -10516,24 +10516,47 @@ var init_turn_trace = __esm({
10516
10516
  });
10517
10517
 
10518
10518
  // src/brightsy/config.ts
10519
+ function resolveBrightsyConfigFile(path) {
10520
+ try {
10521
+ if ((0, import_node_fs23.existsSync)(path) && (0, import_node_fs23.statSync)(path).isDirectory()) {
10522
+ return (0, import_node_path26.join)(path, "config.json");
10523
+ }
10524
+ } catch {
10525
+ }
10526
+ return path;
10527
+ }
10519
10528
  function brightsyConfigPath() {
10520
10529
  const override = process.env.BRIGHTSY_CONFIG?.trim();
10521
- if (override) return override;
10522
- return (0, import_node_path26.join)((0, import_node_os9.homedir)(), ".brightsy", "config.json");
10530
+ const raw = override || (0, import_node_path26.join)((0, import_node_os9.homedir)(), ".brightsy", "config.json");
10531
+ return resolveBrightsyConfigFile(raw);
10523
10532
  }
10524
10533
  function loadBrightsyConfig() {
10525
10534
  const path = brightsyConfigPath();
10526
10535
  if (!(0, import_node_fs23.existsSync)(path)) {
10527
10536
  throw new Error("Brightsy not logged in \u2014 run `brightsy login` first");
10528
10537
  }
10529
- const raw = JSON.parse((0, import_node_fs23.readFileSync)(path, "utf8"));
10538
+ let text7;
10539
+ try {
10540
+ text7 = (0, import_node_fs23.readFileSync)(path, "utf8");
10541
+ } catch (err) {
10542
+ const code = err && typeof err === "object" && "code" in err ? String(err.code) : "";
10543
+ if (code === "EISDIR") {
10544
+ throw new Error(
10545
+ `Brightsy config is a directory (${path}) \u2014 expected ~/.brightsy/config.json`
10546
+ );
10547
+ }
10548
+ throw err;
10549
+ }
10550
+ const raw = JSON.parse(text7);
10530
10551
  if (!raw.access_token || !raw.account_id) {
10531
10552
  throw new Error("Brightsy config incomplete \u2014 run `brightsy login`");
10532
10553
  }
10533
10554
  return raw;
10534
10555
  }
10535
10556
  function saveBrightsyConfig(cfg) {
10536
- (0, import_node_fs23.writeFileSync)(brightsyConfigPath(), `${JSON.stringify(cfg, null, 2)}
10557
+ const path = brightsyConfigPath();
10558
+ (0, import_node_fs23.mkdirSync)((0, import_node_path26.dirname)(path), { recursive: true });
10559
+ (0, import_node_fs23.writeFileSync)(path, `${JSON.stringify(cfg, null, 2)}
10537
10560
  `, {
10538
10561
  mode: 384
10539
10562
  });
@@ -10788,6 +10811,25 @@ function listConnectedBrightsyTeams() {
10788
10811
  expires_at
10789
10812
  }));
10790
10813
  }
10814
+ function teamFromCliSession(cfg, current) {
10815
+ return {
10816
+ ...current,
10817
+ access_token: cfg.access_token,
10818
+ refresh_token: cfg.refresh_token ?? current.refresh_token,
10819
+ expires_at: cfg.expires_at ?? current.expires_at,
10820
+ endpoint: cfg.endpoint ?? current.endpoint,
10821
+ oauth_client_id: cfg.oauth_client_id ?? current.oauth_client_id,
10822
+ slug: cfg.account_slug || current.slug
10823
+ };
10824
+ }
10825
+ function brightsySessionShouldReplace(a, b) {
10826
+ if (!a.access_token) return false;
10827
+ const aStale = brightsyAccessTokenNeedsRefresh(a.expires_at);
10828
+ const bStale = !b.access_token || brightsyAccessTokenNeedsRefresh(b.expires_at);
10829
+ if (!aStale && bStale) return true;
10830
+ if (aStale) return false;
10831
+ return (a.expires_at ?? 0) > (b.expires_at ?? 0);
10832
+ }
10791
10833
  function applyConnectedTeamToCli(team) {
10792
10834
  let base = {};
10793
10835
  try {
@@ -10874,22 +10916,34 @@ async function ensureConnectedBrightsyTeamTokens(opts) {
10874
10916
  }
10875
10917
  next.push(refreshed);
10876
10918
  }
10877
- if (changed) writeStore(next);
10878
10919
  try {
10879
10920
  const cfg2 = loadBrightsyConfig();
10880
- const active = next.find((t) => t.id === cfg2.account_id);
10881
- if (active && active.access_token !== cfg2.access_token) {
10882
- applyConnectedTeamToCli(active);
10921
+ const idx = next.findIndex((t) => t.id === cfg2.account_id);
10922
+ if (idx >= 0) {
10923
+ const active = next[idx];
10924
+ if (brightsySessionShouldReplace(cfg2, active)) {
10925
+ next[idx] = teamFromCliSession(cfg2, active);
10926
+ changed = true;
10927
+ } else if (active.access_token !== cfg2.access_token) {
10928
+ applyConnectedTeamToCli(active);
10929
+ }
10883
10930
  }
10884
10931
  } catch {
10885
10932
  }
10933
+ if (changed) writeStore(next);
10886
10934
  return next;
10887
10935
  }
10888
10936
  function ensureCliTeamTracked(meta) {
10889
10937
  try {
10890
10938
  const cfg = loadBrightsyConfig();
10891
10939
  const existing = readStore();
10892
- if (existing.some((t) => t.id === cfg.account_id)) {
10940
+ const idx = existing.findIndex((t) => t.id === cfg.account_id);
10941
+ if (idx >= 0) {
10942
+ const current = existing[idx];
10943
+ if (brightsySessionShouldReplace(cfg, current)) {
10944
+ existing[idx] = teamFromCliSession(cfg, current);
10945
+ writeStore(existing);
10946
+ }
10893
10947
  return listConnectedBrightsyTeams();
10894
10948
  }
10895
10949
  const team = {
@@ -11332,6 +11386,19 @@ var init_brightsy = __esm({
11332
11386
  });
11333
11387
 
11334
11388
  // src/mcp-ui/meta.ts
11389
+ function matchClaudeMcpTool(toolName, serverNames) {
11390
+ const name = toolName.trim();
11391
+ if (!name.startsWith("mcp__")) return null;
11392
+ const ranked = [...serverNames].filter((s) => s.trim()).sort((a, b) => b.length - a.length);
11393
+ for (const server of ranked) {
11394
+ const prefix = `mcp__${server}__`;
11395
+ if (!name.startsWith(prefix)) continue;
11396
+ const tool = name.slice(prefix.length).trim();
11397
+ if (!tool) continue;
11398
+ return { server, tool };
11399
+ }
11400
+ return null;
11401
+ }
11335
11402
  function parseMcpServerLaunch(entry) {
11336
11403
  const command = typeof entry.command === "string" ? entry.command.trim() : "";
11337
11404
  if (command) {
@@ -11363,6 +11430,105 @@ function parseMcpServerLaunch(entry) {
11363
11430
  ...headers ? { headers } : {}
11364
11431
  };
11365
11432
  }
11433
+ function uiResourceUriFromMeta(meta) {
11434
+ const rec = asRecord3(meta);
11435
+ const nested = asRecord3(rec.ui);
11436
+ const fromNested = typeof nested.resourceUri === "string" ? nested.resourceUri.trim() : "";
11437
+ const legacy = typeof rec["ui/resourceUri"] === "string" ? rec["ui/resourceUri"].trim() : "";
11438
+ const uri = fromNested || legacy;
11439
+ return uri.startsWith("ui://") ? uri : null;
11440
+ }
11441
+ function cspFromMeta(meta) {
11442
+ const ui = asRecord3(asRecord3(meta).ui);
11443
+ const csp = asRecord3(ui.csp);
11444
+ const connectDomains = originList(csp.connectDomains);
11445
+ const resourceDomains = originList(csp.resourceDomains);
11446
+ const frameDomains = originList(csp.frameDomains);
11447
+ const baseUriDomains = originList(csp.baseUriDomains);
11448
+ if (!connectDomains?.length && !resourceDomains?.length && !frameDomains?.length && !baseUriDomains?.length) {
11449
+ return void 0;
11450
+ }
11451
+ return {
11452
+ ...connectDomains?.length ? { connectDomains } : {},
11453
+ ...resourceDomains?.length ? { resourceDomains } : {},
11454
+ ...frameDomains?.length ? { frameDomains } : {},
11455
+ ...baseUriDomains?.length ? { baseUriDomains } : {}
11456
+ };
11457
+ }
11458
+ function htmlFromResourceContent(content) {
11459
+ const uri = content.uri?.trim() ?? "";
11460
+ if (!uri.startsWith("ui://")) return null;
11461
+ const mimeType = content.mimeType?.trim() || "text/html";
11462
+ if (!isHtmlMime(mimeType)) return null;
11463
+ const html = htmlText(content.text, content.blob);
11464
+ if (!html) return null;
11465
+ return { uri, mimeType, html };
11466
+ }
11467
+ function mcpUiContentSecurityPolicy(csp) {
11468
+ const resource = (csp?.resourceDomains ?? []).join(" ");
11469
+ const connect = (csp?.connectDomains ?? []).join(" ");
11470
+ const frames = csp?.frameDomains?.length ? csp.frameDomains.join(" ") : "'none'";
11471
+ const base = csp?.baseUriDomains?.length ? csp.baseUriDomains.join(" ") : "'none'";
11472
+ const connectSrc = connect ? `'self' ${connect}`.trim() : "'none'";
11473
+ return [
11474
+ "default-src 'none'",
11475
+ `script-src 'self' 'unsafe-inline' ${resource}`.trim(),
11476
+ `style-src 'self' 'unsafe-inline' ${resource}`.trim(),
11477
+ `img-src 'self' data: ${resource}`.trim(),
11478
+ `font-src 'self' ${resource}`.trim(),
11479
+ `connect-src ${connectSrc}`,
11480
+ `media-src 'self' data: ${resource}`.trim(),
11481
+ `frame-src ${frames}`,
11482
+ `base-uri ${base}`,
11483
+ "object-src 'none'"
11484
+ ].join("; ");
11485
+ }
11486
+ function htmlText(text7, blob) {
11487
+ if (typeof text7 === "string" && text7.trim()) {
11488
+ return text7.length <= HTML_MAX ? text7 : null;
11489
+ }
11490
+ if (typeof blob !== "string" || !blob.trim()) return null;
11491
+ try {
11492
+ const decoded = decodeBase64(blob.trim());
11493
+ if (!decoded.trim() || decoded.length > HTML_MAX) return null;
11494
+ return decoded;
11495
+ } catch {
11496
+ return null;
11497
+ }
11498
+ }
11499
+ function decodeBase64(blob) {
11500
+ if (typeof Buffer !== "undefined") return Buffer.from(blob, "base64").toString("utf8");
11501
+ const bin = atob(blob);
11502
+ const bytes = Uint8Array.from(bin, (c) => c.charCodeAt(0));
11503
+ return new TextDecoder().decode(bytes);
11504
+ }
11505
+ function isHtmlMime(mime) {
11506
+ const base = mime.split(";")[0]?.trim().toLowerCase() ?? "";
11507
+ return base === "text/html";
11508
+ }
11509
+ function originList(value) {
11510
+ if (!Array.isArray(value)) return void 0;
11511
+ const out = [];
11512
+ for (const item of value) {
11513
+ if (typeof item !== "string") continue;
11514
+ const origin = originToken(item);
11515
+ if (origin && !out.includes(origin)) out.push(origin);
11516
+ }
11517
+ return out;
11518
+ }
11519
+ function originToken(value) {
11520
+ const trimmed = value.trim();
11521
+ if (/^(https?|wss?):\/\/\*\.[a-z0-9.-]+(?::\d+)?$/i.test(trimmed)) return trimmed;
11522
+ try {
11523
+ const url = new URL(trimmed);
11524
+ if (url.protocol !== "https:" && url.protocol !== "http:" && url.protocol !== "wss:" && url.protocol !== "ws:") {
11525
+ return null;
11526
+ }
11527
+ return url.origin;
11528
+ } catch {
11529
+ return null;
11530
+ }
11531
+ }
11366
11532
  function stringRecord(value) {
11367
11533
  const rec = asRecord3(value);
11368
11534
  const out = {};
@@ -11375,9 +11541,11 @@ function asRecord3(value) {
11375
11541
  if (!value || typeof value !== "object" || Array.isArray(value)) return {};
11376
11542
  return value;
11377
11543
  }
11544
+ var HTML_MAX;
11378
11545
  var init_meta = __esm({
11379
11546
  "src/mcp-ui/meta.ts"() {
11380
11547
  "use strict";
11548
+ HTML_MAX = 15e5;
11381
11549
  }
11382
11550
  });
11383
11551
 
@@ -12416,6 +12584,519 @@ var init_orch_mcp_isolation = __esm({
12416
12584
  }
12417
12585
  });
12418
12586
 
12587
+ // src/mcp-ui/visibility.ts
12588
+ function visibilityFromMeta(meta) {
12589
+ const rec = asRecord4(meta);
12590
+ const ui = asRecord4(rec.ui);
12591
+ const raw = ui.visibility;
12592
+ if (!Array.isArray(raw)) return ["model", "app"];
12593
+ const out = [];
12594
+ for (const item of raw) {
12595
+ if (item !== "model" && item !== "app") continue;
12596
+ if (!out.includes(item)) out.push(item);
12597
+ }
12598
+ return out.length ? out : ["model", "app"];
12599
+ }
12600
+ function toolVisibleTo(visibility, audience) {
12601
+ const vis = visibility?.length ? visibility : ["model", "app"];
12602
+ return vis.includes(audience);
12603
+ }
12604
+ function asRecord4(value) {
12605
+ if (!value || typeof value !== "object" || Array.isArray(value)) return {};
12606
+ return value;
12607
+ }
12608
+ var init_visibility = __esm({
12609
+ "src/mcp-ui/visibility.ts"() {
12610
+ "use strict";
12611
+ }
12612
+ });
12613
+
12614
+ // src/mcp-ui/proxy-server.ts
12615
+ function attachMcpUiProxyHandlers(server, session) {
12616
+ server.setRequestHandler(import_types.ListToolsRequestSchema, async () => {
12617
+ const tools = await session.listTools();
12618
+ return { tools: tools.filter((tool) => toolVisibleTo(tool.visibility, "model")).map(listedTool) };
12619
+ });
12620
+ server.setRequestHandler(import_types.CallToolRequestSchema, async (request) => {
12621
+ const name = request.params.name;
12622
+ const tools = await session.listTools();
12623
+ const tool = tools.find((item) => item.name === name);
12624
+ if (!tool || !toolVisibleTo(tool.visibility, "model")) {
12625
+ throw new Error(`Tool ${name} is not available to the model`);
12626
+ }
12627
+ return await session.callTool(name, request.params.arguments ?? {});
12628
+ });
12629
+ server.setRequestHandler(import_types.ReadResourceRequestSchema, async (request) => {
12630
+ const resource = await session.readResource(request.params.uri);
12631
+ if (!resource) throw new Error(`Resource ${request.params.uri} was empty`);
12632
+ return {
12633
+ contents: [
12634
+ {
12635
+ uri: resource.uri,
12636
+ ...resource.mimeType ? { mimeType: resource.mimeType } : {},
12637
+ ...resource.text != null ? { text: resource.text } : {},
12638
+ ...resource.blob != null ? { blob: resource.blob } : {}
12639
+ }
12640
+ ]
12641
+ };
12642
+ });
12643
+ server.setRequestHandler(import_types.ListResourcesRequestSchema, async () => session.listResources());
12644
+ server.setRequestHandler(
12645
+ import_types.ListResourceTemplatesRequestSchema,
12646
+ async () => session.listResourceTemplates()
12647
+ );
12648
+ server.setRequestHandler(import_types.ListPromptsRequestSchema, async () => session.listPrompts());
12649
+ server.setRequestHandler(import_types.GetPromptRequestSchema, async (request) => {
12650
+ return await session.getPrompt(request.params.name, request.params.arguments);
12651
+ });
12652
+ server.fallbackRequestHandler = async (request) => {
12653
+ return await session.forward(request.method, request.params);
12654
+ };
12655
+ }
12656
+ function listedTool(tool) {
12657
+ return {
12658
+ name: tool.name,
12659
+ ...tool.description ? { description: tool.description } : {},
12660
+ inputSchema: tool.inputSchema ?? { type: "object", properties: {} },
12661
+ _meta: {
12662
+ ui: {
12663
+ ...tool.resourceUri ? { resourceUri: tool.resourceUri } : {},
12664
+ visibility: tool.visibility
12665
+ }
12666
+ }
12667
+ };
12668
+ }
12669
+ var import_server, import_types;
12670
+ var init_proxy_server = __esm({
12671
+ "src/mcp-ui/proxy-server.ts"() {
12672
+ "use strict";
12673
+ import_server = require("@modelcontextprotocol/sdk/server/index.js");
12674
+ import_types = require("@modelcontextprotocol/sdk/types.js");
12675
+ init_visibility();
12676
+ }
12677
+ });
12678
+
12679
+ // src/mcp-ui/proxy-http.ts
12680
+ async function listenMcpUiProxy(opts) {
12681
+ const token = (0, import_node_crypto6.randomBytes)(24).toString("hex");
12682
+ const transports = /* @__PURE__ */ new Map();
12683
+ const httpServer = (0, import_node_http.createServer)((req, res) => {
12684
+ void handle(req, res);
12685
+ });
12686
+ await new Promise((resolve3, reject) => {
12687
+ httpServer.once("error", reject);
12688
+ httpServer.listen(0, "127.0.0.1", () => resolve3());
12689
+ });
12690
+ const addr = httpServer.address();
12691
+ if (!addr || typeof addr === "string") throw new Error("mcp-ui proxy failed to bind");
12692
+ const origin = `http://127.0.0.1:${addr.port}`;
12693
+ async function handle(req, res) {
12694
+ if (req.headers.authorization !== `Bearer ${token}`) {
12695
+ res.writeHead(401).end();
12696
+ return;
12697
+ }
12698
+ const target = parseMcpUiProxyPath(req.url);
12699
+ if (!target) {
12700
+ res.writeHead(404).end();
12701
+ return;
12702
+ }
12703
+ try {
12704
+ const session = await opts.sessionFor(target.server, target.dirsKey);
12705
+ if (!session) {
12706
+ res.writeHead(404).end();
12707
+ return;
12708
+ }
12709
+ const header = req.headers["mcp-session-id"];
12710
+ const sid = typeof header === "string" ? header : "";
12711
+ const sessionKey = `${target.server}:${target.dirsKey}`;
12712
+ let transport = sid ? transports.get(`${sessionKey}:${sid}`) : void 0;
12713
+ if (!transport) {
12714
+ if (req.method !== "POST") {
12715
+ res.writeHead(400).end();
12716
+ return;
12717
+ }
12718
+ const created = new import_streamableHttp.StreamableHTTPServerTransport({
12719
+ sessionIdGenerator: () => (0, import_node_crypto6.randomUUID)(),
12720
+ allowedHosts: ["127.0.0.1", "localhost"],
12721
+ onsessioninitialized: (id) => {
12722
+ transports.set(`${sessionKey}:${id}`, created);
12723
+ },
12724
+ onsessionclosed: (id) => {
12725
+ transports.delete(`${sessionKey}:${id}`);
12726
+ }
12727
+ });
12728
+ transport = created;
12729
+ const mcp = new import_server2.Server(
12730
+ { name: `sideboard-ui-proxy-${target.server}`, version: "1.0.0" },
12731
+ { capabilities: session.capabilities() }
12732
+ );
12733
+ attachMcpUiProxyHandlers(mcp, session);
12734
+ await mcp.connect(created);
12735
+ }
12736
+ await transport.handleRequest(req, res);
12737
+ } catch {
12738
+ if (!res.headersSent) res.writeHead(500).end();
12739
+ }
12740
+ }
12741
+ return {
12742
+ urlFor(server, dirsKey) {
12743
+ const base = `${origin}/s/${encodeURIComponent(server)}`;
12744
+ return dirsKey ? `${base}/d/${dirsKey}` : base;
12745
+ },
12746
+ headers: { Authorization: `Bearer ${token}` },
12747
+ async close() {
12748
+ await Promise.all([...transports.values()].map((item) => item.close().catch(() => void 0)));
12749
+ transports.clear();
12750
+ await new Promise((resolve3) => httpServer.close(() => resolve3()));
12751
+ }
12752
+ };
12753
+ }
12754
+ function parseMcpUiProxyPath(url) {
12755
+ const path = (url ?? "").split("?")[0] ?? "";
12756
+ if (!path.startsWith("/s/")) return null;
12757
+ const rest = path.slice(3).replace(/\/$/, "");
12758
+ const split = rest.indexOf("/d/");
12759
+ try {
12760
+ if (split < 0) {
12761
+ const server2 = decodeURIComponent(rest).trim();
12762
+ return server2 ? { server: server2, dirsKey: "" } : null;
12763
+ }
12764
+ const server = decodeURIComponent(rest.slice(0, split)).trim();
12765
+ const dirsKey = rest.slice(split + 3);
12766
+ if (!server || !/^[a-f0-9]{16}$/.test(dirsKey)) return null;
12767
+ return { server, dirsKey };
12768
+ } catch {
12769
+ return null;
12770
+ }
12771
+ }
12772
+ var import_node_crypto6, import_node_http, import_server2, import_streamableHttp;
12773
+ var init_proxy_http = __esm({
12774
+ "src/mcp-ui/proxy-http.ts"() {
12775
+ "use strict";
12776
+ import_node_crypto6 = require("crypto");
12777
+ import_node_http = require("http");
12778
+ import_server2 = require("@modelcontextprotocol/sdk/server/index.js");
12779
+ import_streamableHttp = require("@modelcontextprotocol/sdk/server/streamableHttp.js");
12780
+ init_proxy_server();
12781
+ }
12782
+ });
12783
+
12784
+ // src/mcp-ui/session.ts
12785
+ async function orEmpty(run2, fallback) {
12786
+ try {
12787
+ return await run2();
12788
+ } catch {
12789
+ return fallback;
12790
+ }
12791
+ }
12792
+ async function openMcpUiSession(launch) {
12793
+ return openMcpUiSessionFromTransport(transportForLaunch(launch));
12794
+ }
12795
+ async function openMcpUiSessionFromTransport(transport) {
12796
+ const client = new import_client.Client(
12797
+ { name: "sideboard", version: "1.0.0" },
12798
+ { capabilities: UI_CAPABILITIES }
12799
+ );
12800
+ await client.connect(transport, { timeout: REQUEST_TIMEOUT_MS });
12801
+ return {
12802
+ async listTools() {
12803
+ const listed = await client.listTools(void 0, { timeout: REQUEST_TIMEOUT_MS });
12804
+ return listed.tools.map((tool) => {
12805
+ const meta = tool._meta;
12806
+ return {
12807
+ name: tool.name,
12808
+ ...tool.description ? { description: tool.description } : {},
12809
+ ...tool.inputSchema ? { inputSchema: tool.inputSchema } : {},
12810
+ resourceUri: uiResourceUriFromMeta(meta),
12811
+ visibility: visibilityFromMeta(meta),
12812
+ ...cspFromMeta(meta) ? { csp: cspFromMeta(meta) } : {}
12813
+ };
12814
+ });
12815
+ },
12816
+ listResources: () => orEmpty(
12817
+ () => client.listResources(void 0, { timeout: REQUEST_TIMEOUT_MS }),
12818
+ { resources: [] }
12819
+ ),
12820
+ listResourceTemplates: () => orEmpty(
12821
+ () => client.listResourceTemplates(void 0, { timeout: REQUEST_TIMEOUT_MS }),
12822
+ { resourceTemplates: [] }
12823
+ ),
12824
+ listPrompts: () => orEmpty(
12825
+ () => client.listPrompts(void 0, { timeout: REQUEST_TIMEOUT_MS }),
12826
+ { prompts: [] }
12827
+ ),
12828
+ getPrompt(name, args) {
12829
+ return client.getPrompt({ name, arguments: args }, { timeout: REQUEST_TIMEOUT_MS });
12830
+ },
12831
+ async readResource(uri) {
12832
+ const result = await client.readResource({ uri }, { timeout: REQUEST_TIMEOUT_MS });
12833
+ const content = result.contents?.[0];
12834
+ if (!content) return null;
12835
+ const text7 = "text" in content && typeof content.text === "string" ? content.text : void 0;
12836
+ const blob = "blob" in content && typeof content.blob === "string" ? content.blob : void 0;
12837
+ return {
12838
+ uri: content.uri,
12839
+ ...content.mimeType ? { mimeType: content.mimeType } : {},
12840
+ ...text7 != null ? { text: text7 } : {},
12841
+ ...blob != null ? { blob } : {},
12842
+ ...cspFromMeta(content._meta) ? { csp: cspFromMeta(content._meta) } : {}
12843
+ };
12844
+ },
12845
+ async callTool(name, args) {
12846
+ return client.callTool({ name, arguments: args }, void 0, { timeout: REQUEST_TIMEOUT_MS });
12847
+ },
12848
+ capabilities() {
12849
+ const caps = client.getServerCapabilities() ?? {};
12850
+ return {
12851
+ tools: caps.tools ?? {},
12852
+ resources: caps.resources ?? {},
12853
+ prompts: caps.prompts ?? {},
12854
+ completions: caps.completions ?? {},
12855
+ ...caps.logging ? { logging: caps.logging } : {}
12856
+ };
12857
+ },
12858
+ forward(method, params) {
12859
+ return client.request(
12860
+ { method, params },
12861
+ import_types2.ResultSchema,
12862
+ { timeout: REQUEST_TIMEOUT_MS }
12863
+ );
12864
+ },
12865
+ async close() {
12866
+ await client.close();
12867
+ }
12868
+ };
12869
+ }
12870
+ function transportForLaunch(launch) {
12871
+ if (launch.kind === "stdio") {
12872
+ return new import_stdio.StdioClientTransport({
12873
+ command: launch.command,
12874
+ args: launch.args,
12875
+ env: { ...(0, import_stdio.getDefaultEnvironment)(), ...launch.env },
12876
+ stderr: "ignore",
12877
+ ...launch.cwd ? { cwd: launch.cwd } : {}
12878
+ });
12879
+ }
12880
+ const url = new URL(launch.url);
12881
+ const requestInit = launch.headers ? { headers: launch.headers } : void 0;
12882
+ if (launch.kind === "sse") {
12883
+ return new import_sse.SSEClientTransport(url, requestInit ? { requestInit } : void 0);
12884
+ }
12885
+ return new import_streamableHttp2.StreamableHTTPClientTransport(url, requestInit ? { requestInit } : void 0);
12886
+ }
12887
+ var import_client, import_sse, import_stdio, import_streamableHttp2, import_types2, REQUEST_TIMEOUT_MS, UI_CAPABILITIES;
12888
+ var init_session = __esm({
12889
+ "src/mcp-ui/session.ts"() {
12890
+ "use strict";
12891
+ import_client = require("@modelcontextprotocol/sdk/client/index.js");
12892
+ import_sse = require("@modelcontextprotocol/sdk/client/sse.js");
12893
+ import_stdio = require("@modelcontextprotocol/sdk/client/stdio.js");
12894
+ import_streamableHttp2 = require("@modelcontextprotocol/sdk/client/streamableHttp.js");
12895
+ import_types2 = require("@modelcontextprotocol/sdk/types.js");
12896
+ init_meta();
12897
+ init_visibility();
12898
+ REQUEST_TIMEOUT_MS = 2e4;
12899
+ UI_CAPABILITIES = {
12900
+ extensions: {
12901
+ "io.modelcontextprotocol/ui": {
12902
+ mimeTypes: ["text/html;profile=mcp-app"]
12903
+ }
12904
+ }
12905
+ };
12906
+ }
12907
+ });
12908
+
12909
+ // src/mcp-ui/host.ts
12910
+ function getMcpUiHost() {
12911
+ if (!singleton) {
12912
+ singleton = new McpUiHost({
12913
+ entries: (projectDirs) => listUserClaudeMcpServerEntries((0, import_node_os15.homedir)(), projectDirs)
12914
+ });
12915
+ }
12916
+ return singleton;
12917
+ }
12918
+ async function proxyClaudeUserMcp(orchestrator, projectDirs) {
12919
+ if (orchestrator) return {};
12920
+ const dirs = projectDirs.filter((d) => typeof d === "string" && d.length > 0);
12921
+ return getMcpUiHost().proxyEntries(listUserClaudeMcpServerEntries((0, import_node_os15.homedir)(), dirs), dirs);
12922
+ }
12923
+ function dirsKeyFor(projectDirs) {
12924
+ if (!projectDirs?.length) return "";
12925
+ return (0, import_node_crypto7.createHash)("sha256").update(projectDirs.join("\0")).digest("hex").slice(0, 16);
12926
+ }
12927
+ var import_node_crypto7, import_node_os15, TOOL_TTL_MS, McpUiHost, singleton;
12928
+ var init_host = __esm({
12929
+ "src/mcp-ui/host.ts"() {
12930
+ "use strict";
12931
+ import_node_crypto7 = require("crypto");
12932
+ import_node_os15 = require("os");
12933
+ init_orch_mcp_isolation();
12934
+ init_meta();
12935
+ init_proxy_http();
12936
+ init_session();
12937
+ init_visibility();
12938
+ TOOL_TTL_MS = 5 * 60 * 1e3;
12939
+ McpUiHost = class {
12940
+ constructor(opts) {
12941
+ this.opts = opts;
12942
+ }
12943
+ opts;
12944
+ sessions = /* @__PURE__ */ new Map();
12945
+ toolLists = /* @__PURE__ */ new Map();
12946
+ proxy;
12947
+ proxyDirs = /* @__PURE__ */ new Map();
12948
+ async viewForClaudeTool(toolName, projectDirs) {
12949
+ const entries = this.userEntries(projectDirs);
12950
+ const match = matchClaudeMcpTool(toolName, Object.keys(entries));
12951
+ if (!match) return null;
12952
+ const launch = parseMcpServerLaunch(entries[match.server] ?? {});
12953
+ if (!launch) return null;
12954
+ try {
12955
+ const session = await this.sessionFor(match.server, launch);
12956
+ const tools = await this.toolsFor(match.server, launch, session);
12957
+ const tool = tools.find((item) => item.name === match.tool);
12958
+ if (!tool?.resourceUri) return null;
12959
+ const resource = await session.readResource(tool.resourceUri);
12960
+ if (!resource) return null;
12961
+ const html = htmlFromResourceContent(resource);
12962
+ if (!html) return null;
12963
+ const csp = resource.csp ?? tool.csp;
12964
+ return {
12965
+ server: match.server,
12966
+ tool: match.tool,
12967
+ uri: html.uri,
12968
+ mimeType: html.mimeType,
12969
+ html: html.html,
12970
+ csp: mcpUiContentSecurityPolicy(csp)
12971
+ };
12972
+ } catch (err) {
12973
+ console.error(
12974
+ `[mcp-ui] ${match.server}/${match.tool}:`,
12975
+ err instanceof Error ? err.message : err
12976
+ );
12977
+ return null;
12978
+ }
12979
+ }
12980
+ /**
12981
+ * Point Claude at loopback HTTP so it shares this host's upstream session
12982
+ * and never sees `visibility: ["app"]` tools.
12983
+ */
12984
+ async proxyEntries(entries, projectDirs) {
12985
+ const names = Object.keys(entries).filter((name) => name.trim());
12986
+ if (names.length === 0) return {};
12987
+ const dirsKey = dirsKeyFor(projectDirs);
12988
+ this.proxyDirs.set(dirsKey, projectDirs);
12989
+ try {
12990
+ const listen = await this.ensureProxy();
12991
+ const out = {};
12992
+ for (const name of names) {
12993
+ out[name] = {
12994
+ type: "http",
12995
+ url: listen.urlFor(name, dirsKey),
12996
+ headers: listen.headers
12997
+ };
12998
+ }
12999
+ return out;
13000
+ } catch (err) {
13001
+ console.error("[mcp-ui] proxy:", err instanceof Error ? err.message : err);
13002
+ return { ...entries };
13003
+ }
13004
+ }
13005
+ async callTool(server, tool, args, projectDirs) {
13006
+ const entry = this.userEntries(projectDirs)[server];
13007
+ if (!entry) throw new Error(`MCP server ${server} is not available`);
13008
+ const launch = parseMcpServerLaunch(entry);
13009
+ if (!launch) throw new Error(`MCP server ${server} is not available`);
13010
+ const session = await this.sessionFor(server, launch);
13011
+ const tools = await this.toolsFor(server, launch, session);
13012
+ const info = tools.find((item) => item.name === tool);
13013
+ if (!info || !toolVisibleTo(info.visibility, "app")) {
13014
+ throw new Error(`Tool ${tool} is not available to the app`);
13015
+ }
13016
+ return session.callTool(tool, args);
13017
+ }
13018
+ async readResource(server, uri, projectDirs) {
13019
+ const session = await this.sessionForName(server, projectDirs);
13020
+ if (!session) throw new Error(`MCP server ${server} is not available`);
13021
+ const resource = await session.readResource(uri);
13022
+ if (!resource) throw new Error(`Resource ${uri} was empty`);
13023
+ return {
13024
+ contents: [
13025
+ {
13026
+ uri: resource.uri,
13027
+ ...resource.mimeType ? { mimeType: resource.mimeType } : {},
13028
+ ...resource.text != null ? { text: resource.text } : {},
13029
+ ...resource.blob != null ? { blob: resource.blob } : {}
13030
+ }
13031
+ ]
13032
+ };
13033
+ }
13034
+ async closeAll() {
13035
+ const pending = [...this.sessions.values()];
13036
+ const proxy = this.proxy;
13037
+ this.sessions.clear();
13038
+ this.toolLists.clear();
13039
+ this.proxyDirs.clear();
13040
+ this.proxy = void 0;
13041
+ await Promise.all([
13042
+ ...pending.map((session) => session.then((open) => open.close()).catch(() => void 0)),
13043
+ proxy ? proxy.then((listen) => listen.close()).catch(() => void 0) : Promise.resolve()
13044
+ ]);
13045
+ }
13046
+ ensureProxy() {
13047
+ if (this.proxy) return this.proxy;
13048
+ this.proxy = listenMcpUiProxy({
13049
+ sessionFor: (server, dirsKey) => {
13050
+ if (dirsKey && !this.proxyDirs.has(dirsKey)) return Promise.resolve(null);
13051
+ return this.sessionForName(server, this.proxyDirs.get(dirsKey));
13052
+ }
13053
+ }).catch((err) => {
13054
+ this.proxy = void 0;
13055
+ throw err;
13056
+ });
13057
+ return this.proxy;
13058
+ }
13059
+ userEntries(projectDirs) {
13060
+ const out = {};
13061
+ for (const [name, entry] of Object.entries(this.opts.entries(projectDirs))) {
13062
+ if (!name.trim() || isInjectedOrchMcpName(name) || !entry) continue;
13063
+ out[name] = entry;
13064
+ }
13065
+ return out;
13066
+ }
13067
+ async sessionForName(server, projectDirs) {
13068
+ const entry = this.userEntries(projectDirs)[server];
13069
+ if (!entry) return null;
13070
+ const launch = parseMcpServerLaunch(entry);
13071
+ if (!launch) return null;
13072
+ return this.sessionFor(server, launch);
13073
+ }
13074
+ sessionFor(server, launch) {
13075
+ const key = `${server}
13076
+ ${JSON.stringify(launch)}`;
13077
+ const existing = this.sessions.get(key);
13078
+ if (existing) return existing;
13079
+ const open = this.opts.openSession ?? openMcpUiSession;
13080
+ const pending = open(launch).catch((err) => {
13081
+ this.sessions.delete(key);
13082
+ throw err;
13083
+ });
13084
+ this.sessions.set(key, pending);
13085
+ return pending;
13086
+ }
13087
+ async toolsFor(server, launch, session) {
13088
+ const key = `${server}
13089
+ ${JSON.stringify(launch)}`;
13090
+ const cached = this.toolLists.get(key);
13091
+ if (cached && cached.key === key && Date.now() - cached.at < TOOL_TTL_MS) return cached.tools;
13092
+ const tools = await session.listTools();
13093
+ this.toolLists.set(key, { at: Date.now(), key, tools });
13094
+ return tools;
13095
+ }
13096
+ };
13097
+ }
13098
+ });
13099
+
12419
13100
  // src/agents/types.ts
12420
13101
  function planModeTurnInstruction(planMode) {
12421
13102
  return planMode ? PLAN_MODE_INSTRUCTION : PLAN_MODE_OFF_INSTRUCTION;
@@ -12596,7 +13277,7 @@ function entryDir() {
12596
13277
  const cjsDir = typeof __dirname !== "undefined" ? __dirname : "";
12597
13278
  if (cjsDir) return cjsDir;
12598
13279
  try {
12599
- return (0, import_node_path35.dirname)((0, import_node_url2.fileURLToPath)(import_meta3.url));
13280
+ return (0, import_node_path35.dirname)((0, import_node_url2.fileURLToPath)(import_meta5.url));
12600
13281
  } catch {
12601
13282
  try {
12602
13283
  const req = (0, import_node_module2.createRequire)(process.cwd() + "/");
@@ -12646,7 +13327,7 @@ async function buildClaudeRpcTurnCommand(req) {
12646
13327
  }
12647
13328
  };
12648
13329
  }
12649
- var import_node_fs33, import_node_module2, import_node_path35, import_node_url2, import_meta3;
13330
+ var import_node_fs33, import_node_module2, import_node_path35, import_node_url2, import_meta5;
12650
13331
  var init_claude_host = __esm({
12651
13332
  "src/agents/claude-host.ts"() {
12652
13333
  "use strict";
@@ -12658,7 +13339,7 @@ var init_claude_host = __esm({
12658
13339
  init_pilot_tools();
12659
13340
  init_node_launch();
12660
13341
  init_packaged_runtime();
12661
- import_meta3 = {};
13342
+ import_meta5 = {};
12662
13343
  }
12663
13344
  });
12664
13345
 
@@ -13061,16 +13742,15 @@ function parseIssuesJson(raw) {
13061
13742
  }
13062
13743
  return [];
13063
13744
  }
13064
- var import_node_fs34, import_node_os15, CLAUDE_PROMPT_ARG_MAX, claudeAdapter;
13745
+ var import_node_fs34, CLAUDE_PROMPT_ARG_MAX, claudeAdapter;
13065
13746
  var init_claude = __esm({
13066
13747
  "src/agents/claude.ts"() {
13067
13748
  "use strict";
13068
13749
  import_node_fs34 = require("fs");
13069
- import_node_os15 = require("os");
13070
13750
  init_run();
13071
13751
  init_app_settings();
13072
13752
  init_claude_mcp();
13073
- init_orch_mcp_isolation();
13753
+ init_host();
13074
13754
  init_error_detail();
13075
13755
  init_message_parts();
13076
13756
  init_injected_mcp();
@@ -13147,7 +13827,7 @@ var init_claude = __esm({
13147
13827
  });
13148
13828
  const injectedBrightsyNames = injectedServers.filter((s) => s.name === "brightsy" || s.name.startsWith("brightsy_")).map((s) => s.name);
13149
13829
  const chromeOn = claudeChromeEnabled();
13150
- const userMcpEntries = isOrchestrator ? {} : listUserClaudeMcpServerEntries((0, import_node_os15.homedir)(), [thread.repoPath, thread.worktreePath]);
13830
+ const userMcpEntries = await proxyClaudeUserMcp(isOrchestrator, [thread.repoPath, thread.worktreePath]);
13151
13831
  let allowedTools;
13152
13832
  if (isOrchestrator) {
13153
13833
  allowedTools = [
@@ -13449,7 +14129,7 @@ function unwrapCodexMcpResult(result) {
13449
14129
  return String(result);
13450
14130
  }
13451
14131
  }
13452
- function asRecord4(value) {
14132
+ function asRecord5(value) {
13453
14133
  if (value && typeof value === "object" && !Array.isArray(value)) {
13454
14134
  return value;
13455
14135
  }
@@ -13629,7 +14309,7 @@ var init_codex = __esm({
13629
14309
  }
13630
14310
  if (itemType === "mcp_tool_call" && item.id && item.server && item.tool) {
13631
14311
  const name = `mcp__${item.server}__${item.tool}`;
13632
- const input = asRecord4(item.arguments);
14312
+ const input = asRecord5(item.arguments);
13633
14313
  const events = [
13634
14314
  { type: "tool_use", id: item.id, name, input }
13635
14315
  ];
@@ -13776,7 +14456,7 @@ function thisModuleFile() {
13776
14456
  const cjsDir = typeof __dirname !== "undefined" ? __dirname : "";
13777
14457
  if (cjsDir) return (0, import_node_path37.join)(cjsDir, "cursor-sdk-resolve.js");
13778
14458
  try {
13779
- return (0, import_node_url3.fileURLToPath)(import_meta4.url);
14459
+ return (0, import_node_url3.fileURLToPath)(import_meta6.url);
13780
14460
  } catch {
13781
14461
  return (0, import_node_path37.join)(process.cwd(), "package.json");
13782
14462
  }
@@ -13875,7 +14555,7 @@ function cursorSdkRipgrepCandidate(opts) {
13875
14555
  const nested = (0, import_node_path37.join)(root, "node_modules", pkg, "bin", bin);
13876
14556
  return (0, import_node_fs36.existsSync)(nested) ? nested : null;
13877
14557
  }
13878
- var import_node_fs36, import_node_module3, import_node_path37, import_node_url3, import_meta4, CURSOR_SDK_INSTALL_HINT;
14558
+ var import_node_fs36, import_node_module3, import_node_path37, import_node_url3, import_meta6, CURSOR_SDK_INSTALL_HINT;
13879
14559
  var init_cursor_sdk_resolve = __esm({
13880
14560
  "src/agents/cursor-sdk-resolve.ts"() {
13881
14561
  "use strict";
@@ -13884,7 +14564,7 @@ var init_cursor_sdk_resolve = __esm({
13884
14564
  import_node_path37 = require("path");
13885
14565
  import_node_url3 = require("url");
13886
14566
  init_path();
13887
- import_meta4 = {};
14567
+ import_meta6 = {};
13888
14568
  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.";
13889
14569
  }
13890
14570
  });
@@ -14019,7 +14699,7 @@ function entryDir2() {
14019
14699
  const cjsDir = typeof __dirname !== "undefined" ? __dirname : "";
14020
14700
  if (cjsDir) return cjsDir;
14021
14701
  try {
14022
- return (0, import_node_path39.dirname)((0, import_node_url4.fileURLToPath)(import_meta5.url));
14702
+ return (0, import_node_path39.dirname)((0, import_node_url4.fileURLToPath)(import_meta7.url));
14023
14703
  } catch {
14024
14704
  try {
14025
14705
  const req = (0, import_node_module5.createRequire)(process.cwd() + "/");
@@ -14048,7 +14728,7 @@ function cursorRunnerPath() {
14048
14728
  }
14049
14729
  return candidates[0];
14050
14730
  }
14051
- var import_node_fs38, import_node_module5, import_node_path39, import_node_url4, import_meta5, FALLBACK_CURSOR_MODELS, cachedModels, MODEL_CACHE_MS, cursorAdapter;
14731
+ var import_node_fs38, import_node_module5, import_node_path39, import_node_url4, import_meta7, FALLBACK_CURSOR_MODELS, cachedModels, MODEL_CACHE_MS, cursorAdapter;
14052
14732
  var init_cursor = __esm({
14053
14733
  "src/agents/cursor.ts"() {
14054
14734
  "use strict";
@@ -14068,7 +14748,7 @@ var init_cursor = __esm({
14068
14748
  init_packaged_runtime();
14069
14749
  init_turn_input();
14070
14750
  init_cursor_events();
14071
- import_meta5 = {};
14751
+ import_meta7 = {};
14072
14752
  FALLBACK_CURSOR_MODELS = [
14073
14753
  { id: "default", displayName: "Auto" },
14074
14754
  { id: "composer-2.5", displayName: "Composer 2.5" },
@@ -14342,7 +15022,7 @@ var init_opencode_host = __esm({
14342
15022
  });
14343
15023
 
14344
15024
  // src/agents/opencode.ts
14345
- function asRecord5(value) {
15025
+ function asRecord6(value) {
14346
15026
  if (value && typeof value === "object" && !Array.isArray(value)) {
14347
15027
  return value;
14348
15028
  }
@@ -14538,7 +15218,7 @@ var init_opencode = __esm({
14538
15218
  const name = part?.tool ?? part?.name ?? obj.tool ?? obj.name ?? "tool";
14539
15219
  const state = part?.state;
14540
15220
  const input = (state?.input && typeof state.input === "object" ? state.input : void 0) ?? part?.input ?? obj.input;
14541
- const metadata = asRecord5(state?.metadata);
15221
+ const metadata = asRecord6(state?.metadata);
14542
15222
  const id = opencodeToolId(
14543
15223
  name,
14544
15224
  part?.callID ?? part?.id ?? obj.id,
@@ -14573,7 +15253,7 @@ var init_opencode = __esm({
14573
15253
  }
14574
15254
  if (obj.type === "subtask_event") {
14575
15255
  const parentId = str3(obj.childSessionID) ?? str3(obj.childSessionId);
14576
- const part = asRecord5(obj.part);
15256
+ const part = asRecord6(obj.part);
14577
15257
  if (!parentId || !part) return null;
14578
15258
  if (part.type === "text" && str3(part.text)) {
14579
15259
  return withTaskParent(
@@ -14584,8 +15264,8 @@ var init_opencode = __esm({
14584
15264
  if (part.type === "tool" || str3(part.tool)) {
14585
15265
  const name = str3(part.tool) ?? str3(part.name) ?? "tool";
14586
15266
  const id = str3(part.callID) ?? str3(part.id) ?? `${parentId}-${name}`;
14587
- const state = asRecord5(part.state);
14588
- const input = asRecord5(state?.input) ?? asRecord5(part.input);
15267
+ const state = asRecord6(part.state);
15268
+ const input = asRecord6(state?.input) ?? asRecord6(part.input);
14589
15269
  const nested = [
14590
15270
  withEventParentId({ type: "tool_use", id, name, input }, parentId)
14591
15271
  ];
@@ -16361,7 +17041,7 @@ function forkMessageSlice(from, throughIndex) {
16361
17041
  function buildForkTranscriptAttachment(baseTitle, messages) {
16362
17042
  const title = baseTitle || "Chat";
16363
17043
  return {
16364
- id: (0, import_node_crypto6.randomUUID)(),
17044
+ id: (0, import_node_crypto8.randomUUID)(),
16365
17045
  name: `Transcript of ${title}.md`,
16366
17046
  kind: "transcript",
16367
17047
  content: formatTranscriptMarkdown(title, messages)
@@ -16420,11 +17100,11 @@ function forkChatTab(input) {
16420
17100
  }
16421
17101
  return tab;
16422
17102
  }
16423
- var import_node_crypto6;
17103
+ var import_node_crypto8;
16424
17104
  var init_chat_tabs = __esm({
16425
17105
  "src/threads/chat-tabs.ts"() {
16426
17106
  "use strict";
16427
- import_node_crypto6 = require("crypto");
17107
+ import_node_crypto8 = require("crypto");
16428
17108
  init_context_compact();
16429
17109
  init_teams();
16430
17110
  init_worktree_labels();
@@ -16698,7 +17378,7 @@ function buildReviewRequestAttachment(content, opts) {
16698
17378
  const path = opts?.path ?? REVIEW_SKILL_PATH;
16699
17379
  const name = opts?.name ?? (path === REVIEW_SKILL_PATH ? REVIEW_SKILL_NAME : path === REPO_REVIEW_PATH || path === CONTEXT_REVIEW_PATH ? REPO_REVIEW_NAME : REVIEW_REQUEST_NAME);
16700
17380
  return {
16701
- id: (0, import_node_crypto7.randomUUID)(),
17381
+ id: (0, import_node_crypto9.randomUUID)(),
16702
17382
  name,
16703
17383
  kind: "file",
16704
17384
  path,
@@ -16751,11 +17431,11 @@ async function requestReview(threadRef, send) {
16751
17431
  const started = await send(tab.id, REVIEW_REQUEST_PREFILL);
16752
17432
  return { tab: started, from };
16753
17433
  }
16754
- var import_node_crypto7, import_node_fs44, import_node_path44, 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;
17434
+ var import_node_crypto9, import_node_fs44, import_node_path44, 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;
16755
17435
  var init_request_review = __esm({
16756
17436
  "src/review/request-review.ts"() {
16757
17437
  "use strict";
16758
- import_node_crypto7 = require("crypto");
17438
+ import_node_crypto9 = require("crypto");
16759
17439
  import_node_fs44 = require("fs");
16760
17440
  import_node_path44 = require("path");
16761
17441
  init_global_workspace();
@@ -18013,7 +18693,7 @@ function setupLogPath(threadId) {
18013
18693
  }
18014
18694
  function setupLogKeyForWorktree(worktreePath) {
18015
18695
  const norm = normalizeWorktreePath(worktreePath);
18016
- return `wt-${(0, import_node_crypto8.createHash)("sha1").update(norm).digest("hex").slice(0, 16)}`;
18696
+ return `wt-${(0, import_node_crypto10.createHash)("sha1").update(norm).digest("hex").slice(0, 16)}`;
18017
18697
  }
18018
18698
  function emptySetupLog() {
18019
18699
  return { ...EMPTY };
@@ -18106,11 +18786,11 @@ function finishSetupLog(threadId, exitCode, source) {
18106
18786
  persistNow(threadId);
18107
18787
  return materialize(mem);
18108
18788
  }
18109
- var import_node_crypto8, import_node_fs48, import_node_path48, EMPTY, MAX_SETUP_LOG_CHARS, memory, persistTimers, PERSIST_DEBOUNCE_MS;
18789
+ var import_node_crypto10, import_node_fs48, import_node_path48, EMPTY, MAX_SETUP_LOG_CHARS, memory, persistTimers, PERSIST_DEBOUNCE_MS;
18110
18790
  var init_setup_log = __esm({
18111
18791
  "src/store/setup-log.ts"() {
18112
18792
  "use strict";
18113
- import_node_crypto8 = require("crypto");
18793
+ import_node_crypto10 = require("crypto");
18114
18794
  import_node_fs48 = require("fs");
18115
18795
  import_node_path48 = require("path");
18116
18796
  init_worktree_labels();
@@ -18161,7 +18841,7 @@ function runLogPath(key) {
18161
18841
  }
18162
18842
  function runLogKeyForWorktree(worktreePath, scriptName) {
18163
18843
  const norm = normalizeWorktreePath(worktreePath);
18164
- const hash = (0, import_node_crypto9.createHash)("sha1").update(norm).digest("hex").slice(0, 16);
18844
+ const hash = (0, import_node_crypto11.createHash)("sha1").update(norm).digest("hex").slice(0, 16);
18165
18845
  return `wt-${hash}-run-${safeScriptToken(scriptName)}`;
18166
18846
  }
18167
18847
  function emptyRunLog() {
@@ -18262,11 +18942,11 @@ function finishRunLog(key, exitCode) {
18262
18942
  function flushRunLog(key) {
18263
18943
  persistNow2(key);
18264
18944
  }
18265
- var import_node_crypto9, import_node_fs49, import_node_path49, EMPTY2, MAX_RUN_LOG_CHARS, DEFAULT_RUN_LOG_TAIL_CHARS, memory2, persistTimers2, PERSIST_DEBOUNCE_MS2;
18945
+ var import_node_crypto11, import_node_fs49, import_node_path49, EMPTY2, MAX_RUN_LOG_CHARS, DEFAULT_RUN_LOG_TAIL_CHARS, memory2, persistTimers2, PERSIST_DEBOUNCE_MS2;
18266
18946
  var init_run_log = __esm({
18267
18947
  "src/store/run-log.ts"() {
18268
18948
  "use strict";
18269
- import_node_crypto9 = require("crypto");
18949
+ import_node_crypto11 = require("crypto");
18270
18950
  import_node_fs49 = require("fs");
18271
18951
  import_node_path49 = require("path");
18272
18952
  init_worktree_labels();
@@ -18657,6 +19337,21 @@ var init_desktop_host = __esm({
18657
19337
  }
18658
19338
  });
18659
19339
 
19340
+ // src/mcp-ui/model-context.ts
19341
+ function takeMcpAppModelContext(threadId) {
19342
+ const thread = readThread(threadId);
19343
+ const text7 = thread?.mcpAppModelContext?.trim();
19344
+ if (!text7) return void 0;
19345
+ updateThread(threadId, { mcpAppModelContext: null });
19346
+ return text7;
19347
+ }
19348
+ var init_model_context = __esm({
19349
+ "src/mcp-ui/model-context.ts"() {
19350
+ "use strict";
19351
+ init_thread_store();
19352
+ }
19353
+ });
19354
+
18660
19355
  // src/agents/tool-permission.ts
18661
19356
  function setToolPermissionPublisher(next) {
18662
19357
  publisher = next;
@@ -18677,11 +19372,11 @@ function denyPendingToolPermissions(threadId) {
18677
19372
  const last = pending[pending.length - 1];
18678
19373
  if (last) clearPrompt(threadId, last.id);
18679
19374
  }
18680
- var import_node_crypto10, import_node_path53, queues, publisher;
19375
+ var import_node_crypto12, import_node_path53, queues, publisher;
18681
19376
  var init_tool_permission = __esm({
18682
19377
  "src/agents/tool-permission.ts"() {
18683
19378
  "use strict";
18684
- import_node_crypto10 = require("crypto");
19379
+ import_node_crypto12 = require("crypto");
18685
19380
  import_node_path53 = require("path");
18686
19381
  init_claude_mcp();
18687
19382
  queues = /* @__PURE__ */ new Map();
@@ -18739,7 +19434,7 @@ var init_agent_block_view = __esm({
18739
19434
  });
18740
19435
 
18741
19436
  // src/plan/plan-present.ts
18742
- function asRecord6(v) {
19437
+ function asRecord7(v) {
18743
19438
  return v != null && typeof v === "object" && !Array.isArray(v) ? v : null;
18744
19439
  }
18745
19440
  function isPresentPlanToolName(name) {
@@ -18758,7 +19453,7 @@ function extractPresentedPlan(parts) {
18758
19453
  for (let i = parts.length - 1; i >= 0; i--) {
18759
19454
  const p = parts[i];
18760
19455
  if (p.type !== "tool" || !isPresentPlanToolName(p.name)) continue;
18761
- const input = asRecord6(p.input) ?? {};
19456
+ const input = asRecord7(p.input) ?? {};
18762
19457
  const content = typeof input.content === "string" ? input.content : typeof input.plan === "string" ? input.plan : typeof input.markdown === "string" ? input.markdown : "";
18763
19458
  if (!content.trim()) continue;
18764
19459
  const title = typeof input.title === "string" && input.title.trim() ? input.title.trim() : "Plan";
@@ -19213,7 +19908,7 @@ function isUnclaimedSteerRequest(req) {
19213
19908
  }
19214
19909
  function nextSteerRequest(existing) {
19215
19910
  if (existing?.requestId && !existing.claimedAt) return existing;
19216
- return { requestId: (0, import_node_crypto11.randomUUID)(), requestedAt: (/* @__PURE__ */ new Date()).toISOString() };
19911
+ return { requestId: (0, import_node_crypto13.randomUUID)(), requestedAt: (/* @__PURE__ */ new Date()).toISOString() };
19217
19912
  }
19218
19913
  function claimSteerRequest(threadId) {
19219
19914
  const pending = readThread(threadId)?.steerRequest;
@@ -19222,11 +19917,11 @@ function claimSteerRequest(threadId) {
19222
19917
  steerRequest: { ...pending, claimedAt: (/* @__PURE__ */ new Date()).toISOString() }
19223
19918
  });
19224
19919
  }
19225
- var import_node_crypto11;
19920
+ var import_node_crypto13;
19226
19921
  var init_steer_request = __esm({
19227
19922
  "src/orchestrator/steer-request.ts"() {
19228
19923
  "use strict";
19229
- import_node_crypto11 = require("crypto");
19924
+ import_node_crypto13 = require("crypto");
19230
19925
  init_thread_store();
19231
19926
  }
19232
19927
  });
@@ -19998,8 +20693,8 @@ function resolveAbleTimeOAuthHost(requested, saved) {
19998
20693
  return fromSaved || void 0;
19999
20694
  }
20000
20695
  function createAbleTimePkce() {
20001
- const verifier = (0, import_node_crypto12.randomBytes)(32).toString("base64url");
20002
- const challenge = (0, import_node_crypto12.createHash)("sha256").update(verifier).digest("base64url");
20696
+ const verifier = (0, import_node_crypto14.randomBytes)(32).toString("base64url");
20697
+ const challenge = (0, import_node_crypto14.createHash)("sha256").update(verifier).digest("base64url");
20003
20698
  return { verifier, challenge };
20004
20699
  }
20005
20700
  function ableTimeOAuthAuthorizeUrl(clientId, state, codeChallenge, host) {
@@ -20104,7 +20799,7 @@ async function startAbleTimeOAuth(opts) {
20104
20799
  opts?.host,
20105
20800
  loadAppSettings().integrations.abletimeHost
20106
20801
  );
20107
- const state = (0, import_node_crypto12.randomBytes)(16).toString("hex");
20802
+ const state = (0, import_node_crypto14.randomBytes)(16).toString("hex");
20108
20803
  const pkce = createAbleTimePkce();
20109
20804
  const authorizeUrl = ableTimeOAuthAuthorizeUrl(clientId, state, pkce.challenge, host);
20110
20805
  const timeoutMs = opts?.timeoutMs ?? 5 * 6e4;
@@ -20117,7 +20812,7 @@ async function startAbleTimeOAuth(opts) {
20117
20812
  if (err) reject(err);
20118
20813
  else resolve3(value);
20119
20814
  };
20120
- const server = (0, import_node_http.createServer)((req, res) => {
20815
+ const server = (0, import_node_http2.createServer)((req, res) => {
20121
20816
  try {
20122
20817
  const url = new URL(req.url || "/", `http://127.0.0.1:${ABLETIME_OAUTH_PORT}`);
20123
20818
  if (url.pathname !== "/callback") {
@@ -20204,12 +20899,12 @@ async function startAbleTimeOAuth(opts) {
20204
20899
  return loadAppSettings();
20205
20900
  }
20206
20901
  }
20207
- var import_node_crypto12, 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;
20902
+ var import_node_crypto14, 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;
20208
20903
  var init_abletime_oauth = __esm({
20209
20904
  "src/integrations/abletime-oauth.ts"() {
20210
20905
  "use strict";
20211
- import_node_crypto12 = require("crypto");
20212
- import_node_http = require("http");
20906
+ import_node_crypto14 = require("crypto");
20907
+ import_node_http2 = require("http");
20213
20908
  init_fetch();
20214
20909
  init_app_settings();
20215
20910
  init_abletime_mcp();
@@ -20242,7 +20937,7 @@ __export(abletime_rest_exports, {
20242
20937
  looksLikeAbleTimeUlid: () => looksLikeAbleTimeUlid,
20243
20938
  textFromAbleTimeDoc: () => textFromAbleTimeDoc
20244
20939
  });
20245
- function asRecord7(value) {
20940
+ function asRecord8(value) {
20246
20941
  return value && typeof value === "object" && !Array.isArray(value) ? value : null;
20247
20942
  }
20248
20943
  function asString(value) {
@@ -20250,7 +20945,7 @@ function asString(value) {
20250
20945
  }
20251
20946
  function asList(value) {
20252
20947
  if (Array.isArray(value)) return value;
20253
- const record = asRecord7(value);
20948
+ const record = asRecord8(value);
20254
20949
  if (!record) return [];
20255
20950
  for (const key of ["data", "tasks", "projects", "users", "items", "results"]) {
20256
20951
  if (Array.isArray(record[key])) return record[key];
@@ -20267,12 +20962,12 @@ function ableTimeDocFromText(text7) {
20267
20962
  }
20268
20963
  function textFromAbleTimeDoc(value) {
20269
20964
  if (typeof value === "string") return value.trim();
20270
- const record = asRecord7(value);
20965
+ const record = asRecord8(value);
20271
20966
  if (!record) return "";
20272
20967
  if (typeof record.text === "string" && record.text.trim()) return record.text.trim();
20273
20968
  const chunks = [];
20274
20969
  const walk = (node) => {
20275
- const rec = asRecord7(node);
20970
+ const rec = asRecord8(node);
20276
20971
  if (!rec) return;
20277
20972
  if (typeof rec.text === "string" && rec.text) chunks.push(rec.text);
20278
20973
  if (Array.isArray(rec.content)) rec.content.forEach(walk);
@@ -20334,7 +21029,7 @@ async function restPages(path, opts, maxPages = 20) {
20334
21029
  query: { ...opts.query, ...cursor ? { cursor } : {} }
20335
21030
  });
20336
21031
  items.push(...asList(raw));
20337
- const page = asRecord7(asRecord7(raw)?.page);
21032
+ const page = asRecord8(asRecord8(raw)?.page);
20338
21033
  const next = page ? asString(page.nextCursor) : "";
20339
21034
  if (!next) break;
20340
21035
  cursor = next;
@@ -20342,7 +21037,7 @@ async function restPages(path, opts, maxPages = 20) {
20342
21037
  return items;
20343
21038
  }
20344
21039
  function userDisplayName(raw) {
20345
- const rec = asRecord7(raw);
21040
+ const rec = asRecord8(raw);
20346
21041
  if (!rec) return null;
20347
21042
  const id = asString(rec.userId) || asString(rec.id);
20348
21043
  const name = [asString(rec.firstName), asString(rec.lastName)].filter(Boolean).join(" ") || asString(rec.username) || asString(rec.email) || asString(rec.name);
@@ -20350,7 +21045,7 @@ function userDisplayName(raw) {
20350
21045
  return { id: id || void 0, name };
20351
21046
  }
20352
21047
  function restTaskToRaw(raw, users) {
20353
- const rec = asRecord7(raw);
21048
+ const rec = asRecord8(raw);
20354
21049
  if (!rec) return null;
20355
21050
  const id = asString(rec.timeflowTaskId) || asString(rec.taskId) || asString(rec.id);
20356
21051
  const identifier = asString(rec.taskRef) || asString(rec.reference) || id;
@@ -20358,7 +21053,7 @@ function restTaskToRaw(raw, users) {
20358
21053
  if (!id && !identifier && !title) return null;
20359
21054
  const assignee = users.get(asString(rec.assignedUserId));
20360
21055
  const comments = asList(rec.comments).map((item) => {
20361
- const comment = asRecord7(item) ?? {};
21056
+ const comment = asRecord8(item) ?? {};
20362
21057
  const user = userDisplayName(comment);
20363
21058
  return {
20364
21059
  id: asString(comment.commentId) || asString(comment.id),
@@ -20388,13 +21083,13 @@ function restTaskToRaw(raw, users) {
20388
21083
  };
20389
21084
  }
20390
21085
  function restProjectToRaw(raw) {
20391
- const rec = asRecord7(raw);
21086
+ const rec = asRecord8(raw);
20392
21087
  if (!rec) return null;
20393
21088
  const id = asString(rec.projectId) || asString(rec.id);
20394
21089
  const name = asString(rec.projectName) || asString(rec.name);
20395
21090
  if (!id && !name) return null;
20396
21091
  const categories = asList(rec.categories).map((item) => {
20397
- const cat = asRecord7(item) ?? {};
21092
+ const cat = asRecord8(item) ?? {};
20398
21093
  return {
20399
21094
  id: asString(cat.projectCategoryId) || asString(cat.categoryId) || asString(cat.id),
20400
21095
  name: asString(cat.categoryName) || asString(cat.name)
@@ -20406,7 +21101,7 @@ async function listUsers(opts) {
20406
21101
  const users = /* @__PURE__ */ new Map();
20407
21102
  for (const item of await restPages("/users", opts).catch(() => [])) {
20408
21103
  const user = userDisplayName(item);
20409
- const rec = asRecord7(item);
21104
+ const rec = asRecord8(item);
20410
21105
  const id = user?.id || (rec ? asString(rec.userId) : "");
20411
21106
  if (user && id) users.set(id, user);
20412
21107
  }
@@ -20532,10 +21227,10 @@ async function callAbleTimeRestTool(name, args = {}, opts) {
20532
21227
  if (!project) throw new Error("AbleTime has no projects to create a task in");
20533
21228
  const categories = asList(project.categories);
20534
21229
  const wantedCategory = firstStringArg(args, ["category_id", "categoryId", "category"]);
20535
- const category = categories.map((item) => asRecord7(item)).find((item) => {
21230
+ const category = categories.map((item) => asRecord8(item)).find((item) => {
20536
21231
  if (!item || !wantedCategory) return false;
20537
21232
  return asString(item.id).toLowerCase() === wantedCategory.toLowerCase() || asString(item.name).toLowerCase() === wantedCategory.toLowerCase();
20538
- }) ?? asRecord7(categories[0]);
21233
+ }) ?? asRecord8(categories[0]);
20539
21234
  const parentArg = firstStringArg(args, ["parent", "parent_id", "parentId", "related_task_id"]);
20540
21235
  const parentTaskId = parentArg ? await resolveRestParentTaskId(parentArg, requestOpts) : void 0;
20541
21236
  const created = await abletimeRestRequest("/tasks", {
@@ -20549,7 +21244,7 @@ async function callAbleTimeRestTool(name, args = {}, opts) {
20549
21244
  }
20550
21245
  });
20551
21246
  const state = firstStringArg(args, ["state"]);
20552
- const createdId = asString(asRecord7(created)?.timeflowTaskId);
21247
+ const createdId = asString(asRecord8(created)?.timeflowTaskId);
20553
21248
  const description = asString(args.description);
20554
21249
  if (createdId && description) {
20555
21250
  await abletimeRestRequest(`/tasks/${encodeURIComponent(createdId)}`, {
@@ -20622,7 +21317,7 @@ async function callAbleTimeRestTool(name, args = {}, opts) {
20622
21317
  method: "POST",
20623
21318
  body: { content: ableTimeDocFromText(body) }
20624
21319
  });
20625
- const rec = asRecord7(created) ?? {};
21320
+ const rec = asRecord8(created) ?? {};
20626
21321
  return {
20627
21322
  id: asString(rec.commentId) || void 0,
20628
21323
  body: textFromAbleTimeDoc(rec.content) || body
@@ -20717,7 +21412,7 @@ function rewriteAbleTimeError(message) {
20717
21412
  }
20718
21413
  return message;
20719
21414
  }
20720
- function asRecord8(value) {
21415
+ function asRecord9(value) {
20721
21416
  return value && typeof value === "object" && !Array.isArray(value) ? value : null;
20722
21417
  }
20723
21418
  function parseSseJson(body) {
@@ -20739,12 +21434,12 @@ function parseSseJson(body) {
20739
21434
  }
20740
21435
  }
20741
21436
  function unwrapToolResult(result) {
20742
- const record = asRecord8(result);
21437
+ const record = asRecord9(result);
20743
21438
  if (!record) return result;
20744
21439
  const content = record.content;
20745
21440
  if (Array.isArray(content)) {
20746
21441
  const texts = content.map((part) => {
20747
- const item = asRecord8(part);
21442
+ const item = asRecord9(part);
20748
21443
  if (!item) return "";
20749
21444
  return typeof item.text === "string" ? item.text : "";
20750
21445
  }).filter(Boolean);
@@ -20766,7 +21461,7 @@ function unwrapToolResult(result) {
20766
21461
  return result;
20767
21462
  }
20768
21463
  function textsFromUnknown(value) {
20769
- const record = asRecord8(value);
21464
+ const record = asRecord9(value);
20770
21465
  if (!record) return "";
20771
21466
  if (typeof record.message === "string") return record.message;
20772
21467
  if (typeof record.error === "string") return record.error;
@@ -20813,7 +21508,7 @@ async function abletimeMcpRequest(method, params, opts) {
20813
21508
  return parseSseJson(body);
20814
21509
  }
20815
21510
  })();
20816
- const rpc = asRecord8(parsed);
21511
+ const rpc = asRecord9(parsed);
20817
21512
  if (rpc?.error) {
20818
21513
  const detail = typeof rpc.error.message === "string" && rpc.error.message.trim() ? rpc.error.message : `AbleTime MCP error ${rpc.error.code ?? ""}`.trim();
20819
21514
  throw new Error(rewriteAbleTimeError(detail));
@@ -20968,7 +21663,7 @@ function uniqueAttachmentFileName(dir, originalName) {
20968
21663
  const candidate = `${stem}-${i}${ext}`;
20969
21664
  if (!(0, import_node_fs53.existsSync)((0, import_node_path54.join)(dir, candidate))) return candidate;
20970
21665
  }
20971
- return `${stem}-${(0, import_node_crypto13.randomUUID)()}${ext}`;
21666
+ return `${stem}-${(0, import_node_crypto15.randomUUID)()}${ext}`;
20972
21667
  }
20973
21668
  function extractHttpUrls(markdown) {
20974
21669
  const text7 = markdown ?? "";
@@ -21074,13 +21769,13 @@ async function downloadAuthenticatedFile(opts) {
21074
21769
  ...contentType ? { contentType } : {}
21075
21770
  };
21076
21771
  }
21077
- var import_node_fs53, import_node_path54, import_node_crypto13, ISSUE_ATTACHMENT_MAX_BYTES, MARKDOWN_IMAGE_RE, MARKDOWN_LINK_RE, HTML_SRC_RE, BARE_URL_RE, EXT_BY_MIME;
21772
+ var import_node_fs53, import_node_path54, import_node_crypto15, ISSUE_ATTACHMENT_MAX_BYTES, MARKDOWN_IMAGE_RE, MARKDOWN_LINK_RE, HTML_SRC_RE, BARE_URL_RE, EXT_BY_MIME;
21078
21773
  var init_issue_attachments = __esm({
21079
21774
  "src/integrations/issue-attachments.ts"() {
21080
21775
  "use strict";
21081
21776
  import_node_fs53 = require("fs");
21082
21777
  import_node_path54 = require("path");
21083
- import_node_crypto13 = require("crypto");
21778
+ import_node_crypto15 = require("crypto");
21084
21779
  init_fetch();
21085
21780
  init_workspace_scratch();
21086
21781
  ISSUE_ATTACHMENT_MAX_BYTES = 25 * 1024 * 1024;
@@ -21105,7 +21800,7 @@ var init_issue_attachments = __esm({
21105
21800
  });
21106
21801
 
21107
21802
  // src/integrations/abletime-attachments.ts
21108
- function asRecord9(value) {
21803
+ function asRecord10(value) {
21109
21804
  return value && typeof value === "object" && !Array.isArray(value) ? value : null;
21110
21805
  }
21111
21806
  function asString2(value) {
@@ -21113,7 +21808,7 @@ function asString2(value) {
21113
21808
  }
21114
21809
  function asList2(value) {
21115
21810
  if (Array.isArray(value)) return value;
21116
- const record = asRecord9(value);
21811
+ const record = asRecord10(value);
21117
21812
  if (!record) return [];
21118
21813
  for (const key of ["data", "tasks", "projects", "items", "results", "nodes"]) {
21119
21814
  if (Array.isArray(record[key])) return record[key];
@@ -21132,9 +21827,9 @@ function filesFromAbleTimeDoc(value) {
21132
21827
  const out = [];
21133
21828
  const seen = /* @__PURE__ */ new Set();
21134
21829
  const walk = (node) => {
21135
- const rec = asRecord9(node);
21830
+ const rec = asRecord10(node);
21136
21831
  if (!rec) return;
21137
- const attrs = asRecord9(rec.attrs) ?? rec;
21832
+ const attrs = asRecord10(rec.attrs) ?? rec;
21138
21833
  const url = asString2(attrs.src) || asString2(attrs.href) || asString2(attrs.url) || asString2(attrs.fileUrl) || asString2(attrs.downloadUrl);
21139
21834
  if (url && !seen.has(url)) {
21140
21835
  seen.add(url);
@@ -21152,7 +21847,7 @@ function filesFromAbleTimeDoc(value) {
21152
21847
  function listedAbleTimeFiles(raw) {
21153
21848
  const out = [];
21154
21849
  for (const item of asList2(raw)) {
21155
- const rec = asRecord9(item);
21850
+ const rec = asRecord10(item);
21156
21851
  if (!rec) continue;
21157
21852
  const url = firstString(rec, ["url", "href", "src", "fileUrl", "downloadUrl", "permalink"]);
21158
21853
  if (!url) continue;
@@ -21172,7 +21867,7 @@ function mapAbleTimeAttachments(record) {
21172
21867
  ...filesFromAbleTimeDoc(record.description),
21173
21868
  ...filesFromAbleTimeDoc(record.content),
21174
21869
  ...asList2(record.comments).flatMap((item) => {
21175
- const rec = asRecord9(item);
21870
+ const rec = asRecord10(item);
21176
21871
  return rec ? filesFromAbleTimeDoc(rec.content ?? rec.body) : [];
21177
21872
  })
21178
21873
  ].map((file) => ({
@@ -21214,7 +21909,7 @@ async function resolveAbleTimeAttachmentUrl(id, opts) {
21214
21909
  const json = await res.json().catch(() => null);
21215
21910
  const rec = json && typeof json === "object" && !Array.isArray(json) ? json.data && typeof json.data === "object" ? json.data : json : null;
21216
21911
  if (!rec) continue;
21217
- const url = firstString(rec, ["url", "href", "src", "fileUrl", "downloadUrl"]) || firstString(asRecord9(rec.file), ["url", "href"]);
21912
+ const url = firstString(rec, ["url", "href", "src", "fileUrl", "downloadUrl"]) || firstString(asRecord10(rec.file), ["url", "href"]);
21218
21913
  if (url) {
21219
21914
  return {
21220
21915
  url,
@@ -21256,7 +21951,7 @@ var init_abletime_attachments = __esm({
21256
21951
  });
21257
21952
 
21258
21953
  // src/integrations/abletime-projects.ts
21259
- function asRecord10(value) {
21954
+ function asRecord11(value) {
21260
21955
  return value && typeof value === "object" && !Array.isArray(value) ? value : null;
21261
21956
  }
21262
21957
  function firstString2(record, keys) {
@@ -21269,7 +21964,7 @@ function firstString2(record, keys) {
21269
21964
  }
21270
21965
  function asList3(value) {
21271
21966
  if (Array.isArray(value)) return value;
21272
- const record = asRecord10(value);
21967
+ const record = asRecord11(value);
21273
21968
  if (!record) return [];
21274
21969
  for (const key of ["data", "tasks", "projects", "items", "results", "nodes"]) {
21275
21970
  if (Array.isArray(record[key])) return record[key];
@@ -21277,7 +21972,7 @@ function asList3(value) {
21277
21972
  return [];
21278
21973
  }
21279
21974
  function ableTimeProjectFields(nested) {
21280
- const projectRecord = asRecord10(nested.project);
21975
+ const projectRecord = asRecord11(nested.project);
21281
21976
  const projectId = firstString2(nested, ["project_id", "projectId"]) || firstString2(projectRecord, ["id"]) || void 0;
21282
21977
  const projectName = firstString2(nested, ["project_name", "projectName"]) || firstString2(projectRecord, ["name", "title"]) || void 0;
21283
21978
  if (!projectId && !projectName) return {};
@@ -21290,13 +21985,13 @@ function ableTimeProjectFields(nested) {
21290
21985
  };
21291
21986
  }
21292
21987
  function mapAbleTimeProject(raw) {
21293
- const record = asRecord10(raw);
21988
+ const record = asRecord11(raw);
21294
21989
  if (!record) return null;
21295
21990
  const id = firstString2(record, ["id", "project_id", "projectId"]);
21296
21991
  const name = firstString2(record, ["name", "title", "projectName"]);
21297
21992
  if (!id && !name) return null;
21298
21993
  const categories = asList3(record.categories ?? record.category).map((item) => {
21299
- const rec = asRecord10(item);
21994
+ const rec = asRecord11(item);
21300
21995
  if (!rec) return null;
21301
21996
  const categoryId = firstString2(rec, ["id", "category_id", "projectCategoryId", "categoryId"]);
21302
21997
  const categoryName = firstString2(rec, ["name", "title", "categoryName"]);
@@ -21332,7 +22027,7 @@ __export(abletime_exports, {
21332
22027
  updateAbleTimeTask: () => updateAbleTimeTask,
21333
22028
  verifyAbleTimeConnection: () => verifyAbleTimeConnection
21334
22029
  });
21335
- function asRecord11(value) {
22030
+ function asRecord12(value) {
21336
22031
  return value && typeof value === "object" && !Array.isArray(value) ? value : null;
21337
22032
  }
21338
22033
  function asString3(value) {
@@ -21349,14 +22044,14 @@ function firstString3(record, keys) {
21349
22044
  function firstRecord(record, keys) {
21350
22045
  if (!record) return null;
21351
22046
  for (const key of keys) {
21352
- const value = asRecord11(record[key]);
22047
+ const value = asRecord12(record[key]);
21353
22048
  if (value) return value;
21354
22049
  }
21355
22050
  return null;
21356
22051
  }
21357
22052
  function asList4(value) {
21358
22053
  if (Array.isArray(value)) return value;
21359
- const record = asRecord11(value);
22054
+ const record = asRecord12(value);
21360
22055
  if (!record) return [];
21361
22056
  for (const key of ["data", "tasks", "projects", "items", "results", "nodes"]) {
21362
22057
  if (Array.isArray(record[key])) return record[key];
@@ -21368,18 +22063,18 @@ function labelsOf(record) {
21368
22063
  if (!Array.isArray(raw)) return [];
21369
22064
  return raw.map((item) => {
21370
22065
  if (typeof item === "string") return item.trim();
21371
- const rec = asRecord11(item);
22066
+ const rec = asRecord12(item);
21372
22067
  return rec ? firstString3(rec, ["name", "title", "label"]) : "";
21373
22068
  }).filter(Boolean);
21374
22069
  }
21375
22070
  function commentsOf(record) {
21376
22071
  const out = [];
21377
22072
  for (const item of asList4(record.comments ?? record.notes ?? record.discussion)) {
21378
- const rec = asRecord11(item);
22073
+ const rec = asRecord12(item);
21379
22074
  if (!rec) continue;
21380
22075
  const body = firstString3(rec, ["body", "text", "comment", "message", "contentSanitized"]) || textFromAbleTimeDoc(rec.content);
21381
22076
  if (!body) continue;
21382
- const user = firstString3(asRecord11(rec.user) ?? asRecord11(rec.author), ["name", "display_name", "username"]) || firstString3(rec, ["user_name", "author", "username"]);
22077
+ const user = firstString3(asRecord12(rec.user) ?? asRecord12(rec.author), ["name", "display_name", "username"]) || firstString3(rec, ["user_name", "author", "username"]);
21383
22078
  const id = firstString3(rec, ["id", "comment_id", "commentId"]);
21384
22079
  const url = firstString3(rec, ["url", "permalink"]);
21385
22080
  const createdAt = firstString3(rec, ["created_at", "createdAt", "created"]);
@@ -21406,7 +22101,7 @@ function taskUrl(task, host) {
21406
22101
  return `${base}/tasks/${slug}`;
21407
22102
  }
21408
22103
  function mapAbleTimeTask(raw, host) {
21409
- const record = asRecord11(raw);
22104
+ const record = asRecord12(raw);
21410
22105
  if (!record) return null;
21411
22106
  const nested = firstRecord(record, ["task", "data"]) ?? record;
21412
22107
  const id = firstString3(nested, ["id", "task_id", "taskId", "timeflowTaskId"]);
@@ -21424,7 +22119,7 @@ function mapAbleTimeTask(raw, host) {
21424
22119
  description: firstString3(nested, ["description", "body", "details", "descriptionSanitized"]) || textFromAbleTimeDoc(nested.description) || void 0,
21425
22120
  state: firstString3(nested, ["state", "board_state", "boardState", "status", "taskState"]) || void 0,
21426
22121
  ...ableTimeProjectFields(nested),
21427
- categoryId: firstString3(nested, ["category_id", "categoryId", "projectCategoryId"]) || firstString3(asRecord11(nested.category), ["id"]) || void 0,
22122
+ categoryId: firstString3(nested, ["category_id", "categoryId", "projectCategoryId"]) || firstString3(asRecord12(nested.category), ["id"]) || void 0,
21428
22123
  assignee: assigneeOf(nested),
21429
22124
  labels: labelsOf(nested),
21430
22125
  comments: commentsOf(nested),
@@ -21474,7 +22169,7 @@ function isOpenTask(task) {
21474
22169
  }
21475
22170
  async function getAbleTimeOrientation(opts) {
21476
22171
  const raw = await callAbleTimeTool("orientation", {}, opts);
21477
- const record = asRecord11(raw);
22172
+ const record = asRecord12(raw);
21478
22173
  const viewerRec = firstRecord(record, ["viewer", "principal", "user", "actor", "me", "person"]) ?? record;
21479
22174
  const viewer = {
21480
22175
  id: firstString3(viewerRec, ["id", "user_id"]) || void 0,
@@ -21553,7 +22248,7 @@ async function commentAbleTimeTask(input, opts) {
21553
22248
  { id, task_id: id, task: id, body, comment: body, text: body },
21554
22249
  opts
21555
22250
  );
21556
- const rec = asRecord11(raw);
22251
+ const rec = asRecord12(raw);
21557
22252
  return {
21558
22253
  id: rec ? firstString3(rec, ["id", "comment_id"]) || void 0 : void 0,
21559
22254
  body: rec ? firstString3(rec, ["body", "text", "comment"]) || body : body
@@ -22691,7 +23386,7 @@ function buildQuotaHandoffAttachment(from, limitText, fallbackAgent) {
22691
23386
  ...instructions
22692
23387
  ].join("\n");
22693
23388
  return {
22694
- id: (0, import_node_crypto14.randomUUID)(),
23389
+ id: (0, import_node_crypto16.randomUUID)(),
22695
23390
  name: orch ? "Orchestration quota handoff.md" : "Quota handoff.md",
22696
23391
  kind: "transcript",
22697
23392
  content: body
@@ -22723,11 +23418,11 @@ function createQuotaFailoverChat(from, fallbackAgent, limitText, opts) {
22723
23418
  }
22724
23419
  return updateThread(tab.id, patch);
22725
23420
  }
22726
- var import_node_crypto14, QUOTA_CONTINUE_PROMPT, QUOTA_CONTINUE_ACCOUNT_PROMPT, QUOTA_RESUME_PROMPT;
23421
+ var import_node_crypto16, QUOTA_CONTINUE_PROMPT, QUOTA_CONTINUE_ACCOUNT_PROMPT, QUOTA_RESUME_PROMPT;
22727
23422
  var init_quota_failover = __esm({
22728
23423
  "src/orchestrator/quota-failover.ts"() {
22729
23424
  "use strict";
22730
- import_node_crypto14 = require("crypto");
23425
+ import_node_crypto16 = require("crypto");
22731
23426
  init_session_quota();
22732
23427
  init_app_settings();
22733
23428
  init_managed_accounts();
@@ -24790,7 +25485,7 @@ function compiledModuleDir() {
24790
25485
  const cjsDir = typeof __dirname !== "undefined" ? __dirname : "";
24791
25486
  if (cjsDir) return cjsDir;
24792
25487
  try {
24793
- const url = import_meta6.url;
25488
+ const url = import_meta8.url;
24794
25489
  if (typeof url === "string" && url.length > 0) {
24795
25490
  return (0, import_node_path60.dirname)((0, import_node_url5.fileURLToPath)(url));
24796
25491
  }
@@ -24829,7 +25524,7 @@ function formatDetachedJobInvoke(scriptPath) {
24829
25524
  if (resolved) return `node ${JSON.stringify(resolved)}`;
24830
25525
  return "node scripts/detached-job.cjs";
24831
25526
  }
24832
- var import_node_fs61, import_node_path60, import_node_url5, import_meta6, DETACHED_JOB_FILENAMES;
25527
+ var import_node_fs61, import_node_path60, import_node_url5, import_meta8, DETACHED_JOB_FILENAMES;
24833
25528
  var init_detached_job_path = __esm({
24834
25529
  "src/skills/detached-job-path.ts"() {
24835
25530
  "use strict";
@@ -24837,7 +25532,7 @@ var init_detached_job_path = __esm({
24837
25532
  import_node_path60 = require("path");
24838
25533
  import_node_url5 = require("url");
24839
25534
  init_packaged_runtime();
24840
- import_meta6 = {};
25535
+ import_meta8 = {};
24841
25536
  DETACHED_JOB_FILENAMES = ["detached-job.cjs", "detached-job.js"];
24842
25537
  }
24843
25538
  });
@@ -26205,7 +26900,7 @@ function buildTask(input, now) {
26205
26900
  const ts = nowIso2(now);
26206
26901
  const agent = input.agent ? coerceOrchestratorAgent(input.agent) : null;
26207
26902
  return {
26208
- id: (0, import_node_crypto15.randomUUID)(),
26903
+ id: (0, import_node_crypto17.randomUUID)(),
26209
26904
  name: input.name?.trim() || defaultScheduleName(prompt),
26210
26905
  prompt,
26211
26906
  enabled: input.enabled !== false,
@@ -26305,11 +27000,11 @@ function recordScheduleRun(id, result) {
26305
27000
  writeAll2(rows);
26306
27001
  return next;
26307
27002
  }
26308
- var import_node_crypto15, import_node_fs65, import_node_path64, import_croner, DURATION_RE, UNIT_MS;
27003
+ var import_node_crypto17, import_node_fs65, import_node_path64, import_croner, DURATION_RE, UNIT_MS;
26309
27004
  var init_schedules = __esm({
26310
27005
  "src/store/schedules.ts"() {
26311
27006
  "use strict";
26312
- import_node_crypto15 = require("crypto");
27007
+ import_node_crypto17 = require("crypto");
26313
27008
  import_node_fs65 = require("fs");
26314
27009
  import_node_path64 = require("path");
26315
27010
  import_croner = require("croner");
@@ -26552,10 +27247,10 @@ function collectActiveRunPorts(runs) {
26552
27247
  return [...ports];
26553
27248
  }
26554
27249
  function getOrchestrator() {
26555
- if (!singleton) {
26556
- singleton = new Orchestrator();
27250
+ if (!singleton2) {
27251
+ singleton2 = new Orchestrator();
26557
27252
  }
26558
- return singleton;
27253
+ return singleton2;
26559
27254
  }
26560
27255
  async function startOrchestration(opts) {
26561
27256
  const repoPath = opts.repoPath?.trim();
@@ -26615,7 +27310,7 @@ async function startOrchestration(opts) {
26615
27310
  }
26616
27311
  return updated;
26617
27312
  }
26618
- var import_node_events, import_node_crypto16, import_node_fs67, LIVE_TURN_SPAWN_GRACE_MS, RUN_SCRIPT_DESKTOP_ADOPT_MS, STALE_AGENT_PID_WAIT_MS, LIGHT_RECONCILE_THROTTLE_MS, Orchestrator, singleton;
27313
+ var import_node_events, import_node_crypto18, import_node_fs67, LIVE_TURN_SPAWN_GRACE_MS, RUN_SCRIPT_DESKTOP_ADOPT_MS, STALE_AGENT_PID_WAIT_MS, LIGHT_RECONCILE_THROTTLE_MS, Orchestrator, singleton2;
26619
27314
  var init_orchestrator = __esm({
26620
27315
  "src/orchestrator/orchestrator.ts"() {
26621
27316
  "use strict";
@@ -26623,7 +27318,7 @@ var init_orchestrator = __esm({
26623
27318
  init_injected_notices();
26624
27319
  init_task_state();
26625
27320
  init_wait_for_turn();
26626
- import_node_crypto16 = require("crypto");
27321
+ import_node_crypto18 = require("crypto");
26627
27322
  import_node_fs67 = require("fs");
26628
27323
  init_error_detail();
26629
27324
  init_run();
@@ -26649,6 +27344,7 @@ var init_orchestrator = __esm({
26649
27344
  init_usage();
26650
27345
  init_thread_store();
26651
27346
  init_desktop_host();
27347
+ init_model_context();
26652
27348
  init_agent_block();
26653
27349
  init_child_halt();
26654
27350
  init_stop_reason();
@@ -27647,6 +28343,7 @@ ${formatEnvReminder(projectNameForRepoPath(thread.repoPath || thread.worktreePat
27647
28343
  orchestrationReminder,
27648
28344
  prGateDirective,
27649
28345
  injectedNoticeContext,
28346
+ takeMcpAppModelContext(threadId),
27650
28347
  expandedPrompt
27651
28348
  ].filter(Boolean).join("\n\n");
27652
28349
  if (!autoContinue && sentAttachments) {
@@ -28275,7 +28972,7 @@ ${formatEnvReminder(projectNameForRepoPath(thread.repoPath || thread.worktreePat
28275
28972
  const request = sameIntent ? pending : {
28276
28973
  op,
28277
28974
  scriptName: scriptName ?? null,
28278
- requestId: (0, import_node_crypto16.randomUUID)(),
28975
+ requestId: (0, import_node_crypto18.randomUUID)(),
28279
28976
  requestedAt: (/* @__PURE__ */ new Date()).toISOString()
28280
28977
  };
28281
28978
  if (!sameIntent) {
@@ -29396,7 +30093,7 @@ ${formatEnvReminder(projectNameForRepoPath(thread.repoPath || thread.worktreePat
29396
30093
  return thread;
29397
30094
  }
29398
30095
  };
29399
- singleton = null;
30096
+ singleton2 = null;
29400
30097
  }
29401
30098
  });
29402
30099
 
@@ -29405,7 +30102,7 @@ init_nested_electron_env();
29405
30102
  init_system_ca();
29406
30103
 
29407
30104
  // src/mcp/server.ts
29408
- var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
30105
+ var import_stdio2 = require("@modelcontextprotocol/sdk/server/stdio.js");
29409
30106
 
29410
30107
  // src/mcp/wrap-mcp-tools.ts
29411
30108
  var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
@@ -29516,7 +30213,7 @@ function createClippedMcpServer() {
29516
30213
 
29517
30214
  // src/mcp/server.ts
29518
30215
  var import_zod11 = require("zod");
29519
- var import_node_crypto20 = require("crypto");
30216
+ var import_node_crypto22 = require("crypto");
29520
30217
  var import_node_path68 = require("path");
29521
30218
  init_orchestrator();
29522
30219
  init_task_state();
@@ -30028,8 +30725,8 @@ init_fetch();
30028
30725
  init_issue_attachments();
30029
30726
 
30030
30727
  // src/integrations/linear-oauth.ts
30031
- var import_node_crypto17 = require("crypto");
30032
- var import_node_http2 = require("http");
30728
+ var import_node_crypto19 = require("crypto");
30729
+ var import_node_http3 = require("http");
30033
30730
  init_app_settings();
30034
30731
  init_fetch();
30035
30732
 
@@ -33014,7 +33711,7 @@ function registerScheduleTools(server) {
33014
33711
  }
33015
33712
 
33016
33713
  // src/agent-rpc/handlers.ts
33017
- var import_node_crypto18 = require("crypto");
33714
+ var import_node_crypto20 = require("crypto");
33018
33715
  var import_node_path65 = require("path");
33019
33716
  init_wait_for_job();
33020
33717
  init_wait_for_turn();
@@ -33061,7 +33758,7 @@ setToolPermissionPublisher({
33061
33758
  // src/agent-rpc/handlers.ts
33062
33759
  init_protocol2();
33063
33760
  function presentArtifactResult(input) {
33064
- const id = input.artifact_id?.trim() || `artifact_${Date.now().toString(36)}_${(0, import_node_crypto18.randomUUID)().slice(0, 8)}`;
33761
+ const id = input.artifact_id?.trim() || `artifact_${Date.now().toString(36)}_${(0, import_node_crypto20.randomUUID)().slice(0, 8)}`;
33065
33762
  return {
33066
33763
  ok: true,
33067
33764
  artifact_id: id,
@@ -33086,7 +33783,7 @@ init_worktree();
33086
33783
  init_paths();
33087
33784
 
33088
33785
  // src/board/board-pins.ts
33089
- var import_node_crypto19 = require("crypto");
33786
+ var import_node_crypto21 = require("crypto");
33090
33787
  var import_node_fs68 = require("fs");
33091
33788
  var import_node_path66 = require("path");
33092
33789
  init_paths();
@@ -34036,7 +34733,7 @@ async function startMcpServer() {
34036
34733
  const ident = issue?.identifier ?? ref.trim();
34037
34734
  const attachments = issue ? [
34038
34735
  {
34039
- id: (0, import_node_crypto20.randomUUID)(),
34736
+ id: (0, import_node_crypto22.randomUUID)(),
34040
34737
  name: issue.identifier,
34041
34738
  kind: "issue",
34042
34739
  content: [
@@ -34589,7 +35286,7 @@ async function startMcpServer() {
34589
35286
  }
34590
35287
  );
34591
35288
  }
34592
- const transport = new import_stdio.StdioServerTransport();
35289
+ const transport = new import_stdio2.StdioServerTransport();
34593
35290
  await server.connect(transport);
34594
35291
  }
34595
35292