@sideboard-ai/core 0.1.311 → 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.js CHANGED
@@ -188,6 +188,7 @@ import {
188
188
  stampNotifyBlock,
189
189
  stampPlanBlock,
190
190
  startOrchestration,
191
+ stashMcpAppModelContext,
191
192
  statWorktreePath,
192
193
  syncBoardPins,
193
194
  takePendingTurnAttachments,
@@ -201,7 +202,7 @@ import {
201
202
  worktreeCleanupSettings,
202
203
  writeAgentBlock,
203
204
  writeWorktreeFile
204
- } from "./chunk-2ER7DQJP.js";
205
+ } from "./chunk-VIVXKN5N.js";
205
206
  import {
206
207
  LEGACY_PLAN_FILE_REL,
207
208
  PLAN_FILE_NAME,
@@ -237,9 +238,9 @@ import {
237
238
  buildClaudeStreamJsonUserMessage,
238
239
  claudeAdapter,
239
240
  claudeUsageOverLimitWindows,
241
+ closeMcpUiHost,
240
242
  codexAdapter,
241
243
  countCacheControlBlocks,
242
- cspFromMeta,
243
244
  cursorAdapter,
244
245
  decodeBrightsyTarget,
245
246
  dropCachedPrefixOnResume,
@@ -256,8 +257,8 @@ import {
256
257
  formatClaudeUsageTooltip,
257
258
  getAdapter,
258
259
  getClaudePlanUsage,
260
+ getMcpUiHost,
259
261
  hottestClaudeWindow,
260
- htmlFromResourceContent,
261
262
  isBrightsyConnected,
262
263
  isCursorApiKeyConfigured,
263
264
  isCursorAutoModel,
@@ -268,15 +269,12 @@ import {
268
269
  listCursorModels,
269
270
  listModelsForAgent,
270
271
  listOpencodeModels,
271
- listUserClaudeMcpServerEntries,
272
- matchClaudeMcpTool,
273
272
  mcpStatusThinkingFromClaudeInit,
274
273
  mcpUiContentSecurityPolicy,
275
274
  mergeSideboardIntoMcpServersJson,
276
275
  normalizeTurnInput,
277
276
  opencodeAdapter,
278
277
  parseClaudeUsagePayload,
279
- parseMcpServerLaunch,
280
278
  parseSessionQuotaResetAt,
281
279
  permissionMode,
282
280
  planModeTurnInstruction,
@@ -289,13 +287,12 @@ import {
289
287
  sideboardMcpProfile,
290
288
  splitTurnInputForSystemPrompt,
291
289
  threadRequestsBrightsyMcp,
292
- uiResourceUriFromMeta,
293
290
  userClaudeMcpConfigPath,
294
291
  userCursorMcpConfigPath,
295
292
  userMcpNamesToDisable,
296
293
  worktreeMcpToolNames,
297
294
  writeInjectedMcpConfig
298
- } from "./chunk-4YBQBVYL.js";
295
+ } from "./chunk-4FZUUH6W.js";
299
296
  import {
300
297
  brightsyMcpServerName,
301
298
  connectBrightsyTeam,
@@ -1662,208 +1659,6 @@ function buildPathRefAttachment(input) {
1662
1659
  };
1663
1660
  }
1664
1661
 
1665
- // src/mcp-ui/host.ts
1666
- import { homedir } from "os";
1667
-
1668
- // src/mcp-ui/session.ts
1669
- import { Client } from "@modelcontextprotocol/sdk/client/index.js";
1670
- import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
1671
- import { StdioClientTransport, getDefaultEnvironment } from "@modelcontextprotocol/sdk/client/stdio.js";
1672
- import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
1673
- var REQUEST_TIMEOUT_MS = 2e4;
1674
- var UI_CAPABILITIES = {
1675
- extensions: {
1676
- "io.modelcontextprotocol/ui": {
1677
- mimeTypes: ["text/html;profile=mcp-app"]
1678
- }
1679
- }
1680
- };
1681
- async function openMcpUiSession(launch) {
1682
- return openMcpUiSessionFromTransport(transportForLaunch(launch));
1683
- }
1684
- async function openMcpUiSessionFromTransport(transport) {
1685
- const client = new Client(
1686
- { name: "sideboard", version: "1.0.0" },
1687
- { capabilities: UI_CAPABILITIES }
1688
- );
1689
- await client.connect(transport, { timeout: REQUEST_TIMEOUT_MS });
1690
- return {
1691
- async listTools() {
1692
- const listed = await client.listTools(void 0, { timeout: REQUEST_TIMEOUT_MS });
1693
- return listed.tools.map((tool) => {
1694
- const meta = tool._meta;
1695
- return {
1696
- name: tool.name,
1697
- ...tool.description ? { description: tool.description } : {},
1698
- ...tool.inputSchema ? { inputSchema: tool.inputSchema } : {},
1699
- resourceUri: uiResourceUriFromMeta(meta),
1700
- ...cspFromMeta(meta) ? { csp: cspFromMeta(meta) } : {}
1701
- };
1702
- });
1703
- },
1704
- async readResource(uri) {
1705
- const result = await client.readResource({ uri }, { timeout: REQUEST_TIMEOUT_MS });
1706
- const content = result.contents?.[0];
1707
- if (!content) return null;
1708
- const text5 = "text" in content && typeof content.text === "string" ? content.text : void 0;
1709
- const blob = "blob" in content && typeof content.blob === "string" ? content.blob : void 0;
1710
- return {
1711
- uri: content.uri,
1712
- ...content.mimeType ? { mimeType: content.mimeType } : {},
1713
- ...text5 != null ? { text: text5 } : {},
1714
- ...blob != null ? { blob } : {},
1715
- ...cspFromMeta(content._meta) ? { csp: cspFromMeta(content._meta) } : {}
1716
- };
1717
- },
1718
- async callTool(name, args) {
1719
- return client.callTool({ name, arguments: args }, void 0, { timeout: REQUEST_TIMEOUT_MS });
1720
- },
1721
- async close() {
1722
- await client.close();
1723
- }
1724
- };
1725
- }
1726
- function transportForLaunch(launch) {
1727
- if (launch.kind === "stdio") {
1728
- return new StdioClientTransport({
1729
- command: launch.command,
1730
- args: launch.args,
1731
- env: { ...getDefaultEnvironment(), ...launch.env },
1732
- stderr: "ignore",
1733
- ...launch.cwd ? { cwd: launch.cwd } : {}
1734
- });
1735
- }
1736
- const url = new URL(launch.url);
1737
- const requestInit = launch.headers ? { headers: launch.headers } : void 0;
1738
- if (launch.kind === "sse") {
1739
- return new SSEClientTransport(url, requestInit ? { requestInit } : void 0);
1740
- }
1741
- return new StreamableHTTPClientTransport(url, requestInit ? { requestInit } : void 0);
1742
- }
1743
-
1744
- // src/mcp-ui/host.ts
1745
- var TOOL_TTL_MS = 5 * 60 * 1e3;
1746
- var McpUiHost = class {
1747
- constructor(opts) {
1748
- this.opts = opts;
1749
- }
1750
- opts;
1751
- sessions = /* @__PURE__ */ new Map();
1752
- toolLists = /* @__PURE__ */ new Map();
1753
- async viewForClaudeTool(toolName, projectDirs) {
1754
- const entries = this.userEntries(projectDirs);
1755
- const match = matchClaudeMcpTool(toolName, Object.keys(entries));
1756
- if (!match) return null;
1757
- const launch = parseMcpServerLaunch(entries[match.server] ?? {});
1758
- if (!launch) return null;
1759
- try {
1760
- const session = await this.sessionFor(match.server, launch);
1761
- const tools = await this.toolsFor(match.server, launch, session);
1762
- const tool = tools.find((item) => item.name === match.tool);
1763
- if (!tool?.resourceUri) return null;
1764
- const resource = await session.readResource(tool.resourceUri);
1765
- if (!resource) return null;
1766
- const html = htmlFromResourceContent(resource);
1767
- if (!html) return null;
1768
- const csp = resource.csp ?? tool.csp;
1769
- return {
1770
- server: match.server,
1771
- tool: match.tool,
1772
- uri: html.uri,
1773
- mimeType: html.mimeType,
1774
- html: html.html,
1775
- csp: mcpUiContentSecurityPolicy(csp)
1776
- };
1777
- } catch (err) {
1778
- console.error(
1779
- `[mcp-ui] ${match.server}/${match.tool}:`,
1780
- err instanceof Error ? err.message : err
1781
- );
1782
- return null;
1783
- }
1784
- }
1785
- async callTool(server, tool, args, projectDirs) {
1786
- const session = await this.sessionForName(server, projectDirs);
1787
- if (!session) throw new Error(`MCP server ${server} is not available`);
1788
- return session.callTool(tool, args);
1789
- }
1790
- async readResource(server, uri, projectDirs) {
1791
- const session = await this.sessionForName(server, projectDirs);
1792
- if (!session) throw new Error(`MCP server ${server} is not available`);
1793
- const resource = await session.readResource(uri);
1794
- if (!resource) throw new Error(`Resource ${uri} was empty`);
1795
- return {
1796
- contents: [
1797
- {
1798
- uri: resource.uri,
1799
- ...resource.mimeType ? { mimeType: resource.mimeType } : {},
1800
- ...resource.text != null ? { text: resource.text } : {},
1801
- ...resource.blob != null ? { blob: resource.blob } : {}
1802
- }
1803
- ]
1804
- };
1805
- }
1806
- async closeAll() {
1807
- const pending = [...this.sessions.values()];
1808
- this.sessions.clear();
1809
- this.toolLists.clear();
1810
- await Promise.all(
1811
- pending.map((session) => session.then((open) => open.close()).catch(() => void 0))
1812
- );
1813
- }
1814
- userEntries(projectDirs) {
1815
- const out = {};
1816
- for (const [name, entry] of Object.entries(this.opts.entries(projectDirs))) {
1817
- if (!name.trim() || isInjectedOrchMcpName(name) || !entry) continue;
1818
- out[name] = entry;
1819
- }
1820
- return out;
1821
- }
1822
- async sessionForName(server, projectDirs) {
1823
- const entry = this.userEntries(projectDirs)[server];
1824
- if (!entry) return null;
1825
- const launch = parseMcpServerLaunch(entry);
1826
- if (!launch) return null;
1827
- return this.sessionFor(server, launch);
1828
- }
1829
- sessionFor(server, launch) {
1830
- const key = `${server}
1831
- ${JSON.stringify(launch)}`;
1832
- const existing = this.sessions.get(key);
1833
- if (existing) return existing;
1834
- const open = this.opts.openSession ?? openMcpUiSession;
1835
- const pending = open(launch).catch((err) => {
1836
- this.sessions.delete(key);
1837
- throw err;
1838
- });
1839
- this.sessions.set(key, pending);
1840
- return pending;
1841
- }
1842
- async toolsFor(server, launch, session) {
1843
- const key = `${server}
1844
- ${JSON.stringify(launch)}`;
1845
- const cached2 = this.toolLists.get(key);
1846
- if (cached2 && cached2.key === key && Date.now() - cached2.at < TOOL_TTL_MS) return cached2.tools;
1847
- const tools = await session.listTools();
1848
- this.toolLists.set(key, { at: Date.now(), key, tools });
1849
- return tools;
1850
- }
1851
- };
1852
- var singleton;
1853
- function getMcpUiHost() {
1854
- if (!singleton) {
1855
- singleton = new McpUiHost({
1856
- entries: (projectDirs) => listUserClaudeMcpServerEntries(homedir(), projectDirs)
1857
- });
1858
- }
1859
- return singleton;
1860
- }
1861
- function closeMcpUiHost() {
1862
- const host = singleton;
1863
- singleton = void 0;
1864
- if (host) void host.closeAll();
1865
- }
1866
-
1867
1662
  // src/remote/phone-chats.ts
1868
1663
  import { randomUUID as randomUUID2 } from "crypto";
1869
1664
 
@@ -2454,13 +2249,21 @@ function parsePhoneMcpUi(value, op, chatId) {
2454
2249
  }
2455
2250
  return { op: "mcp-ui", chatId, tool: tool2, callId, reqId: reqId2 };
2456
2251
  }
2252
+ if (op === "mcp-ui-context") {
2253
+ const reqId2 = controlText(value, "reqId");
2254
+ const text5 = controlText(value, "text");
2255
+ if (!reqId2 || reqId2.length > 40 || !text5 || text5.length > 8e3) return "invalid";
2256
+ return { op, chatId, reqId: reqId2, text: text5 };
2257
+ }
2457
2258
  if (op !== "mcp-ui-call" && op !== "mcp-ui-read") return "invalid";
2458
2259
  const reqId = controlText(value, "reqId");
2459
2260
  const server = controlText(value, "server");
2460
2261
  if (!reqId || reqId.length > 40 || !server || server.length > 120) return "invalid";
2461
2262
  if (op === "mcp-ui-read") {
2462
2263
  const uri = controlText(value, "uri");
2463
- if (!uri.startsWith("ui://") || uri.length > 500) return "invalid";
2264
+ if (!uri || uri.length > 500 || /\s/.test(uri) || /^(javascript|data):/i.test(uri)) {
2265
+ return "invalid";
2266
+ }
2464
2267
  return { op, chatId, reqId, server, uri };
2465
2268
  }
2466
2269
  const tool = controlText(value, "tool");
@@ -2678,7 +2481,7 @@ function parsePhoneControl(value) {
2678
2481
  }
2679
2482
  if (op === "pane") return parsePhonePane(value, chatId);
2680
2483
  if (op === "open-artifact") return parseOpenArtifact(value, chatId);
2681
- if (op === "mcp-ui" || op === "mcp-ui-call" || op === "mcp-ui-read") return parsePhoneMcpUi(value, op, chatId);
2484
+ if (op === "mcp-ui" || op === "mcp-ui-call" || op === "mcp-ui-read" || op === "mcp-ui-context") return parsePhoneMcpUi(value, op, chatId);
2682
2485
  if (op === "open-file" || op === "media") {
2683
2486
  const path2 = textField(value, "path");
2684
2487
  if (!path2 || path2.length > 2e3) return "invalid";
@@ -3281,7 +3084,9 @@ function deliverPhoneTurn(opts, chatId) {
3281
3084
  // src/remote/phone-mcp-ui-listen.ts
3282
3085
  var PHONE_HTML_CAP = 7e5;
3283
3086
  function dispatchPhoneMcpUi(cmd, opts) {
3284
- if (cmd.op !== "mcp-ui" && cmd.op !== "mcp-ui-call" && cmd.op !== "mcp-ui-read") return false;
3087
+ if (cmd.op !== "mcp-ui" && cmd.op !== "mcp-ui-call" && cmd.op !== "mcp-ui-read" && cmd.op !== "mcp-ui-context") {
3088
+ return false;
3089
+ }
3285
3090
  const thread = readPhoneThread(cmd.chatId);
3286
3091
  const reqId = cmd.reqId;
3287
3092
  const chatId = cmd.chatId;
@@ -3291,6 +3096,11 @@ function dispatchPhoneMcpUi(cmd, opts) {
3291
3096
  return true;
3292
3097
  }
3293
3098
  const projectDirs = [thread.repoPath, thread.worktreePath];
3099
+ if (cmd.op === "mcp-ui-context") {
3100
+ stashMcpAppModelContext(thread.id, cmd.text);
3101
+ emitControl(opts, { op: "mcp-ui-context", chatId, reqId, result: {} });
3102
+ return true;
3103
+ }
3294
3104
  if (cmd.op === "mcp-ui-call") {
3295
3105
  void getMcpUiHost().callTool(cmd.server, cmd.tool, cmd.args, projectDirs).then((result) => emitControl(opts, { op: "mcp-ui-call", chatId, reqId, result })).catch(
3296
3106
  (err) => emitControl(opts, { op: "mcp-ui-call", chatId, reqId, error: phoneError(err) })
@@ -8917,7 +8727,7 @@ async function startHeadlessHost(opts) {
8917
8727
  };
8918
8728
  const refreshRunning = async () => {
8919
8729
  try {
8920
- const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-2CCFGYAA.js");
8730
+ const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-BYTSILLH.js");
8921
8731
  agentsRunning = getOrchestrator2().getRuntime().running;
8922
8732
  } catch {
8923
8733
  agentsRunning = 0;
@@ -10849,7 +10659,7 @@ async function handleJobStop(params, _ctx) {
10849
10659
  return stopDetachedJob(jobCwd(rec), id, reason ? { reason } : void 0);
10850
10660
  }
10851
10661
  async function defaultTurnWait(ref, timeoutMs) {
10852
- const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-2CCFGYAA.js");
10662
+ const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-BYTSILLH.js");
10853
10663
  const orch = getOrchestrator2();
10854
10664
  const thread = await orch.waitForTurn(ref, timeoutMs, {
10855
10665
  resolveIfStillRunning: true
@@ -14225,7 +14035,7 @@ async function continueSourceThread(threadId, prompt) {
14225
14035
  await continueOnReply(threadId, prompt);
14226
14036
  return;
14227
14037
  }
14228
- const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-2CCFGYAA.js");
14038
+ const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-BYTSILLH.js");
14229
14039
  await getOrchestrator2().send(threadId, prompt);
14230
14040
  } catch {
14231
14041
  }
@@ -15477,6 +15287,7 @@ export {
15477
15287
  startRelayServer,
15478
15288
  startRemoteAccountLogin,
15479
15289
  startSlackOAuth,
15290
+ stashMcpAppModelContext,
15480
15291
  statWorktreePath,
15481
15292
  stopAgentRpcServer,
15482
15293
  stripBrightsyNdjsonNoise,