@sideboard-ai/core 0.1.302 → 0.1.303
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/agents/claude-runner.cjs +28 -7
- package/dist/agents/claude-runner.js +22 -8
- package/dist/{agents-V2SRC2LH.js → agents-3GN4E2X3.js} +5 -5
- package/dist/{agents-ETD2LWP4.js → agents-XLHFVC64.js} +4 -4
- package/dist/{chunk-FUXOZHHF.js → chunk-3TZRSKFJ.js} +4 -4
- package/dist/{chunk-JTW4CZEQ.js → chunk-545DY7CQ.js} +13 -13
- package/dist/{chunk-3XDU7RIE.js → chunk-5MVOZLN7.js} +1 -1
- package/dist/{chunk-2KJE53ZJ.js → chunk-7AYOOG77.js} +5 -4
- package/dist/{chunk-7SEWZXPT.js → chunk-BRFDPV7Z.js} +2 -2
- package/dist/{chunk-EP4IIKP4.js → chunk-DW6NNYUJ.js} +4 -4
- package/dist/{chunk-FO3NKZVJ.js → chunk-F2PVRF3B.js} +9 -0
- package/dist/{chunk-KIWICTLW.js → chunk-GEFH4QFX.js} +1 -1
- package/dist/{chunk-FPJFK4LB.js → chunk-GS6O65Q2.js} +11 -11
- package/dist/{chunk-WV33I2GC.js → chunk-P2GHFJOB.js} +1 -1
- package/dist/{chunk-OJKSDRZU.js → chunk-RAGDMEIB.js} +4 -4
- package/dist/{chunk-LZ744H2I.js → chunk-YCDHLK2Z.js} +2 -2
- package/dist/{conductor-57UKACQA.js → conductor-2AVFGSQJ.js} +4 -4
- package/dist/{conductor-57KZLWTB.js → conductor-ATST6OMC.js} +5 -5
- package/dist/{coordinator-prompt-VOWUJRVJ.js → coordinator-prompt-CQPUNMRX.js} +4 -4
- package/dist/{coordinator-prompt-2TBRFJZ5.js → coordinator-prompt-TIAI6A47.js} +3 -3
- package/dist/{global-workspace-V6SOEETA.js → global-workspace-7YABMLQG.js} +4 -4
- package/dist/{global-workspace-T5C7EMVV.js → global-workspace-UZJUHGQP.js} +3 -3
- package/dist/index.cjs +851 -367
- package/dist/index.d.cts +104 -2
- package/dist/index.d.ts +104 -2
- package/dist/index.js +825 -354
- package/dist/mcp/run-stdio.js +6 -6
- package/dist/{orchestrator-C43M3JDK.js → orchestrator-COX6QO2B.js} +6 -6
- package/dist/{orchestrator-JEF7JC3S.js → orchestrator-CZPRDLHV.js} +7 -7
- package/dist/{thread-store-POAYB2ID.js → thread-store-PNX4HVLO.js} +2 -2
- package/dist/{thread-store-BMNJEJUH.js → thread-store-VC4AIKN3.js} +1 -1
- package/dist/{workspaces-EWVIEJ4O.js → workspaces-6DJL4IST.js} +4 -4
- package/dist/{workspaces-7ZYTTB4A.js → workspaces-GZ7F5EJR.js} +3 -3
- package/dist/{worktree-2Q6J2VWZ.js → worktree-2BYVRYPJ.js} +3 -3
- package/dist/{worktree-ZAJGYKCB.js → worktree-VXPOY2LE.js} +2 -2
- package/package.json +1 -1
- /package/dist/{chunk-FBZODCO4.js → chunk-FA3V56KF.js} +0 -0
package/dist/index.cjs
CHANGED
|
@@ -65,6 +65,14 @@ function parseMcpList(text7) {
|
|
|
65
65
|
function sanitizeMcpServerName(name) {
|
|
66
66
|
return name.replace(/[^A-Za-z0-9_-]/g, "_");
|
|
67
67
|
}
|
|
68
|
+
function isClaudeAiConnectorMcp(toolName, serverName, serverSource) {
|
|
69
|
+
if (!toolName.startsWith("mcp__")) return false;
|
|
70
|
+
if (serverSource === "claudeai") return true;
|
|
71
|
+
if (serverName && /^claude\.ai\b/i.test(serverName.trim())) return true;
|
|
72
|
+
if (/^mcp__claude_ai_/i.test(toolName)) return true;
|
|
73
|
+
const id = mcpServerIdForPermission(toolName, serverName);
|
|
74
|
+
return id != null && id.startsWith("claude_ai_");
|
|
75
|
+
}
|
|
68
76
|
function mcpServerIdForPermission(toolName, serverName) {
|
|
69
77
|
if (toolName.startsWith("mcp__")) {
|
|
70
78
|
const rest = toolName.slice("mcp__".length);
|
|
@@ -31334,6 +31342,7 @@ __export(index_exports, {
|
|
|
31334
31342
|
clipAgentEventForPaint: () => clipAgentEventForPaint,
|
|
31335
31343
|
clipThinkingForStore: () => clipThinkingForStore,
|
|
31336
31344
|
cloneRepoIntoSideboard: () => cloneRepoIntoSideboard,
|
|
31345
|
+
closeMcpUiHost: () => closeMcpUiHost,
|
|
31337
31346
|
codeRefRangeLabel: () => codeRefRangeLabel,
|
|
31338
31347
|
codexAdapter: () => codexAdapter,
|
|
31339
31348
|
codexSandboxWritableRootsArgs: () => codexSandboxWritableRootsArgs,
|
|
@@ -31556,6 +31565,7 @@ __export(index_exports, {
|
|
|
31556
31565
|
getLinearApiKey: () => getLinearApiKey,
|
|
31557
31566
|
getLinearAuthToken: () => getLinearAuthToken,
|
|
31558
31567
|
getLinearIssue: () => getLinearIssue,
|
|
31568
|
+
getMcpUiHost: () => getMcpUiHost,
|
|
31559
31569
|
getOrchestrator: () => getOrchestrator,
|
|
31560
31570
|
getPr: () => getPr,
|
|
31561
31571
|
getPrChecks: () => getPrChecks,
|
|
@@ -31621,6 +31631,7 @@ __export(index_exports, {
|
|
|
31621
31631
|
isBrightsyConnected: () => isBrightsyConnected,
|
|
31622
31632
|
isBrightsyNdjsonLine: () => isBrightsyNdjsonLine,
|
|
31623
31633
|
isChatTextScale: () => isChatTextScale,
|
|
31634
|
+
isClaudeAiConnectorMcp: () => isClaudeAiConnectorMcp,
|
|
31624
31635
|
isCloudCoordinatorThread: () => isCloudCoordinatorThread,
|
|
31625
31636
|
isCompactToolName: () => isCompactToolName,
|
|
31626
31637
|
isConductorBundledCli: () => isConductorBundledCli,
|
|
@@ -31775,6 +31786,7 @@ __export(index_exports, {
|
|
|
31775
31786
|
mcpServerIdForPermission: () => mcpServerIdForPermission,
|
|
31776
31787
|
mcpServerPermissionUpdate: () => mcpServerPermissionUpdate,
|
|
31777
31788
|
mcpStatusThinkingFromClaudeInit: () => mcpStatusThinkingFromClaudeInit,
|
|
31789
|
+
mcpUiContentSecurityPolicy: () => mcpUiContentSecurityPolicy,
|
|
31778
31790
|
mentionsPrGoal: () => mentionsPrGoal,
|
|
31779
31791
|
mergeAgentGitAuthEnv: () => mergeAgentGitAuthEnv,
|
|
31780
31792
|
mergePr: () => mergePr,
|
|
@@ -38886,6 +38898,362 @@ init_injected_mcp();
|
|
|
38886
38898
|
init_user_mcp_config();
|
|
38887
38899
|
init_orch_mcp_isolation();
|
|
38888
38900
|
|
|
38901
|
+
// src/mcp-ui/host.ts
|
|
38902
|
+
init_orch_mcp_isolation();
|
|
38903
|
+
|
|
38904
|
+
// src/mcp-ui/meta.ts
|
|
38905
|
+
var HTML_MAX = 15e5;
|
|
38906
|
+
function matchClaudeMcpTool(toolName, serverNames) {
|
|
38907
|
+
const name = toolName.trim();
|
|
38908
|
+
if (!name.startsWith("mcp__")) return null;
|
|
38909
|
+
const ranked = [...serverNames].filter((s) => s.trim()).sort((a, b) => b.length - a.length);
|
|
38910
|
+
for (const server of ranked) {
|
|
38911
|
+
const prefix = `mcp__${server}__`;
|
|
38912
|
+
if (!name.startsWith(prefix)) continue;
|
|
38913
|
+
const tool = name.slice(prefix.length).trim();
|
|
38914
|
+
if (!tool) continue;
|
|
38915
|
+
return { server, tool };
|
|
38916
|
+
}
|
|
38917
|
+
return null;
|
|
38918
|
+
}
|
|
38919
|
+
function parseMcpServerLaunch(entry) {
|
|
38920
|
+
const command = typeof entry.command === "string" ? entry.command.trim() : "";
|
|
38921
|
+
if (command) {
|
|
38922
|
+
const args = Array.isArray(entry.args) ? entry.args.filter((a) => typeof a === "string") : [];
|
|
38923
|
+
const env = stringRecord(entry.env);
|
|
38924
|
+
const cwd = typeof entry.cwd === "string" && entry.cwd.trim() ? entry.cwd.trim() : void 0;
|
|
38925
|
+
return {
|
|
38926
|
+
kind: "stdio",
|
|
38927
|
+
command,
|
|
38928
|
+
args,
|
|
38929
|
+
...env ? { env } : {},
|
|
38930
|
+
...cwd ? { cwd } : {}
|
|
38931
|
+
};
|
|
38932
|
+
}
|
|
38933
|
+
const url = typeof entry.url === "string" ? entry.url.trim() : "";
|
|
38934
|
+
if (!url) return null;
|
|
38935
|
+
let parsed;
|
|
38936
|
+
try {
|
|
38937
|
+
parsed = new URL(url);
|
|
38938
|
+
} catch {
|
|
38939
|
+
return null;
|
|
38940
|
+
}
|
|
38941
|
+
if (parsed.protocol !== "https:" && parsed.protocol !== "http:") return null;
|
|
38942
|
+
const type = typeof entry.type === "string" ? entry.type.trim().toLowerCase() : "";
|
|
38943
|
+
const headers = stringRecord(entry.headers);
|
|
38944
|
+
return {
|
|
38945
|
+
kind: type === "sse" ? "sse" : "http",
|
|
38946
|
+
url: parsed.toString(),
|
|
38947
|
+
...headers ? { headers } : {}
|
|
38948
|
+
};
|
|
38949
|
+
}
|
|
38950
|
+
function uiResourceUriFromMeta(meta) {
|
|
38951
|
+
const rec = asRecord15(meta);
|
|
38952
|
+
const nested = asRecord15(rec.ui);
|
|
38953
|
+
const fromNested = typeof nested.resourceUri === "string" ? nested.resourceUri.trim() : "";
|
|
38954
|
+
const legacy = typeof rec["ui/resourceUri"] === "string" ? rec["ui/resourceUri"].trim() : "";
|
|
38955
|
+
const uri = fromNested || legacy;
|
|
38956
|
+
return uri.startsWith("ui://") ? uri : null;
|
|
38957
|
+
}
|
|
38958
|
+
function cspFromMeta(meta) {
|
|
38959
|
+
const ui = asRecord15(asRecord15(meta).ui);
|
|
38960
|
+
const csp = asRecord15(ui.csp);
|
|
38961
|
+
const connectDomains = originList(csp.connectDomains);
|
|
38962
|
+
const resourceDomains = originList(csp.resourceDomains);
|
|
38963
|
+
const frameDomains = originList(csp.frameDomains);
|
|
38964
|
+
const baseUriDomains = originList(csp.baseUriDomains);
|
|
38965
|
+
if (!connectDomains?.length && !resourceDomains?.length && !frameDomains?.length && !baseUriDomains?.length) {
|
|
38966
|
+
return void 0;
|
|
38967
|
+
}
|
|
38968
|
+
return {
|
|
38969
|
+
...connectDomains?.length ? { connectDomains } : {},
|
|
38970
|
+
...resourceDomains?.length ? { resourceDomains } : {},
|
|
38971
|
+
...frameDomains?.length ? { frameDomains } : {},
|
|
38972
|
+
...baseUriDomains?.length ? { baseUriDomains } : {}
|
|
38973
|
+
};
|
|
38974
|
+
}
|
|
38975
|
+
function htmlFromResourceContent(content) {
|
|
38976
|
+
const uri = content.uri?.trim() ?? "";
|
|
38977
|
+
if (!uri.startsWith("ui://")) return null;
|
|
38978
|
+
const mimeType = content.mimeType?.trim() || "text/html";
|
|
38979
|
+
if (!isHtmlMime(mimeType)) return null;
|
|
38980
|
+
const html = htmlText(content.text, content.blob);
|
|
38981
|
+
if (!html) return null;
|
|
38982
|
+
return { uri, mimeType, html };
|
|
38983
|
+
}
|
|
38984
|
+
function mcpUiContentSecurityPolicy(csp) {
|
|
38985
|
+
const resource = (csp?.resourceDomains ?? []).join(" ");
|
|
38986
|
+
const connect = (csp?.connectDomains ?? []).join(" ");
|
|
38987
|
+
const frames = csp?.frameDomains?.length ? csp.frameDomains.join(" ") : "'none'";
|
|
38988
|
+
const base = csp?.baseUriDomains?.length ? csp.baseUriDomains.join(" ") : "'none'";
|
|
38989
|
+
return [
|
|
38990
|
+
"default-src 'none'",
|
|
38991
|
+
`script-src 'self' 'unsafe-inline' 'unsafe-eval' ${resource}`.trim(),
|
|
38992
|
+
`style-src 'self' 'unsafe-inline' ${resource}`.trim(),
|
|
38993
|
+
`img-src 'self' data: blob: ${resource}`.trim(),
|
|
38994
|
+
`font-src 'self' data: ${resource}`.trim(),
|
|
38995
|
+
`connect-src 'self' ${connect}`.trim(),
|
|
38996
|
+
`media-src 'self' data: blob: ${resource}`.trim(),
|
|
38997
|
+
`frame-src ${frames}`,
|
|
38998
|
+
`base-uri ${base}`,
|
|
38999
|
+
"object-src 'none'",
|
|
39000
|
+
"form-action 'self'"
|
|
39001
|
+
].join("; ");
|
|
39002
|
+
}
|
|
39003
|
+
function htmlText(text7, blob) {
|
|
39004
|
+
if (typeof text7 === "string" && text7.trim()) {
|
|
39005
|
+
return text7.length <= HTML_MAX ? text7 : null;
|
|
39006
|
+
}
|
|
39007
|
+
if (typeof blob !== "string" || !blob.trim()) return null;
|
|
39008
|
+
try {
|
|
39009
|
+
const decoded = decodeBase64(blob.trim());
|
|
39010
|
+
if (!decoded.trim() || decoded.length > HTML_MAX) return null;
|
|
39011
|
+
return decoded;
|
|
39012
|
+
} catch {
|
|
39013
|
+
return null;
|
|
39014
|
+
}
|
|
39015
|
+
}
|
|
39016
|
+
function decodeBase64(blob) {
|
|
39017
|
+
if (typeof Buffer !== "undefined") return Buffer.from(blob, "base64").toString("utf8");
|
|
39018
|
+
const bin = atob(blob);
|
|
39019
|
+
const bytes = Uint8Array.from(bin, (c) => c.charCodeAt(0));
|
|
39020
|
+
return new TextDecoder().decode(bytes);
|
|
39021
|
+
}
|
|
39022
|
+
function isHtmlMime(mime) {
|
|
39023
|
+
const base = mime.split(";")[0]?.trim().toLowerCase() ?? "";
|
|
39024
|
+
return base === "text/html";
|
|
39025
|
+
}
|
|
39026
|
+
function originList(value) {
|
|
39027
|
+
if (!Array.isArray(value)) return void 0;
|
|
39028
|
+
const out = [];
|
|
39029
|
+
for (const item of value) {
|
|
39030
|
+
if (typeof item !== "string") continue;
|
|
39031
|
+
const origin = originToken(item);
|
|
39032
|
+
if (origin && !out.includes(origin)) out.push(origin);
|
|
39033
|
+
}
|
|
39034
|
+
return out;
|
|
39035
|
+
}
|
|
39036
|
+
function originToken(value) {
|
|
39037
|
+
try {
|
|
39038
|
+
const url = new URL(value.trim());
|
|
39039
|
+
if (url.protocol !== "https:" && url.protocol !== "http:" && url.protocol !== "wss:" && url.protocol !== "ws:") {
|
|
39040
|
+
return null;
|
|
39041
|
+
}
|
|
39042
|
+
return url.origin;
|
|
39043
|
+
} catch {
|
|
39044
|
+
return null;
|
|
39045
|
+
}
|
|
39046
|
+
}
|
|
39047
|
+
function stringRecord(value) {
|
|
39048
|
+
const rec = asRecord15(value);
|
|
39049
|
+
const out = {};
|
|
39050
|
+
for (const [key, item] of Object.entries(rec)) {
|
|
39051
|
+
if (typeof item === "string") out[key] = item;
|
|
39052
|
+
}
|
|
39053
|
+
return Object.keys(out).length > 0 ? out : void 0;
|
|
39054
|
+
}
|
|
39055
|
+
function asRecord15(value) {
|
|
39056
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return {};
|
|
39057
|
+
return value;
|
|
39058
|
+
}
|
|
39059
|
+
|
|
39060
|
+
// src/mcp-ui/session.ts
|
|
39061
|
+
var import_client3 = require("@modelcontextprotocol/sdk/client/index.js");
|
|
39062
|
+
var import_sse = require("@modelcontextprotocol/sdk/client/sse.js");
|
|
39063
|
+
var import_stdio2 = require("@modelcontextprotocol/sdk/client/stdio.js");
|
|
39064
|
+
var import_streamableHttp = require("@modelcontextprotocol/sdk/client/streamableHttp.js");
|
|
39065
|
+
var REQUEST_TIMEOUT_MS = 2e4;
|
|
39066
|
+
var UI_CAPABILITIES = {
|
|
39067
|
+
extensions: {
|
|
39068
|
+
"io.modelcontextprotocol/ui": {
|
|
39069
|
+
mimeTypes: ["text/html;profile=mcp-app"]
|
|
39070
|
+
}
|
|
39071
|
+
}
|
|
39072
|
+
};
|
|
39073
|
+
async function openMcpUiSession(launch) {
|
|
39074
|
+
return openMcpUiSessionFromTransport(transportForLaunch(launch));
|
|
39075
|
+
}
|
|
39076
|
+
async function openMcpUiSessionFromTransport(transport) {
|
|
39077
|
+
const client = new import_client3.Client(
|
|
39078
|
+
{ name: "sideboard", version: "1.0.0" },
|
|
39079
|
+
{ capabilities: UI_CAPABILITIES }
|
|
39080
|
+
);
|
|
39081
|
+
await client.connect(transport, { timeout: REQUEST_TIMEOUT_MS });
|
|
39082
|
+
return {
|
|
39083
|
+
async listTools() {
|
|
39084
|
+
const listed = await client.listTools(void 0, { timeout: REQUEST_TIMEOUT_MS });
|
|
39085
|
+
return listed.tools.map((tool) => {
|
|
39086
|
+
const meta = tool._meta;
|
|
39087
|
+
return {
|
|
39088
|
+
name: tool.name,
|
|
39089
|
+
...tool.description ? { description: tool.description } : {},
|
|
39090
|
+
...tool.inputSchema ? { inputSchema: tool.inputSchema } : {},
|
|
39091
|
+
resourceUri: uiResourceUriFromMeta(meta),
|
|
39092
|
+
...cspFromMeta(meta) ? { csp: cspFromMeta(meta) } : {}
|
|
39093
|
+
};
|
|
39094
|
+
});
|
|
39095
|
+
},
|
|
39096
|
+
async readResource(uri) {
|
|
39097
|
+
const result = await client.readResource({ uri }, { timeout: REQUEST_TIMEOUT_MS });
|
|
39098
|
+
const content = result.contents?.[0];
|
|
39099
|
+
if (!content) return null;
|
|
39100
|
+
const text7 = "text" in content && typeof content.text === "string" ? content.text : void 0;
|
|
39101
|
+
const blob = "blob" in content && typeof content.blob === "string" ? content.blob : void 0;
|
|
39102
|
+
return {
|
|
39103
|
+
uri: content.uri,
|
|
39104
|
+
...content.mimeType ? { mimeType: content.mimeType } : {},
|
|
39105
|
+
...text7 != null ? { text: text7 } : {},
|
|
39106
|
+
...blob != null ? { blob } : {},
|
|
39107
|
+
...cspFromMeta(content._meta) ? { csp: cspFromMeta(content._meta) } : {}
|
|
39108
|
+
};
|
|
39109
|
+
},
|
|
39110
|
+
async callTool(name, args) {
|
|
39111
|
+
return client.callTool({ name, arguments: args }, void 0, { timeout: REQUEST_TIMEOUT_MS });
|
|
39112
|
+
},
|
|
39113
|
+
async close() {
|
|
39114
|
+
await client.close();
|
|
39115
|
+
}
|
|
39116
|
+
};
|
|
39117
|
+
}
|
|
39118
|
+
function transportForLaunch(launch) {
|
|
39119
|
+
if (launch.kind === "stdio") {
|
|
39120
|
+
return new import_stdio2.StdioClientTransport({
|
|
39121
|
+
command: launch.command,
|
|
39122
|
+
args: launch.args,
|
|
39123
|
+
env: { ...(0, import_stdio2.getDefaultEnvironment)(), ...launch.env },
|
|
39124
|
+
stderr: "ignore",
|
|
39125
|
+
...launch.cwd ? { cwd: launch.cwd } : {}
|
|
39126
|
+
});
|
|
39127
|
+
}
|
|
39128
|
+
const url = new URL(launch.url);
|
|
39129
|
+
const requestInit = launch.headers ? { headers: launch.headers } : void 0;
|
|
39130
|
+
if (launch.kind === "sse") {
|
|
39131
|
+
return new import_sse.SSEClientTransport(url, requestInit ? { requestInit } : void 0);
|
|
39132
|
+
}
|
|
39133
|
+
return new import_streamableHttp.StreamableHTTPClientTransport(url, requestInit ? { requestInit } : void 0);
|
|
39134
|
+
}
|
|
39135
|
+
|
|
39136
|
+
// src/mcp-ui/host.ts
|
|
39137
|
+
var TOOL_TTL_MS = 5 * 60 * 1e3;
|
|
39138
|
+
var McpUiHost = class {
|
|
39139
|
+
constructor(opts) {
|
|
39140
|
+
this.opts = opts;
|
|
39141
|
+
}
|
|
39142
|
+
opts;
|
|
39143
|
+
sessions = /* @__PURE__ */ new Map();
|
|
39144
|
+
toolLists = /* @__PURE__ */ new Map();
|
|
39145
|
+
async viewForClaudeTool(toolName) {
|
|
39146
|
+
const entries = this.userEntries();
|
|
39147
|
+
const match = matchClaudeMcpTool(toolName, Object.keys(entries));
|
|
39148
|
+
if (!match) return null;
|
|
39149
|
+
const launch = parseMcpServerLaunch(entries[match.server] ?? {});
|
|
39150
|
+
if (!launch) return null;
|
|
39151
|
+
try {
|
|
39152
|
+
const session = await this.sessionFor(match.server, launch);
|
|
39153
|
+
const tools = await this.toolsFor(match.server, launch, session);
|
|
39154
|
+
const tool = tools.find((item) => item.name === match.tool);
|
|
39155
|
+
if (!tool?.resourceUri) return null;
|
|
39156
|
+
const resource = await session.readResource(tool.resourceUri);
|
|
39157
|
+
if (!resource) return null;
|
|
39158
|
+
const html = htmlFromResourceContent(resource);
|
|
39159
|
+
if (!html) return null;
|
|
39160
|
+
const csp = resource.csp ?? tool.csp;
|
|
39161
|
+
return {
|
|
39162
|
+
server: match.server,
|
|
39163
|
+
tool: match.tool,
|
|
39164
|
+
uri: html.uri,
|
|
39165
|
+
mimeType: html.mimeType,
|
|
39166
|
+
html: html.html,
|
|
39167
|
+
csp: mcpUiContentSecurityPolicy(csp)
|
|
39168
|
+
};
|
|
39169
|
+
} catch (err) {
|
|
39170
|
+
console.error(
|
|
39171
|
+
`[mcp-ui] ${match.server}/${match.tool}:`,
|
|
39172
|
+
err instanceof Error ? err.message : err
|
|
39173
|
+
);
|
|
39174
|
+
return null;
|
|
39175
|
+
}
|
|
39176
|
+
}
|
|
39177
|
+
async callTool(server, tool, args) {
|
|
39178
|
+
const session = await this.sessionForName(server);
|
|
39179
|
+
if (!session) throw new Error(`MCP server ${server} is not available`);
|
|
39180
|
+
return session.callTool(tool, args);
|
|
39181
|
+
}
|
|
39182
|
+
async readResource(server, uri) {
|
|
39183
|
+
const session = await this.sessionForName(server);
|
|
39184
|
+
if (!session) throw new Error(`MCP server ${server} is not available`);
|
|
39185
|
+
const resource = await session.readResource(uri);
|
|
39186
|
+
if (!resource) throw new Error(`Resource ${uri} was empty`);
|
|
39187
|
+
return {
|
|
39188
|
+
contents: [
|
|
39189
|
+
{
|
|
39190
|
+
uri: resource.uri,
|
|
39191
|
+
...resource.mimeType ? { mimeType: resource.mimeType } : {},
|
|
39192
|
+
...resource.text != null ? { text: resource.text } : {},
|
|
39193
|
+
...resource.blob != null ? { blob: resource.blob } : {}
|
|
39194
|
+
}
|
|
39195
|
+
]
|
|
39196
|
+
};
|
|
39197
|
+
}
|
|
39198
|
+
async closeAll() {
|
|
39199
|
+
const pending = [...this.sessions.values()];
|
|
39200
|
+
this.sessions.clear();
|
|
39201
|
+
this.toolLists.clear();
|
|
39202
|
+
await Promise.all(
|
|
39203
|
+
pending.map((session) => session.then((open) => open.close()).catch(() => void 0))
|
|
39204
|
+
);
|
|
39205
|
+
}
|
|
39206
|
+
userEntries() {
|
|
39207
|
+
const out = {};
|
|
39208
|
+
for (const [name, entry] of Object.entries(this.opts.entries())) {
|
|
39209
|
+
if (!name.trim() || isInjectedOrchMcpName(name) || !entry) continue;
|
|
39210
|
+
out[name] = entry;
|
|
39211
|
+
}
|
|
39212
|
+
return out;
|
|
39213
|
+
}
|
|
39214
|
+
async sessionForName(server) {
|
|
39215
|
+
const entry = this.userEntries()[server];
|
|
39216
|
+
if (!entry) return null;
|
|
39217
|
+
const launch = parseMcpServerLaunch(entry);
|
|
39218
|
+
if (!launch) return null;
|
|
39219
|
+
return this.sessionFor(server, launch);
|
|
39220
|
+
}
|
|
39221
|
+
sessionFor(server, launch) {
|
|
39222
|
+
const key = `${server}
|
|
39223
|
+
${JSON.stringify(launch)}`;
|
|
39224
|
+
const existing = this.sessions.get(key);
|
|
39225
|
+
if (existing) return existing;
|
|
39226
|
+
const open = this.opts.openSession ?? openMcpUiSession;
|
|
39227
|
+
const pending = open(launch).catch((err) => {
|
|
39228
|
+
this.sessions.delete(key);
|
|
39229
|
+
throw err;
|
|
39230
|
+
});
|
|
39231
|
+
this.sessions.set(key, pending);
|
|
39232
|
+
return pending;
|
|
39233
|
+
}
|
|
39234
|
+
async toolsFor(server, launch, session) {
|
|
39235
|
+
const key = `${server}
|
|
39236
|
+
${JSON.stringify(launch)}`;
|
|
39237
|
+
const cached2 = this.toolLists.get(key);
|
|
39238
|
+
if (cached2 && cached2.key === key && Date.now() - cached2.at < TOOL_TTL_MS) return cached2.tools;
|
|
39239
|
+
const tools = await session.listTools();
|
|
39240
|
+
this.toolLists.set(key, { at: Date.now(), key, tools });
|
|
39241
|
+
return tools;
|
|
39242
|
+
}
|
|
39243
|
+
};
|
|
39244
|
+
var singleton2;
|
|
39245
|
+
function getMcpUiHost() {
|
|
39246
|
+
if (!singleton2) {
|
|
39247
|
+
singleton2 = new McpUiHost({ entries: () => listUserClaudeMcpServerEntries() });
|
|
39248
|
+
}
|
|
39249
|
+
return singleton2;
|
|
39250
|
+
}
|
|
39251
|
+
function closeMcpUiHost() {
|
|
39252
|
+
const host = singleton2;
|
|
39253
|
+
singleton2 = void 0;
|
|
39254
|
+
if (host) void host.closeAll();
|
|
39255
|
+
}
|
|
39256
|
+
|
|
38889
39257
|
// src/slack/workspaces.ts
|
|
38890
39258
|
var import_node_path69 = require("path");
|
|
38891
39259
|
init_paths();
|
|
@@ -40972,132 +41340,21 @@ var import_ws5 = require("ws");
|
|
|
40972
41340
|
init_orchestrator_capable();
|
|
40973
41341
|
init_stage_files();
|
|
40974
41342
|
init_orchestrator();
|
|
40975
|
-
init_app_settings();
|
|
40976
|
-
init_implied_first_prompt();
|
|
40977
|
-
init_message_parts();
|
|
40978
|
-
init_turn_live();
|
|
40979
41343
|
|
|
40980
|
-
// src/remote/phone-
|
|
40981
|
-
var
|
|
40982
|
-
|
|
40983
|
-
|
|
40984
|
-
|
|
40985
|
-
|
|
40986
|
-
|
|
40987
|
-
|
|
40988
|
-
|
|
40989
|
-
|
|
40990
|
-
|
|
40991
|
-
|
|
40992
|
-
|
|
40993
|
-
|
|
40994
|
-
};
|
|
40995
|
-
function phoneWorktreeRelative(worktreePath, raw) {
|
|
40996
|
-
let text7 = raw.trim();
|
|
40997
|
-
if (!text7) return null;
|
|
40998
|
-
if (/^file:\/\//i.test(text7)) {
|
|
40999
|
-
try {
|
|
41000
|
-
text7 = decodeURIComponent(new URL(text7).pathname);
|
|
41001
|
-
} catch {
|
|
41002
|
-
return null;
|
|
41003
|
-
}
|
|
41004
|
-
}
|
|
41005
|
-
text7 = (text7.split("#")[0] ?? text7).replace(/\\/g, "/");
|
|
41006
|
-
if (!text7 || text7.includes("\0") || text7.split("/").includes("..")) return null;
|
|
41007
|
-
const root = worktreePath.replace(/\/+$/, "");
|
|
41008
|
-
if (!root || root === "/") return null;
|
|
41009
|
-
if (text7.startsWith("/")) {
|
|
41010
|
-
if (text7 !== root && !text7.startsWith(`${root}/`)) return null;
|
|
41011
|
-
text7 = text7 === root ? "" : text7.slice(root.length + 1);
|
|
41012
|
-
}
|
|
41013
|
-
text7 = text7.replace(/^\.\//, "").replace(/\/+$/, "");
|
|
41014
|
-
if (!text7 || text7 === "." || text7.startsWith("/")) return null;
|
|
41015
|
-
return text7;
|
|
41016
|
-
}
|
|
41017
|
-
function phoneImageMime(relativePath) {
|
|
41018
|
-
const ext = relativePath.split(".").pop()?.toLowerCase() ?? "";
|
|
41019
|
-
return IMAGE_MIME[ext] ?? null;
|
|
41020
|
-
}
|
|
41021
|
-
function phoneImageDataUrl(worktreePath, raw) {
|
|
41022
|
-
const relative = phoneWorktreeRelative(worktreePath, raw);
|
|
41023
|
-
if (!relative) return null;
|
|
41024
|
-
const mime = phoneImageMime(relative);
|
|
41025
|
-
if (!mime) return null;
|
|
41026
|
-
try {
|
|
41027
|
-
const file = readWorktreeFileForUpload(worktreePath, relative, { maxBytes: PHONE_IMAGE_MAX_BYTES });
|
|
41028
|
-
return `data:${mime};base64,${file.contentBase64}`;
|
|
41029
|
-
} catch {
|
|
41030
|
-
return null;
|
|
41031
|
-
}
|
|
41032
|
-
}
|
|
41033
|
-
function phoneDirectoryListing(worktreePath, relative) {
|
|
41034
|
-
try {
|
|
41035
|
-
const entries = (0, import_node_fs71.readdirSync)((0, import_node_path71.join)(worktreePath, relative), { withFileTypes: true });
|
|
41036
|
-
const dirs = new Set(entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name));
|
|
41037
|
-
const names = entries.map((entry) => entry.name).filter((name) => name && !name.includes("/") && !name.includes("\0")).sort((a, b) => a.localeCompare(b));
|
|
41038
|
-
const shown = names.slice(0, PHONE_DIR_MAX);
|
|
41039
|
-
const lines = shown.map((name) => dirs.has(name) ? `${name}/` : name);
|
|
41040
|
-
const truncated = names.length > shown.length;
|
|
41041
|
-
if (truncated) lines.push(`\u2026 ${names.length - shown.length} more`);
|
|
41042
|
-
return { content: lines.join("\n"), truncated };
|
|
41043
|
-
} catch {
|
|
41044
|
-
return null;
|
|
41045
|
-
}
|
|
41046
|
-
}
|
|
41047
|
-
function phoneFilePreview(worktreePath, relative, kind) {
|
|
41048
|
-
if (kind === "dir") {
|
|
41049
|
-
const listing = phoneDirectoryListing(worktreePath, relative);
|
|
41050
|
-
if (!listing) return null;
|
|
41051
|
-
return {
|
|
41052
|
-
content: listing.content,
|
|
41053
|
-
encoding: "utf8",
|
|
41054
|
-
binary: false,
|
|
41055
|
-
directory: true,
|
|
41056
|
-
truncated: listing.truncated
|
|
41057
|
-
};
|
|
41058
|
-
}
|
|
41059
|
-
if (relative.toLowerCase().endsWith(".svg")) {
|
|
41060
|
-
try {
|
|
41061
|
-
const buf = (0, import_node_fs71.readFileSync)((0, import_node_path71.join)(worktreePath, relative));
|
|
41062
|
-
const truncated = buf.length > PHONE_TEXT_MAX_BYTES;
|
|
41063
|
-
return {
|
|
41064
|
-
content: buf.subarray(0, PHONE_TEXT_MAX_BYTES).toString("utf8"),
|
|
41065
|
-
encoding: "utf8",
|
|
41066
|
-
binary: false,
|
|
41067
|
-
directory: false,
|
|
41068
|
-
truncated,
|
|
41069
|
-
mime: "image/svg+xml"
|
|
41070
|
-
};
|
|
41071
|
-
} catch {
|
|
41072
|
-
return null;
|
|
41073
|
-
}
|
|
41074
|
-
}
|
|
41075
|
-
const mime = phoneImageMime(relative);
|
|
41076
|
-
if (mime) {
|
|
41077
|
-
const dataUrl = phoneImageDataUrl(worktreePath, relative);
|
|
41078
|
-
if (!dataUrl) return null;
|
|
41079
|
-
return {
|
|
41080
|
-
content: dataUrl,
|
|
41081
|
-
encoding: "base64",
|
|
41082
|
-
binary: true,
|
|
41083
|
-
directory: false,
|
|
41084
|
-
truncated: false,
|
|
41085
|
-
mime
|
|
41086
|
-
};
|
|
41087
|
-
}
|
|
41088
|
-
try {
|
|
41089
|
-
const file = readWorktreeFile(worktreePath, relative, { maxBytes: PHONE_TEXT_MAX_BYTES });
|
|
41090
|
-
return {
|
|
41091
|
-
content: file.content,
|
|
41092
|
-
encoding: file.encoding,
|
|
41093
|
-
binary: file.binary,
|
|
41094
|
-
directory: false,
|
|
41095
|
-
truncated: file.truncated
|
|
41096
|
-
};
|
|
41097
|
-
} catch {
|
|
41098
|
-
return null;
|
|
41099
|
-
}
|
|
41100
|
-
}
|
|
41344
|
+
// src/remote/phone-chats.ts
|
|
41345
|
+
var import_node_crypto27 = require("crypto");
|
|
41346
|
+
init_list_models();
|
|
41347
|
+
init_home_board();
|
|
41348
|
+
init_stage_files();
|
|
41349
|
+
init_worktree_labels();
|
|
41350
|
+
init_thinking_effort();
|
|
41351
|
+
init_app_settings();
|
|
41352
|
+
init_global_workspace();
|
|
41353
|
+
init_thread_store();
|
|
41354
|
+
init_workspaces();
|
|
41355
|
+
init_chat_tabs();
|
|
41356
|
+
init_create();
|
|
41357
|
+
init_orchestrator();
|
|
41101
41358
|
|
|
41102
41359
|
// src/remote/phone-artifact.ts
|
|
41103
41360
|
var FENCE_RE = /```([a-zA-Z0-9_+-]*)[^\n]*\n([\s\S]*?)(?:```|$)/g;
|
|
@@ -41107,10 +41364,10 @@ var MIN_MD_CHARS = 120;
|
|
|
41107
41364
|
function oneLine2(value, max) {
|
|
41108
41365
|
return value.replace(/[`\r\n]/g, " ").replace(/\s+/g, " ").trim().slice(0, max);
|
|
41109
41366
|
}
|
|
41110
|
-
function
|
|
41367
|
+
function asRecord16(value) {
|
|
41111
41368
|
if (typeof value === "string") {
|
|
41112
41369
|
try {
|
|
41113
|
-
return
|
|
41370
|
+
return asRecord16(JSON.parse(value));
|
|
41114
41371
|
} catch {
|
|
41115
41372
|
return void 0;
|
|
41116
41373
|
}
|
|
@@ -41185,7 +41442,7 @@ function toolContent(input) {
|
|
|
41185
41442
|
if (!input) return "";
|
|
41186
41443
|
const direct = input.content;
|
|
41187
41444
|
if (typeof direct === "string") return direct;
|
|
41188
|
-
const nested =
|
|
41445
|
+
const nested = asRecord16(direct);
|
|
41189
41446
|
if (!nested) return "";
|
|
41190
41447
|
for (const key of ["html", "markup", "text", "source", "content", "code"]) {
|
|
41191
41448
|
if (typeof nested[key] === "string") return nested[key];
|
|
@@ -41208,7 +41465,7 @@ function phoneArtifactText(text7, parts, limit = Number.POSITIVE_INFINITY) {
|
|
|
41208
41465
|
const extras = [];
|
|
41209
41466
|
for (const part of parts ?? []) {
|
|
41210
41467
|
if (part.type !== "tool" || part.parentId || !isArtifactTool(part.name)) continue;
|
|
41211
|
-
const input =
|
|
41468
|
+
const input = asRecord16(part.input);
|
|
41212
41469
|
const content = toolContent(input);
|
|
41213
41470
|
const hint = artifactHint(content);
|
|
41214
41471
|
if (hint && hints.has(hint)) continue;
|
|
@@ -41227,7 +41484,7 @@ function phoneArtifactText(text7, parts, limit = Number.POSITIVE_INFINITY) {
|
|
|
41227
41484
|
${tail}` : tail;
|
|
41228
41485
|
}
|
|
41229
41486
|
function parseOpenArtifact(value, chatId) {
|
|
41230
|
-
const record =
|
|
41487
|
+
const record = asRecord16(value);
|
|
41231
41488
|
if (!record) return "invalid";
|
|
41232
41489
|
const title = oneLine2(str7(record.title), 200);
|
|
41233
41490
|
if (!title) return "invalid";
|
|
@@ -41250,7 +41507,7 @@ function phoneArtifactDocuments(sources) {
|
|
|
41250
41507
|
}
|
|
41251
41508
|
for (const part of source.parts ?? []) {
|
|
41252
41509
|
if (part.type !== "tool" || part.parentId || !isArtifactTool(part.name)) continue;
|
|
41253
|
-
const input =
|
|
41510
|
+
const input = asRecord16(part.input);
|
|
41254
41511
|
const content = toolContent(input);
|
|
41255
41512
|
const hint = artifactHint(content);
|
|
41256
41513
|
if (hint && hints.has(hint)) continue;
|
|
@@ -41300,137 +41557,6 @@ function pickArtifactMatch(items, request) {
|
|
|
41300
41557
|
return null;
|
|
41301
41558
|
}
|
|
41302
41559
|
|
|
41303
|
-
// src/remote/phone-panes.ts
|
|
41304
|
-
init_orchestrator();
|
|
41305
|
-
var PHONE_CHANGE_SCOPES = ["last_turn", "uncommitted", "staged", "unstaged", "commits"];
|
|
41306
|
-
var PHONE_CHANGE_SCOPE_DEFAULT = "commits";
|
|
41307
|
-
function phoneChangeScope(value) {
|
|
41308
|
-
return typeof value === "string" && PHONE_CHANGE_SCOPES.includes(value) ? value : void 0;
|
|
41309
|
-
}
|
|
41310
|
-
function phoneCommitSha(value) {
|
|
41311
|
-
return typeof value === "string" && /^[0-9a-f]{4,40}$/i.test(value) ? value : void 0;
|
|
41312
|
-
}
|
|
41313
|
-
var MAX_ROWS = 200;
|
|
41314
|
-
var MAX_QUERY = 200;
|
|
41315
|
-
function parsePhonePane(value, chatId) {
|
|
41316
|
-
const pane = value && typeof value === "object" ? value.pane : void 0;
|
|
41317
|
-
if (pane !== "files" && pane !== "changes" && pane !== "checks") return "invalid";
|
|
41318
|
-
const scope = phoneChangeScope(value.scope);
|
|
41319
|
-
const commitSha = phoneCommitSha(value.commitSha);
|
|
41320
|
-
const queryRaw = value.query;
|
|
41321
|
-
const query = typeof queryRaw === "string" ? queryRaw.trim().slice(0, MAX_QUERY) : "";
|
|
41322
|
-
return {
|
|
41323
|
-
op: "pane",
|
|
41324
|
-
chatId,
|
|
41325
|
-
pane,
|
|
41326
|
-
...scope && pane === "changes" ? { scope } : {},
|
|
41327
|
-
...commitSha && pane === "changes" && scope === "commits" ? { commitSha } : {},
|
|
41328
|
-
...query && pane === "files" ? { query } : {}
|
|
41329
|
-
};
|
|
41330
|
-
}
|
|
41331
|
-
function filterPhoneFiles(paths, query) {
|
|
41332
|
-
const q = query.trim().toLowerCase();
|
|
41333
|
-
if (!q) return paths;
|
|
41334
|
-
return paths.filter((path2) => path2.toLowerCase().includes(q));
|
|
41335
|
-
}
|
|
41336
|
-
async function readPhonePane(thread, pane, scope, query, commitSha) {
|
|
41337
|
-
try {
|
|
41338
|
-
if (pane === "files") return await readFiles(thread.id, query);
|
|
41339
|
-
if (pane === "changes") return await readChanges(thread.id, scope ?? PHONE_CHANGE_SCOPE_DEFAULT, commitSha);
|
|
41340
|
-
return await readChecks(thread.id);
|
|
41341
|
-
} catch (err) {
|
|
41342
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
41343
|
-
return { rows: [], note: message };
|
|
41344
|
-
}
|
|
41345
|
-
}
|
|
41346
|
-
async function readFiles(threadId, query) {
|
|
41347
|
-
const paths = filterPhoneFiles(await getOrchestrator().listFiles(threadId), query ?? "");
|
|
41348
|
-
const shown = paths.slice(0, MAX_ROWS);
|
|
41349
|
-
const extra = paths.length - shown.length;
|
|
41350
|
-
const note = extra > 0 ? query?.trim() ? `${extra} more matching files` : `${extra} more files on the Mac` : void 0;
|
|
41351
|
-
return {
|
|
41352
|
-
rows: shown.map((path2) => ({ label: path2, path: path2 })),
|
|
41353
|
-
...note ? { note } : {}
|
|
41354
|
-
};
|
|
41355
|
-
}
|
|
41356
|
-
async function readChanges(threadId, scope, commitSha) {
|
|
41357
|
-
const diff = await getOrchestrator().diff(threadId, {
|
|
41358
|
-
includePatches: false,
|
|
41359
|
-
scope,
|
|
41360
|
-
commitSha: scope === "commits" ? commitSha ?? null : null
|
|
41361
|
-
});
|
|
41362
|
-
const shown = diff.files.slice(0, MAX_ROWS);
|
|
41363
|
-
const selected = diff.commits.find((commit) => commit.sha === commitSha || commit.shortSha === commitSha);
|
|
41364
|
-
return {
|
|
41365
|
-
rows: shown.map((file) => {
|
|
41366
|
-
const detail = changeDetail(file.additions, file.deletions);
|
|
41367
|
-
return {
|
|
41368
|
-
label: file.path,
|
|
41369
|
-
path: file.path,
|
|
41370
|
-
...file.status ? { status: file.status } : {},
|
|
41371
|
-
...detail ? { detail } : {}
|
|
41372
|
-
};
|
|
41373
|
-
}),
|
|
41374
|
-
...diff.files.length > shown.length ? { note: `${diff.files.length - shown.length} more changed files` } : {},
|
|
41375
|
-
scope: diff.scope,
|
|
41376
|
-
commitSha: selected?.sha ?? null,
|
|
41377
|
-
...diff.base ? { base: diff.base } : {},
|
|
41378
|
-
hasLastTurnBase: diff.hasLastTurnBase,
|
|
41379
|
-
commits: diff.commits.slice(0, 40),
|
|
41380
|
-
scopeStats: diff.scopeStats
|
|
41381
|
-
};
|
|
41382
|
-
}
|
|
41383
|
-
function changeDetail(additions, deletions) {
|
|
41384
|
-
const add = additions ?? 0;
|
|
41385
|
-
const del = deletions ?? 0;
|
|
41386
|
-
if (add === 0 && del === 0) return void 0;
|
|
41387
|
-
return `+${add} \u2212${del}`;
|
|
41388
|
-
}
|
|
41389
|
-
async function readPhoneChangePatch(threadId, path2, scope = PHONE_CHANGE_SCOPE_DEFAULT, commitSha) {
|
|
41390
|
-
const diff = await getOrchestrator().diff(threadId, {
|
|
41391
|
-
path: path2,
|
|
41392
|
-
scope,
|
|
41393
|
-
commitSha: scope === "commits" ? commitSha ?? null : null,
|
|
41394
|
-
includePatches: true,
|
|
41395
|
-
includeMeta: false,
|
|
41396
|
-
includeUntracked: scope === "uncommitted" || scope === "unstaged" || scope === "last_turn" || scope === "commits" && !commitSha
|
|
41397
|
-
});
|
|
41398
|
-
const file = diff.files.find((row2) => row2.path === path2) ?? diff.files[0];
|
|
41399
|
-
if (!file) return null;
|
|
41400
|
-
const content = file.patch ?? "";
|
|
41401
|
-
return { content, truncated: content.includes("\u2026 truncated") };
|
|
41402
|
-
}
|
|
41403
|
-
async function readChecks(threadId) {
|
|
41404
|
-
const checks = await getOrchestrator().getPrChecks(threadId);
|
|
41405
|
-
if (!checks) return { rows: [], note: "No pull request on this branch." };
|
|
41406
|
-
const shown = checks.slice(0, MAX_ROWS);
|
|
41407
|
-
return {
|
|
41408
|
-
rows: shown.map((check) => ({
|
|
41409
|
-
label: check.name,
|
|
41410
|
-
detail: check.bucket || check.state,
|
|
41411
|
-
...check.link ? { href: check.link } : {}
|
|
41412
|
-
}))
|
|
41413
|
-
};
|
|
41414
|
-
}
|
|
41415
|
-
|
|
41416
|
-
// src/remote/phone-workspace-ops.ts
|
|
41417
|
-
init_orchestrator();
|
|
41418
|
-
|
|
41419
|
-
// src/remote/phone-chats.ts
|
|
41420
|
-
var import_node_crypto27 = require("crypto");
|
|
41421
|
-
init_list_models();
|
|
41422
|
-
init_home_board();
|
|
41423
|
-
init_stage_files();
|
|
41424
|
-
init_worktree_labels();
|
|
41425
|
-
init_thinking_effort();
|
|
41426
|
-
init_app_settings();
|
|
41427
|
-
init_global_workspace();
|
|
41428
|
-
init_thread_store();
|
|
41429
|
-
init_workspaces();
|
|
41430
|
-
init_chat_tabs();
|
|
41431
|
-
init_create();
|
|
41432
|
-
init_orchestrator();
|
|
41433
|
-
|
|
41434
41560
|
// src/remote/phone-header.ts
|
|
41435
41561
|
init_orchestrator();
|
|
41436
41562
|
init_global_workspace();
|
|
@@ -41594,6 +41720,119 @@ function parsePhoneCodeRefs(value) {
|
|
|
41594
41720
|
return refs;
|
|
41595
41721
|
}
|
|
41596
41722
|
|
|
41723
|
+
// src/remote/phone-panes.ts
|
|
41724
|
+
init_orchestrator();
|
|
41725
|
+
var PHONE_CHANGE_SCOPES = ["last_turn", "uncommitted", "staged", "unstaged", "commits"];
|
|
41726
|
+
var PHONE_CHANGE_SCOPE_DEFAULT = "commits";
|
|
41727
|
+
function phoneChangeScope(value) {
|
|
41728
|
+
return typeof value === "string" && PHONE_CHANGE_SCOPES.includes(value) ? value : void 0;
|
|
41729
|
+
}
|
|
41730
|
+
function phoneCommitSha(value) {
|
|
41731
|
+
return typeof value === "string" && /^[0-9a-f]{4,40}$/i.test(value) ? value : void 0;
|
|
41732
|
+
}
|
|
41733
|
+
var MAX_ROWS = 200;
|
|
41734
|
+
var MAX_QUERY = 200;
|
|
41735
|
+
function parsePhonePane(value, chatId) {
|
|
41736
|
+
const pane = value && typeof value === "object" ? value.pane : void 0;
|
|
41737
|
+
if (pane !== "files" && pane !== "changes" && pane !== "checks") return "invalid";
|
|
41738
|
+
const scope = phoneChangeScope(value.scope);
|
|
41739
|
+
const commitSha = phoneCommitSha(value.commitSha);
|
|
41740
|
+
const queryRaw = value.query;
|
|
41741
|
+
const query = typeof queryRaw === "string" ? queryRaw.trim().slice(0, MAX_QUERY) : "";
|
|
41742
|
+
return {
|
|
41743
|
+
op: "pane",
|
|
41744
|
+
chatId,
|
|
41745
|
+
pane,
|
|
41746
|
+
...scope && pane === "changes" ? { scope } : {},
|
|
41747
|
+
...commitSha && pane === "changes" && scope === "commits" ? { commitSha } : {},
|
|
41748
|
+
...query && pane === "files" ? { query } : {}
|
|
41749
|
+
};
|
|
41750
|
+
}
|
|
41751
|
+
function filterPhoneFiles(paths, query) {
|
|
41752
|
+
const q = query.trim().toLowerCase();
|
|
41753
|
+
if (!q) return paths;
|
|
41754
|
+
return paths.filter((path2) => path2.toLowerCase().includes(q));
|
|
41755
|
+
}
|
|
41756
|
+
async function readPhonePane(thread, pane, scope, query, commitSha) {
|
|
41757
|
+
try {
|
|
41758
|
+
if (pane === "files") return await readFiles(thread.id, query);
|
|
41759
|
+
if (pane === "changes") return await readChanges(thread.id, scope ?? PHONE_CHANGE_SCOPE_DEFAULT, commitSha);
|
|
41760
|
+
return await readChecks(thread.id);
|
|
41761
|
+
} catch (err) {
|
|
41762
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
41763
|
+
return { rows: [], note: message };
|
|
41764
|
+
}
|
|
41765
|
+
}
|
|
41766
|
+
async function readFiles(threadId, query) {
|
|
41767
|
+
const paths = filterPhoneFiles(await getOrchestrator().listFiles(threadId), query ?? "");
|
|
41768
|
+
const shown = paths.slice(0, MAX_ROWS);
|
|
41769
|
+
const extra = paths.length - shown.length;
|
|
41770
|
+
const note = extra > 0 ? query?.trim() ? `${extra} more matching files` : `${extra} more files on the Mac` : void 0;
|
|
41771
|
+
return {
|
|
41772
|
+
rows: shown.map((path2) => ({ label: path2, path: path2 })),
|
|
41773
|
+
...note ? { note } : {}
|
|
41774
|
+
};
|
|
41775
|
+
}
|
|
41776
|
+
async function readChanges(threadId, scope, commitSha) {
|
|
41777
|
+
const diff = await getOrchestrator().diff(threadId, {
|
|
41778
|
+
includePatches: false,
|
|
41779
|
+
scope,
|
|
41780
|
+
commitSha: scope === "commits" ? commitSha ?? null : null
|
|
41781
|
+
});
|
|
41782
|
+
const shown = diff.files.slice(0, MAX_ROWS);
|
|
41783
|
+
const selected = diff.commits.find((commit) => commit.sha === commitSha || commit.shortSha === commitSha);
|
|
41784
|
+
return {
|
|
41785
|
+
rows: shown.map((file) => {
|
|
41786
|
+
const detail = changeDetail(file.additions, file.deletions);
|
|
41787
|
+
return {
|
|
41788
|
+
label: file.path,
|
|
41789
|
+
path: file.path,
|
|
41790
|
+
...file.status ? { status: file.status } : {},
|
|
41791
|
+
...detail ? { detail } : {}
|
|
41792
|
+
};
|
|
41793
|
+
}),
|
|
41794
|
+
...diff.files.length > shown.length ? { note: `${diff.files.length - shown.length} more changed files` } : {},
|
|
41795
|
+
scope: diff.scope,
|
|
41796
|
+
commitSha: selected?.sha ?? null,
|
|
41797
|
+
...diff.base ? { base: diff.base } : {},
|
|
41798
|
+
hasLastTurnBase: diff.hasLastTurnBase,
|
|
41799
|
+
commits: diff.commits.slice(0, 40),
|
|
41800
|
+
scopeStats: diff.scopeStats
|
|
41801
|
+
};
|
|
41802
|
+
}
|
|
41803
|
+
function changeDetail(additions, deletions) {
|
|
41804
|
+
const add = additions ?? 0;
|
|
41805
|
+
const del = deletions ?? 0;
|
|
41806
|
+
if (add === 0 && del === 0) return void 0;
|
|
41807
|
+
return `+${add} \u2212${del}`;
|
|
41808
|
+
}
|
|
41809
|
+
async function readPhoneChangePatch(threadId, path2, scope = PHONE_CHANGE_SCOPE_DEFAULT, commitSha) {
|
|
41810
|
+
const diff = await getOrchestrator().diff(threadId, {
|
|
41811
|
+
path: path2,
|
|
41812
|
+
scope,
|
|
41813
|
+
commitSha: scope === "commits" ? commitSha ?? null : null,
|
|
41814
|
+
includePatches: true,
|
|
41815
|
+
includeMeta: false,
|
|
41816
|
+
includeUntracked: scope === "uncommitted" || scope === "unstaged" || scope === "last_turn" || scope === "commits" && !commitSha
|
|
41817
|
+
});
|
|
41818
|
+
const file = diff.files.find((row2) => row2.path === path2) ?? diff.files[0];
|
|
41819
|
+
if (!file) return null;
|
|
41820
|
+
const content = file.patch ?? "";
|
|
41821
|
+
return { content, truncated: content.includes("\u2026 truncated") };
|
|
41822
|
+
}
|
|
41823
|
+
async function readChecks(threadId) {
|
|
41824
|
+
const checks = await getOrchestrator().getPrChecks(threadId);
|
|
41825
|
+
if (!checks) return { rows: [], note: "No pull request on this branch." };
|
|
41826
|
+
const shown = checks.slice(0, MAX_ROWS);
|
|
41827
|
+
return {
|
|
41828
|
+
rows: shown.map((check) => ({
|
|
41829
|
+
label: check.name,
|
|
41830
|
+
detail: check.bucket || check.state,
|
|
41831
|
+
...check.link ? { href: check.link } : {}
|
|
41832
|
+
}))
|
|
41833
|
+
};
|
|
41834
|
+
}
|
|
41835
|
+
|
|
41597
41836
|
// src/remote/phone-defaults.ts
|
|
41598
41837
|
init_app_settings();
|
|
41599
41838
|
function row(resolved) {
|
|
@@ -41638,6 +41877,63 @@ function refreshPhoneViewerLogin(force = false) {
|
|
|
41638
41877
|
init_wait_for_job();
|
|
41639
41878
|
init_turn_live();
|
|
41640
41879
|
|
|
41880
|
+
// src/remote/phone-mcp-ui.ts
|
|
41881
|
+
var MAX_APPS = 4;
|
|
41882
|
+
function phoneMcpApps(agent, parts) {
|
|
41883
|
+
if (agent !== "claude" || !parts?.length) return [];
|
|
41884
|
+
const out = [];
|
|
41885
|
+
for (const part of parts) {
|
|
41886
|
+
if (part.type !== "tool" || part.parentId || part.status === "running") continue;
|
|
41887
|
+
if (!part.name.startsWith("mcp__") || part.name.startsWith("mcp__sideboard")) continue;
|
|
41888
|
+
out.push({ id: part.id, tool: part.name });
|
|
41889
|
+
if (out.length >= MAX_APPS) break;
|
|
41890
|
+
}
|
|
41891
|
+
return out;
|
|
41892
|
+
}
|
|
41893
|
+
function controlText(value, key) {
|
|
41894
|
+
const raw = value[key];
|
|
41895
|
+
return typeof raw === "string" ? raw.trim() : "";
|
|
41896
|
+
}
|
|
41897
|
+
function parsePhoneMcpUi(value, op, chatId) {
|
|
41898
|
+
if (op === "mcp-ui") {
|
|
41899
|
+
const tool2 = controlText(value, "tool");
|
|
41900
|
+
const callId = controlText(value, "callId");
|
|
41901
|
+
const reqId2 = controlText(value, "reqId");
|
|
41902
|
+
if (!tool2.startsWith("mcp__") || tool2.length > 200 || !callId || !reqId2 || reqId2.length > 40) {
|
|
41903
|
+
return "invalid";
|
|
41904
|
+
}
|
|
41905
|
+
return { op: "mcp-ui", chatId, tool: tool2, callId, reqId: reqId2 };
|
|
41906
|
+
}
|
|
41907
|
+
if (op !== "mcp-ui-call" && op !== "mcp-ui-read") return "invalid";
|
|
41908
|
+
const reqId = controlText(value, "reqId");
|
|
41909
|
+
const server = controlText(value, "server");
|
|
41910
|
+
if (!reqId || reqId.length > 40 || !server || server.length > 120) return "invalid";
|
|
41911
|
+
if (op === "mcp-ui-read") {
|
|
41912
|
+
const uri = controlText(value, "uri");
|
|
41913
|
+
if (!uri.startsWith("ui://") || uri.length > 500) return "invalid";
|
|
41914
|
+
return { op, chatId, reqId, server, uri };
|
|
41915
|
+
}
|
|
41916
|
+
const tool = controlText(value, "tool");
|
|
41917
|
+
const args = value.args;
|
|
41918
|
+
if (!tool || tool.length > 200 || !args || typeof args !== "object" || Array.isArray(args)) {
|
|
41919
|
+
return "invalid";
|
|
41920
|
+
}
|
|
41921
|
+
return { op, chatId, reqId, server, tool, args };
|
|
41922
|
+
}
|
|
41923
|
+
function phoneMcpToolPayload(parts, tool, callId) {
|
|
41924
|
+
if (!parts) return null;
|
|
41925
|
+
const matches = parts.filter(
|
|
41926
|
+
(part2) => part2.type === "tool" && part2.name === tool && !part2.parentId
|
|
41927
|
+
);
|
|
41928
|
+
const part = matches.find((row2) => row2.id === callId) ?? matches[matches.length - 1];
|
|
41929
|
+
if (!part) return null;
|
|
41930
|
+
return {
|
|
41931
|
+
input: part.input ?? {},
|
|
41932
|
+
resultText: part.result ?? "",
|
|
41933
|
+
isError: part.status === "error"
|
|
41934
|
+
};
|
|
41935
|
+
}
|
|
41936
|
+
|
|
41641
41937
|
// src/remote/phone-stream.ts
|
|
41642
41938
|
init_message_parts();
|
|
41643
41939
|
var PHONE_STREAM_FLUSH_MS = 80;
|
|
@@ -41697,7 +41993,8 @@ function listPhoneMessages(thread) {
|
|
|
41697
41993
|
const visible = [phoneVisibleText(message.role, message.text), names.length ? names.join(", ") : ""].filter(Boolean).join("\n");
|
|
41698
41994
|
const text7 = message.role === "agent" ? phoneArtifactText(visible, message.parts, MESSAGE_LIMIT) : clip(visible, MESSAGE_LIMIT);
|
|
41699
41995
|
if (!text7) continue;
|
|
41700
|
-
|
|
41996
|
+
const apps = message.role === "agent" ? phoneMcpApps(thread.agent, message.parts) : [];
|
|
41997
|
+
out.push({ role: message.role, text: text7, ...apps.length ? { apps } : {} });
|
|
41701
41998
|
}
|
|
41702
41999
|
const live = withLiveTail(thread, out);
|
|
41703
42000
|
for (const prompt of thread.queue) {
|
|
@@ -41827,6 +42124,7 @@ function parsePhoneControl(value) {
|
|
|
41827
42124
|
}
|
|
41828
42125
|
if (op === "pane") return parsePhonePane(value, chatId);
|
|
41829
42126
|
if (op === "open-artifact") return parseOpenArtifact(value, chatId);
|
|
42127
|
+
if (op === "mcp-ui" || op === "mcp-ui-call" || op === "mcp-ui-read") return parsePhoneMcpUi(value, op, chatId);
|
|
41830
42128
|
if (op === "open-file" || op === "media") {
|
|
41831
42129
|
const path2 = textField2(value, "path");
|
|
41832
42130
|
if (!path2 || path2.length > 2e3) return "invalid";
|
|
@@ -42242,109 +42540,6 @@ function archivePhoneChat(chatId) {
|
|
|
42242
42540
|
return true;
|
|
42243
42541
|
}
|
|
42244
42542
|
|
|
42245
|
-
// src/remote/phone-workspace-ops.ts
|
|
42246
|
-
function dispatchPhoneWorkspace(cmd, emit, publishOpened) {
|
|
42247
|
-
if (cmd.op === "pane") {
|
|
42248
|
-
const thread = readPhoneThread(cmd.chatId);
|
|
42249
|
-
if (!thread) {
|
|
42250
|
-
emit({ op: "error", chatId: cmd.chatId, message: "That agent is not on this Mac." });
|
|
42251
|
-
return;
|
|
42252
|
-
}
|
|
42253
|
-
void readPhonePane(thread, cmd.pane, cmd.scope, cmd.query, cmd.commitSha).then((body) => {
|
|
42254
|
-
emit({
|
|
42255
|
-
op: "pane",
|
|
42256
|
-
chatId: cmd.chatId,
|
|
42257
|
-
pane: cmd.pane,
|
|
42258
|
-
rows: body.rows,
|
|
42259
|
-
...body.note ? { note: body.note } : {},
|
|
42260
|
-
...cmd.pane === "files" ? { query: cmd.query ?? "" } : {},
|
|
42261
|
-
...cmd.pane === "changes" ? {
|
|
42262
|
-
scope: body.scope,
|
|
42263
|
-
commitSha: body.commitSha ?? null,
|
|
42264
|
-
...body.base ? { base: body.base } : {},
|
|
42265
|
-
hasLastTurnBase: body.hasLastTurnBase,
|
|
42266
|
-
commits: body.commits ?? [],
|
|
42267
|
-
...body.scopeStats ? { scopeStats: body.scopeStats } : {}
|
|
42268
|
-
} : {}
|
|
42269
|
-
});
|
|
42270
|
-
});
|
|
42271
|
-
return;
|
|
42272
|
-
}
|
|
42273
|
-
if (cmd.op === "header") {
|
|
42274
|
-
const thread = readPhoneThread(cmd.chatId);
|
|
42275
|
-
if (!thread) {
|
|
42276
|
-
emit({ op: "error", chatId: cmd.chatId, message: "That agent is not on this Mac." });
|
|
42277
|
-
return;
|
|
42278
|
-
}
|
|
42279
|
-
void readPhoneHeader(thread).then((header) => {
|
|
42280
|
-
emit({ op: "header", chatId: cmd.chatId, ...header });
|
|
42281
|
-
});
|
|
42282
|
-
return;
|
|
42283
|
-
}
|
|
42284
|
-
if (cmd.op === "git") {
|
|
42285
|
-
void getOrchestrator().askGit(cmd.chatId, cmd.action).then((tab) => publishOpened(tab.id)).catch((err) => {
|
|
42286
|
-
emit({
|
|
42287
|
-
op: "error",
|
|
42288
|
-
chatId: cmd.chatId,
|
|
42289
|
-
message: err instanceof Error ? err.message : String(err)
|
|
42290
|
-
});
|
|
42291
|
-
});
|
|
42292
|
-
return;
|
|
42293
|
-
}
|
|
42294
|
-
void getOrchestrator().requestReview(cmd.chatId).then((tab) => publishOpened(tab.id)).catch((err) => {
|
|
42295
|
-
emit({
|
|
42296
|
-
op: "error",
|
|
42297
|
-
chatId: cmd.chatId,
|
|
42298
|
-
message: err instanceof Error ? err.message : String(err)
|
|
42299
|
-
});
|
|
42300
|
-
});
|
|
42301
|
-
}
|
|
42302
|
-
|
|
42303
|
-
// src/remote/phone-sources.ts
|
|
42304
|
-
init_worktree();
|
|
42305
|
-
function sourceWarning(label, err) {
|
|
42306
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
42307
|
-
return message ? `${label}: ${message}` : `${label} failed.`;
|
|
42308
|
-
}
|
|
42309
|
-
async function listPhoneSources(repoPath, query) {
|
|
42310
|
-
const path2 = assertKnownProject(repoPath);
|
|
42311
|
-
const q = query?.trim() ?? "";
|
|
42312
|
-
const warnings = [];
|
|
42313
|
-
const [prs, branches, issues] = await Promise.all([
|
|
42314
|
-
listPrs(path2, { state: "open", limit: 40, ...q ? { query: q } : {} }).catch((err) => {
|
|
42315
|
-
warnings.push(sourceWarning("Pull requests", err));
|
|
42316
|
-
return [];
|
|
42317
|
-
}),
|
|
42318
|
-
listBranches(path2).catch((err) => {
|
|
42319
|
-
warnings.push(sourceWarning("Branches", err));
|
|
42320
|
-
return [];
|
|
42321
|
-
}),
|
|
42322
|
-
listIssues(path2, { limit: 40, ...q ? { query: q } : {} }).catch((err) => {
|
|
42323
|
-
warnings.push(sourceWarning("Issues", err));
|
|
42324
|
-
return { issues: [] };
|
|
42325
|
-
})
|
|
42326
|
-
]);
|
|
42327
|
-
const needle = q.toLowerCase();
|
|
42328
|
-
const branchRows = branches.filter((branch) => !needle || branch.name.toLowerCase().includes(needle)).slice(0, 50).map((branch) => ({
|
|
42329
|
-
ref: branch.name,
|
|
42330
|
-
title: branch.current ? `${branch.name} (current)` : branch.name
|
|
42331
|
-
}));
|
|
42332
|
-
return {
|
|
42333
|
-
prs: prs.slice(0, 40).map((pr) => ({
|
|
42334
|
-
ref: String(pr.number),
|
|
42335
|
-
title: clip(pr.title || `PR #${pr.number}`, 140),
|
|
42336
|
-
...pr.url ? { url: pr.url } : {}
|
|
42337
|
-
})),
|
|
42338
|
-
branches: branchRows,
|
|
42339
|
-
issues: (issues.issues ?? []).slice(0, 40).map((issue) => ({
|
|
42340
|
-
ref: issue.identifier,
|
|
42341
|
-
title: clip(issue.title || issue.identifier, 140),
|
|
42342
|
-
...issue.url ? { url: issue.url } : {}
|
|
42343
|
-
})),
|
|
42344
|
-
...warnings.length ? { warnings } : {}
|
|
42345
|
-
};
|
|
42346
|
-
}
|
|
42347
|
-
|
|
42348
42543
|
// src/remote/phone-live.ts
|
|
42349
42544
|
init_orchestrator();
|
|
42350
42545
|
init_ask_user();
|
|
@@ -42475,10 +42670,12 @@ function emitChatTurn(opts, chatId, threadId) {
|
|
|
42475
42670
|
failed: (detail) => detail ? `Sideboard failed: ${detail}` : "Sideboard failed before producing a result."
|
|
42476
42671
|
});
|
|
42477
42672
|
const agent = [...thread.messages].reverse().find((m) => m.role === "agent");
|
|
42673
|
+
const apps = phoneMcpApps(thread.agent, agent?.parts);
|
|
42478
42674
|
emitControl(opts, {
|
|
42479
42675
|
op: "assistant",
|
|
42480
42676
|
chatId,
|
|
42481
|
-
text: phoneArtifactText(reply.trim(), agent?.parts)
|
|
42677
|
+
text: phoneArtifactText(reply.trim(), agent?.parts),
|
|
42678
|
+
...apps.length ? { apps } : {}
|
|
42482
42679
|
});
|
|
42483
42680
|
}
|
|
42484
42681
|
function phoneError(err) {
|
|
@@ -42511,6 +42708,288 @@ function deliverPhoneTurn(opts, chatId) {
|
|
|
42511
42708
|
});
|
|
42512
42709
|
}
|
|
42513
42710
|
|
|
42711
|
+
// src/remote/phone-mcp-ui-listen.ts
|
|
42712
|
+
var PHONE_HTML_CAP = 7e5;
|
|
42713
|
+
function dispatchPhoneMcpUi(cmd, opts) {
|
|
42714
|
+
if (cmd.op !== "mcp-ui" && cmd.op !== "mcp-ui-call" && cmd.op !== "mcp-ui-read") return false;
|
|
42715
|
+
const thread = readPhoneThread(cmd.chatId);
|
|
42716
|
+
const reqId = cmd.reqId;
|
|
42717
|
+
const chatId = cmd.chatId;
|
|
42718
|
+
if (!thread || thread.agent !== "claude") {
|
|
42719
|
+
if (cmd.op === "mcp-ui") emitControl(opts, { op: "mcp-ui", chatId, reqId, view: null });
|
|
42720
|
+
else emitControl(opts, { op: cmd.op, chatId, reqId, error: "This chat is not using Claude." });
|
|
42721
|
+
return true;
|
|
42722
|
+
}
|
|
42723
|
+
if (cmd.op === "mcp-ui-call") {
|
|
42724
|
+
void getMcpUiHost().callTool(cmd.server, cmd.tool, cmd.args).then((result) => emitControl(opts, { op: "mcp-ui-call", chatId, reqId, result })).catch(
|
|
42725
|
+
(err) => emitControl(opts, { op: "mcp-ui-call", chatId, reqId, error: phoneError(err) })
|
|
42726
|
+
);
|
|
42727
|
+
return true;
|
|
42728
|
+
}
|
|
42729
|
+
if (cmd.op === "mcp-ui-read") {
|
|
42730
|
+
void getMcpUiHost().readResource(cmd.server, cmd.uri).then((result) => emitControl(opts, { op: "mcp-ui-read", chatId, reqId, result })).catch(
|
|
42731
|
+
(err) => emitControl(opts, { op: "mcp-ui-read", chatId, reqId, error: phoneError(err) })
|
|
42732
|
+
);
|
|
42733
|
+
return true;
|
|
42734
|
+
}
|
|
42735
|
+
const agentMessage = [...thread.messages].reverse().find((message) => message.role === "agent");
|
|
42736
|
+
const payload = phoneMcpToolPayload(agentMessage?.parts, cmd.tool, cmd.callId);
|
|
42737
|
+
void getMcpUiHost().viewForClaudeTool(cmd.tool).then((view) => {
|
|
42738
|
+
if (!view || view.html.length > PHONE_HTML_CAP) {
|
|
42739
|
+
emitControl(opts, { op: "mcp-ui", chatId, reqId, view: null });
|
|
42740
|
+
return;
|
|
42741
|
+
}
|
|
42742
|
+
emitControl(opts, {
|
|
42743
|
+
op: "mcp-ui",
|
|
42744
|
+
chatId,
|
|
42745
|
+
reqId,
|
|
42746
|
+
view: {
|
|
42747
|
+
server: view.server,
|
|
42748
|
+
tool: view.tool,
|
|
42749
|
+
html: view.html,
|
|
42750
|
+
csp: view.csp,
|
|
42751
|
+
uri: view.uri,
|
|
42752
|
+
input: payload?.input ?? {},
|
|
42753
|
+
resultText: payload?.resultText ?? "",
|
|
42754
|
+
isError: payload?.isError ?? false
|
|
42755
|
+
}
|
|
42756
|
+
});
|
|
42757
|
+
}).catch((err) => emitControl(opts, { op: "error", chatId, message: phoneError(err) }));
|
|
42758
|
+
return true;
|
|
42759
|
+
}
|
|
42760
|
+
|
|
42761
|
+
// src/remote/listen.ts
|
|
42762
|
+
init_app_settings();
|
|
42763
|
+
init_implied_first_prompt();
|
|
42764
|
+
init_message_parts();
|
|
42765
|
+
init_turn_live();
|
|
42766
|
+
|
|
42767
|
+
// src/remote/phone-media.ts
|
|
42768
|
+
var import_node_fs71 = require("fs");
|
|
42769
|
+
var import_node_path71 = require("path");
|
|
42770
|
+
init_diff();
|
|
42771
|
+
var PHONE_IMAGE_MAX_BYTES = 15e5;
|
|
42772
|
+
var PHONE_TEXT_MAX_BYTES = 18e4;
|
|
42773
|
+
var PHONE_DIR_MAX = 200;
|
|
42774
|
+
var IMAGE_MIME = {
|
|
42775
|
+
png: "image/png",
|
|
42776
|
+
jpg: "image/jpeg",
|
|
42777
|
+
jpeg: "image/jpeg",
|
|
42778
|
+
gif: "image/gif",
|
|
42779
|
+
webp: "image/webp",
|
|
42780
|
+
bmp: "image/bmp"
|
|
42781
|
+
};
|
|
42782
|
+
function phoneWorktreeRelative(worktreePath, raw) {
|
|
42783
|
+
let text7 = raw.trim();
|
|
42784
|
+
if (!text7) return null;
|
|
42785
|
+
if (/^file:\/\//i.test(text7)) {
|
|
42786
|
+
try {
|
|
42787
|
+
text7 = decodeURIComponent(new URL(text7).pathname);
|
|
42788
|
+
} catch {
|
|
42789
|
+
return null;
|
|
42790
|
+
}
|
|
42791
|
+
}
|
|
42792
|
+
text7 = (text7.split("#")[0] ?? text7).replace(/\\/g, "/");
|
|
42793
|
+
if (!text7 || text7.includes("\0") || text7.split("/").includes("..")) return null;
|
|
42794
|
+
const root = worktreePath.replace(/\/+$/, "");
|
|
42795
|
+
if (!root || root === "/") return null;
|
|
42796
|
+
if (text7.startsWith("/")) {
|
|
42797
|
+
if (text7 !== root && !text7.startsWith(`${root}/`)) return null;
|
|
42798
|
+
text7 = text7 === root ? "" : text7.slice(root.length + 1);
|
|
42799
|
+
}
|
|
42800
|
+
text7 = text7.replace(/^\.\//, "").replace(/\/+$/, "");
|
|
42801
|
+
if (!text7 || text7 === "." || text7.startsWith("/")) return null;
|
|
42802
|
+
return text7;
|
|
42803
|
+
}
|
|
42804
|
+
function phoneImageMime(relativePath) {
|
|
42805
|
+
const ext = relativePath.split(".").pop()?.toLowerCase() ?? "";
|
|
42806
|
+
return IMAGE_MIME[ext] ?? null;
|
|
42807
|
+
}
|
|
42808
|
+
function phoneImageDataUrl(worktreePath, raw) {
|
|
42809
|
+
const relative = phoneWorktreeRelative(worktreePath, raw);
|
|
42810
|
+
if (!relative) return null;
|
|
42811
|
+
const mime = phoneImageMime(relative);
|
|
42812
|
+
if (!mime) return null;
|
|
42813
|
+
try {
|
|
42814
|
+
const file = readWorktreeFileForUpload(worktreePath, relative, { maxBytes: PHONE_IMAGE_MAX_BYTES });
|
|
42815
|
+
return `data:${mime};base64,${file.contentBase64}`;
|
|
42816
|
+
} catch {
|
|
42817
|
+
return null;
|
|
42818
|
+
}
|
|
42819
|
+
}
|
|
42820
|
+
function phoneDirectoryListing(worktreePath, relative) {
|
|
42821
|
+
try {
|
|
42822
|
+
const entries = (0, import_node_fs71.readdirSync)((0, import_node_path71.join)(worktreePath, relative), { withFileTypes: true });
|
|
42823
|
+
const dirs = new Set(entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name));
|
|
42824
|
+
const names = entries.map((entry) => entry.name).filter((name) => name && !name.includes("/") && !name.includes("\0")).sort((a, b) => a.localeCompare(b));
|
|
42825
|
+
const shown = names.slice(0, PHONE_DIR_MAX);
|
|
42826
|
+
const lines = shown.map((name) => dirs.has(name) ? `${name}/` : name);
|
|
42827
|
+
const truncated = names.length > shown.length;
|
|
42828
|
+
if (truncated) lines.push(`\u2026 ${names.length - shown.length} more`);
|
|
42829
|
+
return { content: lines.join("\n"), truncated };
|
|
42830
|
+
} catch {
|
|
42831
|
+
return null;
|
|
42832
|
+
}
|
|
42833
|
+
}
|
|
42834
|
+
function phoneFilePreview(worktreePath, relative, kind) {
|
|
42835
|
+
if (kind === "dir") {
|
|
42836
|
+
const listing = phoneDirectoryListing(worktreePath, relative);
|
|
42837
|
+
if (!listing) return null;
|
|
42838
|
+
return {
|
|
42839
|
+
content: listing.content,
|
|
42840
|
+
encoding: "utf8",
|
|
42841
|
+
binary: false,
|
|
42842
|
+
directory: true,
|
|
42843
|
+
truncated: listing.truncated
|
|
42844
|
+
};
|
|
42845
|
+
}
|
|
42846
|
+
if (relative.toLowerCase().endsWith(".svg")) {
|
|
42847
|
+
try {
|
|
42848
|
+
const buf = (0, import_node_fs71.readFileSync)((0, import_node_path71.join)(worktreePath, relative));
|
|
42849
|
+
const truncated = buf.length > PHONE_TEXT_MAX_BYTES;
|
|
42850
|
+
return {
|
|
42851
|
+
content: buf.subarray(0, PHONE_TEXT_MAX_BYTES).toString("utf8"),
|
|
42852
|
+
encoding: "utf8",
|
|
42853
|
+
binary: false,
|
|
42854
|
+
directory: false,
|
|
42855
|
+
truncated,
|
|
42856
|
+
mime: "image/svg+xml"
|
|
42857
|
+
};
|
|
42858
|
+
} catch {
|
|
42859
|
+
return null;
|
|
42860
|
+
}
|
|
42861
|
+
}
|
|
42862
|
+
const mime = phoneImageMime(relative);
|
|
42863
|
+
if (mime) {
|
|
42864
|
+
const dataUrl = phoneImageDataUrl(worktreePath, relative);
|
|
42865
|
+
if (!dataUrl) return null;
|
|
42866
|
+
return {
|
|
42867
|
+
content: dataUrl,
|
|
42868
|
+
encoding: "base64",
|
|
42869
|
+
binary: true,
|
|
42870
|
+
directory: false,
|
|
42871
|
+
truncated: false,
|
|
42872
|
+
mime
|
|
42873
|
+
};
|
|
42874
|
+
}
|
|
42875
|
+
try {
|
|
42876
|
+
const file = readWorktreeFile(worktreePath, relative, { maxBytes: PHONE_TEXT_MAX_BYTES });
|
|
42877
|
+
return {
|
|
42878
|
+
content: file.content,
|
|
42879
|
+
encoding: file.encoding,
|
|
42880
|
+
binary: file.binary,
|
|
42881
|
+
directory: false,
|
|
42882
|
+
truncated: file.truncated
|
|
42883
|
+
};
|
|
42884
|
+
} catch {
|
|
42885
|
+
return null;
|
|
42886
|
+
}
|
|
42887
|
+
}
|
|
42888
|
+
|
|
42889
|
+
// src/remote/phone-workspace-ops.ts
|
|
42890
|
+
init_orchestrator();
|
|
42891
|
+
function dispatchPhoneWorkspace(cmd, emit, publishOpened) {
|
|
42892
|
+
if (cmd.op === "pane") {
|
|
42893
|
+
const thread = readPhoneThread(cmd.chatId);
|
|
42894
|
+
if (!thread) {
|
|
42895
|
+
emit({ op: "error", chatId: cmd.chatId, message: "That agent is not on this Mac." });
|
|
42896
|
+
return;
|
|
42897
|
+
}
|
|
42898
|
+
void readPhonePane(thread, cmd.pane, cmd.scope, cmd.query, cmd.commitSha).then((body) => {
|
|
42899
|
+
emit({
|
|
42900
|
+
op: "pane",
|
|
42901
|
+
chatId: cmd.chatId,
|
|
42902
|
+
pane: cmd.pane,
|
|
42903
|
+
rows: body.rows,
|
|
42904
|
+
...body.note ? { note: body.note } : {},
|
|
42905
|
+
...cmd.pane === "files" ? { query: cmd.query ?? "" } : {},
|
|
42906
|
+
...cmd.pane === "changes" ? {
|
|
42907
|
+
scope: body.scope,
|
|
42908
|
+
commitSha: body.commitSha ?? null,
|
|
42909
|
+
...body.base ? { base: body.base } : {},
|
|
42910
|
+
hasLastTurnBase: body.hasLastTurnBase,
|
|
42911
|
+
commits: body.commits ?? [],
|
|
42912
|
+
...body.scopeStats ? { scopeStats: body.scopeStats } : {}
|
|
42913
|
+
} : {}
|
|
42914
|
+
});
|
|
42915
|
+
});
|
|
42916
|
+
return;
|
|
42917
|
+
}
|
|
42918
|
+
if (cmd.op === "header") {
|
|
42919
|
+
const thread = readPhoneThread(cmd.chatId);
|
|
42920
|
+
if (!thread) {
|
|
42921
|
+
emit({ op: "error", chatId: cmd.chatId, message: "That agent is not on this Mac." });
|
|
42922
|
+
return;
|
|
42923
|
+
}
|
|
42924
|
+
void readPhoneHeader(thread).then((header) => {
|
|
42925
|
+
emit({ op: "header", chatId: cmd.chatId, ...header });
|
|
42926
|
+
});
|
|
42927
|
+
return;
|
|
42928
|
+
}
|
|
42929
|
+
if (cmd.op === "git") {
|
|
42930
|
+
void getOrchestrator().askGit(cmd.chatId, cmd.action).then((tab) => publishOpened(tab.id)).catch((err) => {
|
|
42931
|
+
emit({
|
|
42932
|
+
op: "error",
|
|
42933
|
+
chatId: cmd.chatId,
|
|
42934
|
+
message: err instanceof Error ? err.message : String(err)
|
|
42935
|
+
});
|
|
42936
|
+
});
|
|
42937
|
+
return;
|
|
42938
|
+
}
|
|
42939
|
+
void getOrchestrator().requestReview(cmd.chatId).then((tab) => publishOpened(tab.id)).catch((err) => {
|
|
42940
|
+
emit({
|
|
42941
|
+
op: "error",
|
|
42942
|
+
chatId: cmd.chatId,
|
|
42943
|
+
message: err instanceof Error ? err.message : String(err)
|
|
42944
|
+
});
|
|
42945
|
+
});
|
|
42946
|
+
}
|
|
42947
|
+
|
|
42948
|
+
// src/remote/phone-sources.ts
|
|
42949
|
+
init_worktree();
|
|
42950
|
+
function sourceWarning(label, err) {
|
|
42951
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
42952
|
+
return message ? `${label}: ${message}` : `${label} failed.`;
|
|
42953
|
+
}
|
|
42954
|
+
async function listPhoneSources(repoPath, query) {
|
|
42955
|
+
const path2 = assertKnownProject(repoPath);
|
|
42956
|
+
const q = query?.trim() ?? "";
|
|
42957
|
+
const warnings = [];
|
|
42958
|
+
const [prs, branches, issues] = await Promise.all([
|
|
42959
|
+
listPrs(path2, { state: "open", limit: 40, ...q ? { query: q } : {} }).catch((err) => {
|
|
42960
|
+
warnings.push(sourceWarning("Pull requests", err));
|
|
42961
|
+
return [];
|
|
42962
|
+
}),
|
|
42963
|
+
listBranches(path2).catch((err) => {
|
|
42964
|
+
warnings.push(sourceWarning("Branches", err));
|
|
42965
|
+
return [];
|
|
42966
|
+
}),
|
|
42967
|
+
listIssues(path2, { limit: 40, ...q ? { query: q } : {} }).catch((err) => {
|
|
42968
|
+
warnings.push(sourceWarning("Issues", err));
|
|
42969
|
+
return { issues: [] };
|
|
42970
|
+
})
|
|
42971
|
+
]);
|
|
42972
|
+
const needle = q.toLowerCase();
|
|
42973
|
+
const branchRows = branches.filter((branch) => !needle || branch.name.toLowerCase().includes(needle)).slice(0, 50).map((branch) => ({
|
|
42974
|
+
ref: branch.name,
|
|
42975
|
+
title: branch.current ? `${branch.name} (current)` : branch.name
|
|
42976
|
+
}));
|
|
42977
|
+
return {
|
|
42978
|
+
prs: prs.slice(0, 40).map((pr) => ({
|
|
42979
|
+
ref: String(pr.number),
|
|
42980
|
+
title: clip(pr.title || `PR #${pr.number}`, 140),
|
|
42981
|
+
...pr.url ? { url: pr.url } : {}
|
|
42982
|
+
})),
|
|
42983
|
+
branches: branchRows,
|
|
42984
|
+
issues: (issues.issues ?? []).slice(0, 40).map((issue) => ({
|
|
42985
|
+
ref: issue.identifier,
|
|
42986
|
+
title: clip(issue.title || issue.identifier, 140),
|
|
42987
|
+
...issue.url ? { url: issue.url } : {}
|
|
42988
|
+
})),
|
|
42989
|
+
...warnings.length ? { warnings } : {}
|
|
42990
|
+
};
|
|
42991
|
+
}
|
|
42992
|
+
|
|
42514
42993
|
// src/remote/phone-turn.ts
|
|
42515
42994
|
init_orchestrator_capable();
|
|
42516
42995
|
init_orchestrator();
|
|
@@ -42865,6 +43344,7 @@ function handlePhoneControl(cmd, opts) {
|
|
|
42865
43344
|
});
|
|
42866
43345
|
return;
|
|
42867
43346
|
}
|
|
43347
|
+
if (dispatchPhoneMcpUi(cmd, opts)) return;
|
|
42868
43348
|
if (cmd.op === "open-file") {
|
|
42869
43349
|
const thread = readPhoneThread(cmd.chatId);
|
|
42870
43350
|
const relative = thread ? phoneWorktreeRelative(thread.worktreePath, cmd.path) : null;
|
|
@@ -45538,6 +46018,7 @@ async function pollSlackOutboundWatches(opts) {
|
|
|
45538
46018
|
clipAgentEventForPaint,
|
|
45539
46019
|
clipThinkingForStore,
|
|
45540
46020
|
cloneRepoIntoSideboard,
|
|
46021
|
+
closeMcpUiHost,
|
|
45541
46022
|
codeRefRangeLabel,
|
|
45542
46023
|
codexAdapter,
|
|
45543
46024
|
codexSandboxWritableRootsArgs,
|
|
@@ -45760,6 +46241,7 @@ async function pollSlackOutboundWatches(opts) {
|
|
|
45760
46241
|
getLinearApiKey,
|
|
45761
46242
|
getLinearAuthToken,
|
|
45762
46243
|
getLinearIssue,
|
|
46244
|
+
getMcpUiHost,
|
|
45763
46245
|
getOrchestrator,
|
|
45764
46246
|
getPr,
|
|
45765
46247
|
getPrChecks,
|
|
@@ -45825,6 +46307,7 @@ async function pollSlackOutboundWatches(opts) {
|
|
|
45825
46307
|
isBrightsyConnected,
|
|
45826
46308
|
isBrightsyNdjsonLine,
|
|
45827
46309
|
isChatTextScale,
|
|
46310
|
+
isClaudeAiConnectorMcp,
|
|
45828
46311
|
isCloudCoordinatorThread,
|
|
45829
46312
|
isCompactToolName,
|
|
45830
46313
|
isConductorBundledCli,
|
|
@@ -45979,6 +46462,7 @@ async function pollSlackOutboundWatches(opts) {
|
|
|
45979
46462
|
mcpServerIdForPermission,
|
|
45980
46463
|
mcpServerPermissionUpdate,
|
|
45981
46464
|
mcpStatusThinkingFromClaudeInit,
|
|
46465
|
+
mcpUiContentSecurityPolicy,
|
|
45982
46466
|
mentionsPrGoal,
|
|
45983
46467
|
mergeAgentGitAuthEnv,
|
|
45984
46468
|
mergePr,
|