@particle-academy/agent-integrations 0.11.1 → 0.13.0
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/README.md +26 -0
- package/dist/bridges/terminal.d.cts +56 -24
- package/dist/bridges/terminal.d.ts +56 -24
- package/dist/bridges-terminal.cjs +116 -53
- package/dist/bridges-terminal.cjs.map +1 -1
- package/dist/bridges-terminal.js +1 -1
- package/dist/chunk-54QEFRMS.js +285 -0
- package/dist/chunk-54QEFRMS.js.map +1 -0
- package/dist/chunk-57KAMBAR.js +275 -0
- package/dist/chunk-57KAMBAR.js.map +1 -0
- package/dist/chunk-GO2Y6H6U.js +62 -0
- package/dist/chunk-GO2Y6H6U.js.map +1 -0
- package/dist/connectors/build.d.cts +56 -0
- package/dist/connectors/build.d.ts +56 -0
- package/dist/connectors/index.d.cts +130 -0
- package/dist/connectors/index.d.ts +130 -0
- package/dist/connectors-build.cjs +133 -0
- package/dist/connectors-build.cjs.map +1 -0
- package/dist/connectors-build.js +66 -0
- package/dist/connectors-build.js.map +1 -0
- package/dist/connectors.cjs +366 -0
- package/dist/connectors.cjs.map +1 -0
- package/dist/connectors.js +4 -0
- package/dist/connectors.js.map +1 -0
- package/dist/index.cjs +473 -53
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +6 -4
- package/dist/index.js.map +1 -1
- package/dist/mcpb-BXOrsRnv.d.cts +54 -0
- package/dist/mcpb-BXOrsRnv.d.ts +54 -0
- package/dist/styles.css +156 -0
- package/dist/styles.css.map +1 -1
- package/docs/connectors.md +118 -0
- package/package.json +27 -2
- package/dist/chunk-FZ7Q5NS3.js +0 -212
- package/dist/chunk-FZ7Q5NS3.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -1953,19 +1953,39 @@ function serialize(entry) {
|
|
|
1953
1953
|
var DEFAULT_AGENT8 = { id: "agent", name: "Agent", color: "#a855f7" };
|
|
1954
1954
|
var truncate = (s, n = 60) => s.length > n ? s.slice(0, n) + "\u2026" : s;
|
|
1955
1955
|
function registerTerminalBridge(host, options) {
|
|
1956
|
-
const { adapter } = options;
|
|
1957
1956
|
const agent = { ...DEFAULT_AGENT8, ...options.agent ?? {} };
|
|
1958
1957
|
const pendingMode = options.pendingMode ?? false;
|
|
1958
|
+
const screenId = options.screenId ?? options.adapter?.screenId;
|
|
1959
1959
|
const disposers = [];
|
|
1960
1960
|
const staged = /* @__PURE__ */ new Map();
|
|
1961
1961
|
let seq = 0;
|
|
1962
1962
|
ensureUndoToolsRegistered(host);
|
|
1963
|
-
const
|
|
1963
|
+
const listTerminals = () => {
|
|
1964
|
+
if (options.terminals) return options.terminals();
|
|
1965
|
+
if (options.adapter) return [{ id: "terminal", label: "Terminal", active: true, ...options.adapter }];
|
|
1966
|
+
return [];
|
|
1967
|
+
};
|
|
1968
|
+
const resolve = (id) => {
|
|
1969
|
+
const list = listTerminals();
|
|
1970
|
+
if (typeof id === "string" && id !== "") return list.find((t) => t.id === id);
|
|
1971
|
+
return list.find((t) => t.active) ?? list[0];
|
|
1972
|
+
};
|
|
1973
|
+
const anyMulti = !!options.terminals;
|
|
1974
|
+
const canClear = anyMulti || !!options.adapter?.clear;
|
|
1975
|
+
const canShells = anyMulti || !!options.adapter?.listShells;
|
|
1976
|
+
const canSetShell = anyMulti || !!options.adapter?.setShell;
|
|
1977
|
+
const target = (label, terminalId) => ({
|
|
1964
1978
|
kind: "terminal",
|
|
1965
|
-
screenId
|
|
1966
|
-
elementId:
|
|
1979
|
+
screenId,
|
|
1980
|
+
elementId: terminalId ?? screenId ?? "terminal",
|
|
1967
1981
|
label: label ?? "terminal"
|
|
1968
1982
|
});
|
|
1983
|
+
const TERMINAL_ARG = {
|
|
1984
|
+
terminal: {
|
|
1985
|
+
type: "string",
|
|
1986
|
+
description: "Terminal id to target (call terminal_list for ids). Omit for the active / only terminal."
|
|
1987
|
+
}
|
|
1988
|
+
};
|
|
1969
1989
|
const reg = (name, description, properties, required, handler, isMutation, resolveTarget) => {
|
|
1970
1990
|
const wrapped = async (args) => {
|
|
1971
1991
|
try {
|
|
@@ -1978,7 +1998,7 @@ function registerTerminalBridge(host, options) {
|
|
|
1978
1998
|
toolName: name,
|
|
1979
1999
|
agent,
|
|
1980
2000
|
kind: "terminal",
|
|
1981
|
-
screenId
|
|
2001
|
+
screenId,
|
|
1982
2002
|
resolveTarget: ({ args, result }) => resolveTarget?.(args, result) ?? target()
|
|
1983
2003
|
}) : wrapped;
|
|
1984
2004
|
disposers.push(
|
|
@@ -1992,38 +2012,66 @@ function registerTerminalBridge(host, options) {
|
|
|
1992
2012
|
)
|
|
1993
2013
|
);
|
|
1994
2014
|
};
|
|
1995
|
-
|
|
2015
|
+
const need = (args) => {
|
|
2016
|
+
const t = resolve(args.terminal);
|
|
2017
|
+
if (!t) {
|
|
2018
|
+
const ids = listTerminals().map((x) => x.id).join(", ") || "(none)";
|
|
2019
|
+
throw new Error(
|
|
2020
|
+
typeof args.terminal === "string" && args.terminal ? `Unknown terminal '${args.terminal}'. Available: ${ids}. Use terminal_list.` : "No terminal available."
|
|
2021
|
+
);
|
|
2022
|
+
}
|
|
2023
|
+
return t;
|
|
2024
|
+
};
|
|
2025
|
+
async function exec(t, kind, data) {
|
|
1996
2026
|
if (kind === "run") {
|
|
1997
|
-
if (
|
|
1998
|
-
else
|
|
2027
|
+
if (t.runCommand) await t.runCommand(data);
|
|
2028
|
+
else t.write(data + "\r");
|
|
1999
2029
|
} else {
|
|
2000
|
-
|
|
2030
|
+
t.write(data);
|
|
2001
2031
|
}
|
|
2002
2032
|
}
|
|
2003
|
-
async function stageOrExec(kind, data) {
|
|
2033
|
+
async function stageOrExec(t, kind, data) {
|
|
2004
2034
|
if (!pendingMode) {
|
|
2005
|
-
await exec(kind, data);
|
|
2006
|
-
return textResult(`${kind === "run" ? "ran" : "wrote"}: ${truncate(data)}`, {
|
|
2035
|
+
await exec(t, kind, data);
|
|
2036
|
+
return textResult(`${kind === "run" ? "ran" : "wrote"} on ${t.id}: ${truncate(data)}`, {
|
|
2037
|
+
kind,
|
|
2038
|
+
data,
|
|
2039
|
+
terminal: t.id,
|
|
2040
|
+
executed: true
|
|
2041
|
+
});
|
|
2007
2042
|
}
|
|
2008
2043
|
const id = `t${++seq}`;
|
|
2009
|
-
const entry = { id, kind, data };
|
|
2044
|
+
const entry = { id, kind, data, terminalId: t.id };
|
|
2010
2045
|
staged.set(id, entry);
|
|
2011
2046
|
options.onPending?.(entry);
|
|
2012
2047
|
return textResult(
|
|
2013
|
-
`Staged ${kind} (id ${id}) \u2014 awaiting human confirmation: ${truncate(data)}`,
|
|
2048
|
+
`Staged ${kind} on ${t.id} (id ${id}) \u2014 awaiting human confirmation: ${truncate(data)}`,
|
|
2014
2049
|
{ ...entry, pending: true }
|
|
2015
2050
|
);
|
|
2016
2051
|
}
|
|
2052
|
+
reg(
|
|
2053
|
+
"terminal_list",
|
|
2054
|
+
"List the terminals on this screen (id, label, which is active) \u2014 so you can reach into another terminal, not just the active one. Pass the chosen id as `terminal` to the other tools.",
|
|
2055
|
+
{},
|
|
2056
|
+
[],
|
|
2057
|
+
() => {
|
|
2058
|
+
const list = listTerminals().map((t) => ({ id: t.id, label: t.label ?? t.id, active: !!t.active }));
|
|
2059
|
+
const text = list.length ? list.map((t) => `${t.active ? "* " : " "}${t.id} \u2014 ${t.label}`).join("\n") : "(no terminals)";
|
|
2060
|
+
return textResult(text, { terminals: list });
|
|
2061
|
+
},
|
|
2062
|
+
false
|
|
2063
|
+
);
|
|
2017
2064
|
reg(
|
|
2018
2065
|
"terminal_read",
|
|
2019
|
-
"Read
|
|
2020
|
-
{ tail: { type: "number", description: "Return only the last N lines." } },
|
|
2066
|
+
"Read a terminal's visible buffer as text \u2014 what the user sees. Pass `tail` for only the last N lines, `terminal` to read a specific one.",
|
|
2067
|
+
{ ...TERMINAL_ARG, tail: { type: "number", description: "Return only the last N lines." } },
|
|
2021
2068
|
[],
|
|
2022
2069
|
(args) => {
|
|
2023
|
-
|
|
2070
|
+
const t = need(args);
|
|
2071
|
+
let buf = t.getBuffer();
|
|
2024
2072
|
const tail = typeof args.tail === "number" ? args.tail : void 0;
|
|
2025
2073
|
if (tail && tail > 0) buf = buf.split("\n").slice(-tail).join("\n");
|
|
2026
|
-
return textResult(buf, { buffer: buf });
|
|
2074
|
+
return textResult(buf, { buffer: buf, terminal: t.id });
|
|
2027
2075
|
},
|
|
2028
2076
|
false
|
|
2029
2077
|
);
|
|
@@ -2035,7 +2083,7 @@ function registerTerminalBridge(host, options) {
|
|
|
2035
2083
|
() => {
|
|
2036
2084
|
const list = [...staged.values()];
|
|
2037
2085
|
return textResult(
|
|
2038
|
-
list.length ? list.map((s) => `${s.id}: ${s.kind} ${truncate(s.data)}`).join("\n") : "(none)",
|
|
2086
|
+
list.length ? list.map((s) => `${s.id}: ${s.kind} on ${s.terminalId} ${truncate(s.data)}`).join("\n") : "(none)",
|
|
2039
2087
|
{ pending: list }
|
|
2040
2088
|
);
|
|
2041
2089
|
},
|
|
@@ -2043,20 +2091,21 @@ function registerTerminalBridge(host, options) {
|
|
|
2043
2091
|
);
|
|
2044
2092
|
reg(
|
|
2045
2093
|
"terminal_write",
|
|
2046
|
-
"Write raw data / keystrokes to
|
|
2047
|
-
{ data: { type: "string", description: "Raw bytes to write." } },
|
|
2094
|
+
"Write raw data / keystrokes to a terminal (input, control chars, ANSI). Pass `terminal` to target a specific one. In pendingMode this stages instead of executing.",
|
|
2095
|
+
{ ...TERMINAL_ARG, data: { type: "string", description: "Raw bytes to write." } },
|
|
2048
2096
|
["data"],
|
|
2049
|
-
(args) => stageOrExec("write", String(args.data)),
|
|
2050
|
-
true
|
|
2097
|
+
(args) => stageOrExec(need(args), "write", String(args.data)),
|
|
2098
|
+
true,
|
|
2099
|
+
(args) => target(`write:${String(args.terminal ?? "")}`, resolve(args.terminal)?.id)
|
|
2051
2100
|
);
|
|
2052
2101
|
reg(
|
|
2053
2102
|
"terminal_run",
|
|
2054
|
-
"Run a shell command \u2014 writes the command
|
|
2055
|
-
{ command: { type: "string", description: "The command line to run." } },
|
|
2103
|
+
"Run a shell command in a terminal \u2014 writes the command + Enter (or the host's runner). Pass `terminal` to target a specific one. In pendingMode this stages it for confirmation.",
|
|
2104
|
+
{ ...TERMINAL_ARG, command: { type: "string", description: "The command line to run." } },
|
|
2056
2105
|
["command"],
|
|
2057
|
-
(args) => stageOrExec("run", String(args.command)),
|
|
2106
|
+
(args) => stageOrExec(need(args), "run", String(args.command)),
|
|
2058
2107
|
true,
|
|
2059
|
-
(args) => target(truncate(String(args.command ?? "")))
|
|
2108
|
+
(args) => target(truncate(String(args.command ?? "")), resolve(args.terminal)?.id)
|
|
2060
2109
|
);
|
|
2061
2110
|
reg(
|
|
2062
2111
|
"terminal_confirm",
|
|
@@ -2067,11 +2116,17 @@ function registerTerminalBridge(host, options) {
|
|
|
2067
2116
|
const id = String(args.id);
|
|
2068
2117
|
const entry = staged.get(id);
|
|
2069
2118
|
if (!entry) return errorResult(`No staged command ${id}`);
|
|
2119
|
+
const t = resolve(entry.terminalId);
|
|
2120
|
+
if (!t) return errorResult(`Terminal '${entry.terminalId}' is gone \u2014 cannot run ${id}`);
|
|
2070
2121
|
staged.delete(id);
|
|
2071
|
-
await exec(entry.kind, entry.data);
|
|
2072
|
-
return textResult(`Confirmed ${id}: ${entry.kind} ${truncate(entry.data)}`, { ...entry, executed: true });
|
|
2122
|
+
await exec(t, entry.kind, entry.data);
|
|
2123
|
+
return textResult(`Confirmed ${id}: ${entry.kind} on ${t.id} ${truncate(entry.data)}`, { ...entry, executed: true });
|
|
2073
2124
|
},
|
|
2074
|
-
true
|
|
2125
|
+
true,
|
|
2126
|
+
(args) => {
|
|
2127
|
+
const e = staged.get(String(args.id));
|
|
2128
|
+
return target(`confirm:${String(args.id ?? "")}`, e?.terminalId);
|
|
2129
|
+
}
|
|
2075
2130
|
);
|
|
2076
2131
|
reg(
|
|
2077
2132
|
"terminal_reject",
|
|
@@ -2085,51 +2140,58 @@ function registerTerminalBridge(host, options) {
|
|
|
2085
2140
|
},
|
|
2086
2141
|
false
|
|
2087
2142
|
);
|
|
2088
|
-
if (
|
|
2143
|
+
if (canClear) {
|
|
2089
2144
|
reg(
|
|
2090
2145
|
"terminal_clear",
|
|
2091
|
-
"Clear
|
|
2092
|
-
{},
|
|
2146
|
+
"Clear a terminal's viewport. Pass `terminal` to target a specific one.",
|
|
2147
|
+
{ ...TERMINAL_ARG },
|
|
2093
2148
|
[],
|
|
2094
|
-
() => {
|
|
2095
|
-
|
|
2096
|
-
return
|
|
2149
|
+
(args) => {
|
|
2150
|
+
const t = need(args);
|
|
2151
|
+
if (!t.clear) return errorResult(`Terminal '${t.id}' can't be cleared.`);
|
|
2152
|
+
t.clear();
|
|
2153
|
+
return textResult(`cleared ${t.id}`, { terminal: t.id });
|
|
2097
2154
|
},
|
|
2098
|
-
true
|
|
2155
|
+
true,
|
|
2156
|
+
(args) => target(`clear:${String(args.terminal ?? "")}`, resolve(args.terminal)?.id)
|
|
2099
2157
|
);
|
|
2100
2158
|
}
|
|
2101
|
-
if (
|
|
2159
|
+
if (canShells) {
|
|
2102
2160
|
reg(
|
|
2103
2161
|
"terminal_list_shells",
|
|
2104
|
-
"List the shells
|
|
2105
|
-
{},
|
|
2162
|
+
"List the shells a terminal can switch to (cmd, PowerShell, Git Bash, \u2026) \u2014 id + label, active one marked. Pass `terminal` to target a specific one.",
|
|
2163
|
+
{ ...TERMINAL_ARG },
|
|
2106
2164
|
[],
|
|
2107
|
-
() => {
|
|
2108
|
-
const
|
|
2109
|
-
|
|
2165
|
+
(args) => {
|
|
2166
|
+
const t = need(args);
|
|
2167
|
+
if (!t.listShells) return errorResult(`Terminal '${t.id}' has no switchable shells.`);
|
|
2168
|
+
const shells = t.listShells();
|
|
2169
|
+
const active = t.getShell?.();
|
|
2110
2170
|
const text = shells.length ? shells.map((s) => `${s.id === active ? "* " : " "}${s.id} \u2014 ${s.label}`).join("\n") : "(none)";
|
|
2111
|
-
return textResult(text, { shells, active });
|
|
2171
|
+
return textResult(text, { shells, active, terminal: t.id });
|
|
2112
2172
|
},
|
|
2113
2173
|
false
|
|
2114
2174
|
);
|
|
2115
2175
|
}
|
|
2116
|
-
if (
|
|
2176
|
+
if (canSetShell) {
|
|
2117
2177
|
reg(
|
|
2118
2178
|
"terminal_set_shell",
|
|
2119
|
-
"Switch
|
|
2120
|
-
{ id: { type: "string", description: "Shell id to switch to." } },
|
|
2179
|
+
"Switch a terminal's active shell by id (e.g. 'powershell', 'git-bash'). Call terminal_list_shells first for valid ids. Pass `terminal` to target a specific one.",
|
|
2180
|
+
{ ...TERMINAL_ARG, id: { type: "string", description: "Shell id to switch to." } },
|
|
2121
2181
|
["id"],
|
|
2122
2182
|
async (args) => {
|
|
2183
|
+
const t = need(args);
|
|
2184
|
+
if (!t.setShell) return errorResult(`Terminal '${t.id}' can't switch shells.`);
|
|
2123
2185
|
const id = String(args.id);
|
|
2124
|
-
const shells =
|
|
2186
|
+
const shells = t.listShells?.();
|
|
2125
2187
|
if (shells && shells.length && !shells.some((s) => s.id === id)) {
|
|
2126
|
-
return errorResult(`Unknown shell '${id}'. Use terminal_list_shells for valid ids.`);
|
|
2188
|
+
return errorResult(`Unknown shell '${id}' for ${t.id}. Use terminal_list_shells for valid ids.`);
|
|
2127
2189
|
}
|
|
2128
|
-
await
|
|
2129
|
-
return textResult(`Switched shell to ${id}`, { shell: id });
|
|
2190
|
+
await t.setShell(id);
|
|
2191
|
+
return textResult(`Switched ${t.id} shell to ${id}`, { shell: id, terminal: t.id });
|
|
2130
2192
|
},
|
|
2131
2193
|
true,
|
|
2132
|
-
(args) => target(`shell:${String(args.id ?? "")}
|
|
2194
|
+
(args) => target(`shell:${String(args.id ?? "")}`, resolve(args.terminal)?.id)
|
|
2133
2195
|
);
|
|
2134
2196
|
}
|
|
2135
2197
|
return {
|
|
@@ -2143,8 +2205,9 @@ function registerTerminalBridge(host, options) {
|
|
|
2143
2205
|
confirm: (id) => {
|
|
2144
2206
|
const e = staged.get(id);
|
|
2145
2207
|
if (e) {
|
|
2208
|
+
const t = resolve(e.terminalId);
|
|
2146
2209
|
staged.delete(id);
|
|
2147
|
-
void exec(e.kind, e.data);
|
|
2210
|
+
if (t) void exec(t, e.kind, e.data);
|
|
2148
2211
|
}
|
|
2149
2212
|
},
|
|
2150
2213
|
reject: (id) => {
|
|
@@ -2753,6 +2816,342 @@ function attachSseRelay(server, options) {
|
|
|
2753
2816
|
return transport;
|
|
2754
2817
|
}
|
|
2755
2818
|
|
|
2819
|
+
// src/connectors/targets.ts
|
|
2820
|
+
var CLAUDE_CONNECTORS_URL = "https://claude.ai/settings/connectors";
|
|
2821
|
+
function encodeBase64Json(value) {
|
|
2822
|
+
const json = JSON.stringify(value);
|
|
2823
|
+
if (typeof btoa === "function") {
|
|
2824
|
+
return btoa(unescape(encodeURIComponent(json)));
|
|
2825
|
+
}
|
|
2826
|
+
return Buffer.from(json, "utf8").toString("base64");
|
|
2827
|
+
}
|
|
2828
|
+
function buildCursorDeeplink(server) {
|
|
2829
|
+
const config = encodeBase64Json({ url: server.url });
|
|
2830
|
+
return `cursor://anysphere.cursor-deeplink/mcp/install?name=${encodeURIComponent(
|
|
2831
|
+
server.name
|
|
2832
|
+
)}&config=${config}`;
|
|
2833
|
+
}
|
|
2834
|
+
function buildVscodeDeeplink(server, opts = {}) {
|
|
2835
|
+
const scheme = opts.insiders ? "vscode-insiders" : "vscode";
|
|
2836
|
+
const payload = encodeURIComponent(
|
|
2837
|
+
JSON.stringify({ name: server.name, url: server.url })
|
|
2838
|
+
);
|
|
2839
|
+
return `${scheme}://mcp/install?${payload}`;
|
|
2840
|
+
}
|
|
2841
|
+
function slugifyServerName(name) {
|
|
2842
|
+
const slug = name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
2843
|
+
return slug || "mcp-server";
|
|
2844
|
+
}
|
|
2845
|
+
function buildManualConfig(server) {
|
|
2846
|
+
return {
|
|
2847
|
+
mcpServers: {
|
|
2848
|
+
[slugifyServerName(server.name)]: {
|
|
2849
|
+
command: "npx",
|
|
2850
|
+
args: ["-y", "mcp-remote", server.url]
|
|
2851
|
+
}
|
|
2852
|
+
}
|
|
2853
|
+
};
|
|
2854
|
+
}
|
|
2855
|
+
function buildManualConfigSnippet(server) {
|
|
2856
|
+
return JSON.stringify(buildManualConfig(server), null, 2);
|
|
2857
|
+
}
|
|
2858
|
+
var CONNECTOR_TARGETS = {
|
|
2859
|
+
"claude-web": {
|
|
2860
|
+
id: "claude-web",
|
|
2861
|
+
label: "Add to Claude",
|
|
2862
|
+
mechanism: "copy-open",
|
|
2863
|
+
hint: "Copy the MCP URL and open Claude's Connectors page \u2014 click 'Add custom connector' and paste."
|
|
2864
|
+
},
|
|
2865
|
+
"claude-desktop": {
|
|
2866
|
+
id: "claude-desktop",
|
|
2867
|
+
label: "Claude Desktop",
|
|
2868
|
+
mechanism: "download",
|
|
2869
|
+
hint: "Download a .mcpb bundle and double-click it to install in Claude Desktop."
|
|
2870
|
+
},
|
|
2871
|
+
cursor: {
|
|
2872
|
+
id: "cursor",
|
|
2873
|
+
label: "Add to Cursor",
|
|
2874
|
+
mechanism: "deeplink",
|
|
2875
|
+
hint: "Open Cursor with this MCP server pre-filled \u2014 confirm to install."
|
|
2876
|
+
},
|
|
2877
|
+
vscode: {
|
|
2878
|
+
id: "vscode",
|
|
2879
|
+
label: "Add to VS Code",
|
|
2880
|
+
mechanism: "deeplink",
|
|
2881
|
+
hint: "Open VS Code with this MCP server pre-filled \u2014 confirm to install."
|
|
2882
|
+
},
|
|
2883
|
+
manual: {
|
|
2884
|
+
id: "manual",
|
|
2885
|
+
label: "Manual setup",
|
|
2886
|
+
mechanism: "snippet",
|
|
2887
|
+
hint: "Show a config snippet to paste into any stdio MCP client."
|
|
2888
|
+
}
|
|
2889
|
+
};
|
|
2890
|
+
function connectorHref(client, server, opts = {}) {
|
|
2891
|
+
switch (client) {
|
|
2892
|
+
case "cursor":
|
|
2893
|
+
return buildCursorDeeplink(server);
|
|
2894
|
+
case "vscode":
|
|
2895
|
+
return buildVscodeDeeplink(server, opts);
|
|
2896
|
+
default:
|
|
2897
|
+
return null;
|
|
2898
|
+
}
|
|
2899
|
+
}
|
|
2900
|
+
function ClaudeMark(props) {
|
|
2901
|
+
return /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "currentColor", "aria-hidden": true, ...props, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 2 L 14 10 L 22 12 L 14 14 L 12 22 L 10 14 L 2 12 L 10 10 Z" }) });
|
|
2902
|
+
}
|
|
2903
|
+
function CursorMark(props) {
|
|
2904
|
+
return /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "currentColor", "aria-hidden": true, ...props, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M3 3 L 20 11 L 12 13 L 9 21 Z" }) });
|
|
2905
|
+
}
|
|
2906
|
+
function VscodeMark(props) {
|
|
2907
|
+
return /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "currentColor", "aria-hidden": true, ...props, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M17 2 L 22 4.5 V 19.5 L 17 22 L 6.5 13.2 L 3 16 L 1.5 15 V 9 L 3 8 L 6.5 10.8 Z M 17 6.5 L 10 12 L 17 17.5 Z" }) });
|
|
2908
|
+
}
|
|
2909
|
+
function DesktopMark(props) {
|
|
2910
|
+
return /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "currentColor", "aria-hidden": true, ...props, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M3 4 H 21 A 1 1 0 0 1 22 5 V 16 A 1 1 0 0 1 21 17 H 14 V 19 H 16 V 21 H 8 V 19 H 10 V 17 H 3 A 1 1 0 0 1 2 16 V 5 A 1 1 0 0 1 3 4 Z" }) });
|
|
2911
|
+
}
|
|
2912
|
+
function WrenchMark(props) {
|
|
2913
|
+
return /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "currentColor", "aria-hidden": true, ...props, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M21 4 a 5 5 0 0 1 -6.5 6.5 L 6 19 l -3 -3 l 8.5 -8.5 A 5 5 0 0 1 17 1 l -2.5 2.5 l 1.5 3 l 3 1.5 Z" }) });
|
|
2914
|
+
}
|
|
2915
|
+
var CONNECTOR_GLYPHS = {
|
|
2916
|
+
"claude-web": ClaudeMark,
|
|
2917
|
+
"claude-desktop": DesktopMark,
|
|
2918
|
+
cursor: CursorMark,
|
|
2919
|
+
vscode: VscodeMark,
|
|
2920
|
+
manual: WrenchMark
|
|
2921
|
+
};
|
|
2922
|
+
var DEFAULT_CLIENTS = [
|
|
2923
|
+
"claude-web",
|
|
2924
|
+
"cursor",
|
|
2925
|
+
"vscode",
|
|
2926
|
+
"manual"
|
|
2927
|
+
];
|
|
2928
|
+
function ConnectorButtons({
|
|
2929
|
+
serverName,
|
|
2930
|
+
mcpUrl,
|
|
2931
|
+
clients,
|
|
2932
|
+
mcpbDownloadUrl,
|
|
2933
|
+
claudeConnectorsUrl = CLAUDE_CONNECTORS_URL,
|
|
2934
|
+
vscodeInsiders,
|
|
2935
|
+
onCopy,
|
|
2936
|
+
onAction,
|
|
2937
|
+
labels,
|
|
2938
|
+
className,
|
|
2939
|
+
style
|
|
2940
|
+
}) {
|
|
2941
|
+
const server = { name: serverName, url: mcpUrl };
|
|
2942
|
+
const [copied, setCopied] = react.useState(null);
|
|
2943
|
+
const [manualOpen, setManualOpen] = react.useState(false);
|
|
2944
|
+
const manualId = react.useId();
|
|
2945
|
+
const list = (clients ?? defaultClients(mcpbDownloadUrl)).filter(
|
|
2946
|
+
(c) => c === "claude-desktop" ? !!mcpbDownloadUrl : true
|
|
2947
|
+
);
|
|
2948
|
+
const flashCopied = (target) => {
|
|
2949
|
+
setCopied(target);
|
|
2950
|
+
window.setTimeout(() => setCopied((c) => c === target ? null : c), 2e3);
|
|
2951
|
+
};
|
|
2952
|
+
const copy = async (value, target) => {
|
|
2953
|
+
try {
|
|
2954
|
+
await navigator.clipboard?.writeText(value);
|
|
2955
|
+
flashCopied(target);
|
|
2956
|
+
onCopy?.(target);
|
|
2957
|
+
} catch {
|
|
2958
|
+
}
|
|
2959
|
+
};
|
|
2960
|
+
const labelFor = (c) => labels?.[c] ?? CONNECTOR_TARGETS[c].label;
|
|
2961
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2962
|
+
"div",
|
|
2963
|
+
{
|
|
2964
|
+
className: ["fai-connect", className].filter(Boolean).join(" "),
|
|
2965
|
+
style,
|
|
2966
|
+
children: list.map((client) => {
|
|
2967
|
+
const meta = CONNECTOR_TARGETS[client];
|
|
2968
|
+
const Glyph = CONNECTOR_GLYPHS[client];
|
|
2969
|
+
const base = `fai-connect__btn fai-connect__btn--${client}`;
|
|
2970
|
+
const href = connectorHref(client, server, { insiders: vscodeInsiders });
|
|
2971
|
+
if (href) {
|
|
2972
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2973
|
+
"a",
|
|
2974
|
+
{
|
|
2975
|
+
href,
|
|
2976
|
+
className: base,
|
|
2977
|
+
title: meta.hint,
|
|
2978
|
+
onClick: () => onAction?.(client),
|
|
2979
|
+
children: [
|
|
2980
|
+
/* @__PURE__ */ jsxRuntime.jsx(Glyph, { className: "fai-connect__glyph" }),
|
|
2981
|
+
labelFor(client)
|
|
2982
|
+
]
|
|
2983
|
+
},
|
|
2984
|
+
client
|
|
2985
|
+
);
|
|
2986
|
+
}
|
|
2987
|
+
if (client === "claude-desktop") {
|
|
2988
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2989
|
+
"a",
|
|
2990
|
+
{
|
|
2991
|
+
href: mcpbDownloadUrl,
|
|
2992
|
+
download: true,
|
|
2993
|
+
className: base,
|
|
2994
|
+
title: meta.hint,
|
|
2995
|
+
onClick: () => onAction?.(client),
|
|
2996
|
+
children: [
|
|
2997
|
+
/* @__PURE__ */ jsxRuntime.jsx(Glyph, { className: "fai-connect__glyph" }),
|
|
2998
|
+
labelFor(client)
|
|
2999
|
+
]
|
|
3000
|
+
},
|
|
3001
|
+
client
|
|
3002
|
+
);
|
|
3003
|
+
}
|
|
3004
|
+
if (client === "claude-web") {
|
|
3005
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3006
|
+
"button",
|
|
3007
|
+
{
|
|
3008
|
+
type: "button",
|
|
3009
|
+
className: base,
|
|
3010
|
+
title: meta.hint,
|
|
3011
|
+
onClick: () => {
|
|
3012
|
+
void copy(mcpUrl, client);
|
|
3013
|
+
window.open(
|
|
3014
|
+
claudeConnectorsUrl,
|
|
3015
|
+
"_blank",
|
|
3016
|
+
"noopener,noreferrer"
|
|
3017
|
+
);
|
|
3018
|
+
onAction?.(client);
|
|
3019
|
+
},
|
|
3020
|
+
children: [
|
|
3021
|
+
/* @__PURE__ */ jsxRuntime.jsx(Glyph, { className: "fai-connect__glyph" }),
|
|
3022
|
+
copied === client ? "Copied \u2014 paste in Claude" : labelFor(client)
|
|
3023
|
+
]
|
|
3024
|
+
},
|
|
3025
|
+
client
|
|
3026
|
+
);
|
|
3027
|
+
}
|
|
3028
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "fai-connect__manual-wrap", children: [
|
|
3029
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3030
|
+
"button",
|
|
3031
|
+
{
|
|
3032
|
+
type: "button",
|
|
3033
|
+
className: base,
|
|
3034
|
+
title: meta.hint,
|
|
3035
|
+
"aria-expanded": manualOpen,
|
|
3036
|
+
"aria-controls": manualId,
|
|
3037
|
+
onClick: () => {
|
|
3038
|
+
setManualOpen((o) => !o);
|
|
3039
|
+
onAction?.(client);
|
|
3040
|
+
},
|
|
3041
|
+
children: [
|
|
3042
|
+
/* @__PURE__ */ jsxRuntime.jsx(Glyph, { className: "fai-connect__glyph" }),
|
|
3043
|
+
labelFor(client)
|
|
3044
|
+
]
|
|
3045
|
+
}
|
|
3046
|
+
),
|
|
3047
|
+
manualOpen && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3048
|
+
ManualPopover,
|
|
3049
|
+
{
|
|
3050
|
+
id: manualId,
|
|
3051
|
+
snippet: buildManualConfigSnippet(server),
|
|
3052
|
+
copied: copied === client,
|
|
3053
|
+
onCopy: () => copy(buildManualConfigSnippet(server), client),
|
|
3054
|
+
onClose: () => setManualOpen(false)
|
|
3055
|
+
}
|
|
3056
|
+
)
|
|
3057
|
+
] }, client);
|
|
3058
|
+
})
|
|
3059
|
+
}
|
|
3060
|
+
);
|
|
3061
|
+
}
|
|
3062
|
+
function defaultClients(mcpbDownloadUrl) {
|
|
3063
|
+
return mcpbDownloadUrl ? ["claude-web", "claude-desktop", "cursor", "vscode", "manual"] : DEFAULT_CLIENTS;
|
|
3064
|
+
}
|
|
3065
|
+
function ManualPopover({
|
|
3066
|
+
id,
|
|
3067
|
+
snippet,
|
|
3068
|
+
copied,
|
|
3069
|
+
onCopy,
|
|
3070
|
+
onClose
|
|
3071
|
+
}) {
|
|
3072
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { id, className: "fai-connect__popover", role: "dialog", children: [
|
|
3073
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "fai-connect__popover-head", children: [
|
|
3074
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Add to any stdio MCP client" }),
|
|
3075
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3076
|
+
"button",
|
|
3077
|
+
{
|
|
3078
|
+
type: "button",
|
|
3079
|
+
className: "fai-connect__popover-close",
|
|
3080
|
+
"aria-label": "Close",
|
|
3081
|
+
onClick: onClose,
|
|
3082
|
+
children: "\xD7"
|
|
3083
|
+
}
|
|
3084
|
+
)
|
|
3085
|
+
] }),
|
|
3086
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "fai-connect__popover-hint", children: [
|
|
3087
|
+
"Paste into ",
|
|
3088
|
+
/* @__PURE__ */ jsxRuntime.jsx("code", { children: "claude_desktop_config.json" }),
|
|
3089
|
+
" (or any stdio MCP client config). Needs Node 18+."
|
|
3090
|
+
] }),
|
|
3091
|
+
/* @__PURE__ */ jsxRuntime.jsx("pre", { className: "fai-connect__snippet", children: snippet }),
|
|
3092
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "fai-connect__copy-btn", onClick: onCopy, children: copied ? "Copied" : "Copy snippet" })
|
|
3093
|
+
] });
|
|
3094
|
+
}
|
|
3095
|
+
|
|
3096
|
+
// src/connectors/mcpb.ts
|
|
3097
|
+
var MCPB_MANIFEST_VERSION = "0.2";
|
|
3098
|
+
var MCPB_MIN_NODE = ">=18.0.0";
|
|
3099
|
+
var DEFAULT_MCPB_ENTRY_POINT = "server/proxy.js";
|
|
3100
|
+
function buildMcpbManifest(input) {
|
|
3101
|
+
const entryPoint = input.entryPoint ?? DEFAULT_MCPB_ENTRY_POINT;
|
|
3102
|
+
return {
|
|
3103
|
+
manifest_version: MCPB_MANIFEST_VERSION,
|
|
3104
|
+
name: input.name,
|
|
3105
|
+
display_name: input.display_name ?? input.name,
|
|
3106
|
+
version: input.version,
|
|
3107
|
+
description: input.description,
|
|
3108
|
+
...input.long_description ? { long_description: input.long_description } : {},
|
|
3109
|
+
author: input.author,
|
|
3110
|
+
...input.homepage ? { homepage: input.homepage } : {},
|
|
3111
|
+
...input.documentation ? { documentation: input.documentation } : {},
|
|
3112
|
+
...input.support ? { support: input.support } : {},
|
|
3113
|
+
server: {
|
|
3114
|
+
type: "node",
|
|
3115
|
+
entry_point: entryPoint,
|
|
3116
|
+
mcp_config: {
|
|
3117
|
+
command: "npx",
|
|
3118
|
+
args: ["-y", "mcp-remote", input.mcpUrl]
|
|
3119
|
+
}
|
|
3120
|
+
},
|
|
3121
|
+
tools: input.tools ?? [],
|
|
3122
|
+
tools_generated: false,
|
|
3123
|
+
prompts_generated: false,
|
|
3124
|
+
...input.keywords ? { keywords: input.keywords } : {},
|
|
3125
|
+
license: input.license ?? "MIT",
|
|
3126
|
+
compatibility: {
|
|
3127
|
+
claude_desktop: ">=0.10.0",
|
|
3128
|
+
platforms: ["darwin", "win32", "linux"],
|
|
3129
|
+
runtimes: { node: MCPB_MIN_NODE }
|
|
3130
|
+
}
|
|
3131
|
+
};
|
|
3132
|
+
}
|
|
3133
|
+
function buildMcpbProxyStub(mcpUrl) {
|
|
3134
|
+
const urlLiteral = JSON.stringify(mcpUrl);
|
|
3135
|
+
return `#!/usr/bin/env node
|
|
3136
|
+
// MCPB proxy shim (generated by @particle-academy/agent-integrations).
|
|
3137
|
+
//
|
|
3138
|
+
// MCPB (Claude Desktop Extensions) only supports local stdio servers, but this
|
|
3139
|
+
// MCP server is a remote HTTP endpoint. The manifest's \`mcp_config\` invokes
|
|
3140
|
+
// \`npx -y mcp-remote <url>\` to bridge the gap \u2014 this file is the entry_point
|
|
3141
|
+
// fallback the manifest validator requires. If you're seeing this run,
|
|
3142
|
+
// mcp_config wasn't honored; spawn mcp-remote directly so the bundle still works.
|
|
3143
|
+
|
|
3144
|
+
const { spawn } = require("node:child_process");
|
|
3145
|
+
|
|
3146
|
+
const url = ${urlLiteral};
|
|
3147
|
+
const child = spawn("npx", ["-y", "mcp-remote", url], { stdio: "inherit" });
|
|
3148
|
+
|
|
3149
|
+
child.on("exit", (code) => process.exit(code ?? 0));
|
|
3150
|
+
process.on("SIGINT", () => child.kill("SIGINT"));
|
|
3151
|
+
process.on("SIGTERM", () => child.kill("SIGTERM"));
|
|
3152
|
+
`;
|
|
3153
|
+
}
|
|
3154
|
+
|
|
2756
3155
|
Object.defineProperty(exports, "clearUndoStack", {
|
|
2757
3156
|
enumerable: true,
|
|
2758
3157
|
get: function () { return fancyAutoCommon.clearStack; }
|
|
@@ -2797,7 +3196,17 @@ exports.AgentActivityHighlight = AgentActivityHighlight;
|
|
|
2797
3196
|
exports.AgentCursor = AgentCursor;
|
|
2798
3197
|
exports.AgentPanel = AgentPanel;
|
|
2799
3198
|
exports.BridgedForm = BridgedForm;
|
|
3199
|
+
exports.CLAUDE_CONNECTORS_URL = CLAUDE_CONNECTORS_URL;
|
|
3200
|
+
exports.CONNECTOR_GLYPHS = CONNECTOR_GLYPHS;
|
|
3201
|
+
exports.CONNECTOR_TARGETS = CONNECTOR_TARGETS;
|
|
3202
|
+
exports.ClaudeMark = ClaudeMark;
|
|
3203
|
+
exports.ConnectorButtons = ConnectorButtons;
|
|
3204
|
+
exports.CursorMark = CursorMark;
|
|
3205
|
+
exports.DEFAULT_MCPB_ENTRY_POINT = DEFAULT_MCPB_ENTRY_POINT;
|
|
3206
|
+
exports.DesktopMark = DesktopMark;
|
|
2800
3207
|
exports.InProcessTransport = InProcessTransport;
|
|
3208
|
+
exports.MCPB_MANIFEST_VERSION = MCPB_MANIFEST_VERSION;
|
|
3209
|
+
exports.MCPB_MIN_NODE = MCPB_MIN_NODE;
|
|
2801
3210
|
exports.MCP_PROTOCOL_VERSION = MCP_PROTOCOL_VERSION;
|
|
2802
3211
|
exports.MicroMcpServer = MicroMcpServer;
|
|
2803
3212
|
exports.RelayTransport = RelayTransport;
|
|
@@ -2805,13 +3214,23 @@ exports.ScreensActivityBridge = ScreensActivityBridge;
|
|
|
2805
3214
|
exports.ShareControls = ShareControls;
|
|
2806
3215
|
exports.SseRelayTransport = SseRelayTransport;
|
|
2807
3216
|
exports.ToolRegistry = ToolRegistry;
|
|
3217
|
+
exports.VscodeMark = VscodeMark;
|
|
3218
|
+
exports.WrenchMark = WrenchMark;
|
|
2808
3219
|
exports.attachInProcess = attachInProcess;
|
|
2809
3220
|
exports.attachRelay = attachRelay;
|
|
2810
3221
|
exports.attachSseRelay = attachSseRelay;
|
|
3222
|
+
exports.buildCursorDeeplink = buildCursorDeeplink;
|
|
3223
|
+
exports.buildManualConfig = buildManualConfig;
|
|
3224
|
+
exports.buildManualConfigSnippet = buildManualConfigSnippet;
|
|
3225
|
+
exports.buildMcpbManifest = buildMcpbManifest;
|
|
3226
|
+
exports.buildMcpbProxyStub = buildMcpbProxyStub;
|
|
2811
3227
|
exports.buildShareConfig = buildShareConfig;
|
|
2812
3228
|
exports.buildShareUrl = buildShareUrl;
|
|
3229
|
+
exports.buildVscodeDeeplink = buildVscodeDeeplink;
|
|
3230
|
+
exports.connectorHref = connectorHref;
|
|
2813
3231
|
exports.createSessionDescriptor = createSessionDescriptor;
|
|
2814
3232
|
exports.describeSession = describeSession;
|
|
3233
|
+
exports.encodeBase64Json = encodeBase64Json;
|
|
2815
3234
|
exports.ensureUndoToolsRegistered = ensureUndoToolsRegistered;
|
|
2816
3235
|
exports.errorResult = errorResult;
|
|
2817
3236
|
exports.readSessionFromUrl = readSessionFromUrl;
|
|
@@ -2825,6 +3244,7 @@ exports.registerSlidesBridge = registerSlidesBridge;
|
|
|
2825
3244
|
exports.registerTerminalBridge = registerTerminalBridge;
|
|
2826
3245
|
exports.registerUndoTools = registerUndoTools;
|
|
2827
3246
|
exports.rpcError = rpcError;
|
|
3247
|
+
exports.slugifyServerName = slugifyServerName;
|
|
2828
3248
|
exports.textResult = textResult;
|
|
2829
3249
|
exports.useAgentActivity = useAgentActivity;
|
|
2830
3250
|
exports.useAgentActivityForScreen = useAgentActivityForScreen;
|