multicorn-shield 1.0.0 → 1.1.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/CHANGELOG.md +32 -0
- package/dist/index.cjs +4 -0
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +4 -0
- package/dist/multicorn-proxy.js +270 -64
- package/dist/multicorn-shield.js +269 -63
- package/dist/shield-extension.js +64 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,38 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.1.0] - 2026-05-06
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- Kilo Code as a hosted proxy platform
|
|
13
|
+
- GitHub Copilot as a hosted proxy platform
|
|
14
|
+
- Continue as a hosted proxy platform
|
|
15
|
+
- Goose as a hosted proxy platform
|
|
16
|
+
- Claude Desktop as a hosted proxy platform
|
|
17
|
+
- Prereq check step in CLI wizard for all hosted proxy platforms
|
|
18
|
+
- Platform filter and search in dashboard platform select
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
|
|
22
|
+
- GitHub Copilot moved from native plugin to hosted proxy section in CLI wizard
|
|
23
|
+
- Kilo Code config snippet now includes `"type": "streamable-http"`
|
|
24
|
+
- Goose config snippet uses `"type": "streamable_http"` and `"url"` (SSE deprecated)
|
|
25
|
+
- ProxySetup is now a stepped wizard (prereq check, OS selection, proxy form, snippet, completion)
|
|
26
|
+
- Short name prompt removed from CLI wizard (uses agent name automatically)
|
|
27
|
+
|
|
28
|
+
### Removed
|
|
29
|
+
|
|
30
|
+
- Aider as a supported platform (no MCP client support)
|
|
31
|
+
|
|
32
|
+
### Fixed
|
|
33
|
+
|
|
34
|
+
- Proxy ALLOW_PRIVATE_TARGETS env var not bypassing localhost validation
|
|
35
|
+
- Goose prereq URL updated (moved from Block to the Agentic AI Foundation (AAIF))
|
|
36
|
+
- Continue prereq URL updated
|
|
37
|
+
- ProxySetup form input contrast (WCAG AA fix)
|
|
38
|
+
- Governance disclosure now lists all four native plugin platforms
|
|
39
|
+
|
|
8
40
|
## [1.0.0] - 2026-05-02
|
|
9
41
|
|
|
10
42
|
### Changed
|
package/dist/index.cjs
CHANGED
package/dist/index.d.cts
CHANGED
|
@@ -12,7 +12,7 @@ import { LitElement, PropertyValues, HTMLTemplateResult } from 'lit';
|
|
|
12
12
|
/**
|
|
13
13
|
* Agent client platforms supported by hosted proxy and native hooks (aligned with API validation).
|
|
14
14
|
*/
|
|
15
|
-
declare const AGENT_PLATFORM_SLUGS: readonly ["openclaw", "claude-code", "claude-desktop", "cursor", "windsurf", "cline", "gemini-cli", "other-mcp", "github-actions", "unknown"];
|
|
15
|
+
declare const AGENT_PLATFORM_SLUGS: readonly ["openclaw", "claude-code", "claude-desktop", "cursor", "windsurf", "cline", "gemini-cli", "continue-dev", "github-copilot", "goose", "kilo-code", "other-mcp", "github-actions", "unknown"];
|
|
16
16
|
type AgentPlatformSlug = (typeof AGENT_PLATFORM_SLUGS)[number];
|
|
17
17
|
/**
|
|
18
18
|
* Possible operational states for an agent.
|
package/dist/index.d.ts
CHANGED
|
@@ -12,7 +12,7 @@ import { LitElement, PropertyValues, HTMLTemplateResult } from 'lit';
|
|
|
12
12
|
/**
|
|
13
13
|
* Agent client platforms supported by hosted proxy and native hooks (aligned with API validation).
|
|
14
14
|
*/
|
|
15
|
-
declare const AGENT_PLATFORM_SLUGS: readonly ["openclaw", "claude-code", "claude-desktop", "cursor", "windsurf", "cline", "gemini-cli", "other-mcp", "github-actions", "unknown"];
|
|
15
|
+
declare const AGENT_PLATFORM_SLUGS: readonly ["openclaw", "claude-code", "claude-desktop", "cursor", "windsurf", "cline", "gemini-cli", "continue-dev", "github-copilot", "goose", "kilo-code", "other-mcp", "github-actions", "unknown"];
|
|
16
16
|
type AgentPlatformSlug = (typeof AGENT_PLATFORM_SLUGS)[number];
|
|
17
17
|
/**
|
|
18
18
|
* Possible operational states for an agent.
|
package/dist/index.js
CHANGED
package/dist/multicorn-proxy.js
CHANGED
|
@@ -752,31 +752,73 @@ function getClaudeDesktopConfigPath() {
|
|
|
752
752
|
);
|
|
753
753
|
}
|
|
754
754
|
}
|
|
755
|
+
function platformMenuLabelForSelection(sel) {
|
|
756
|
+
const slug = PLATFORM_BY_SELECTION[sel];
|
|
757
|
+
if (slug === void 0) return "Unknown";
|
|
758
|
+
const entry = INIT_WIZARD_PLATFORM_REGISTRY.find((e) => e.slug === slug);
|
|
759
|
+
return entry?.displayName ?? slug;
|
|
760
|
+
}
|
|
761
|
+
async function promptHostedProxyInstallPrereq(ask, platformLabel, prereqUrl) {
|
|
762
|
+
process.stderr.write("\n");
|
|
763
|
+
process.stderr.write(
|
|
764
|
+
style.bold("Before continuing, make sure you have ") + platformLabel + style.bold(" installed.") + "\n"
|
|
765
|
+
);
|
|
766
|
+
process.stderr.write(" \u2192 " + style.cyan(prereqUrl) + "\n\n");
|
|
767
|
+
const answer = await ask("Ready to continue? (Y/n) ");
|
|
768
|
+
return answer.trim().toLowerCase() !== "n";
|
|
769
|
+
}
|
|
770
|
+
function isPlatformDetectedForMenu(slug) {
|
|
771
|
+
switch (slug) {
|
|
772
|
+
case "openclaw":
|
|
773
|
+
return isOpenClawConnected();
|
|
774
|
+
case "claude-code":
|
|
775
|
+
return Promise.resolve(isClaudeCodeConnected());
|
|
776
|
+
case "cursor":
|
|
777
|
+
return isCursorConnected();
|
|
778
|
+
case "windsurf":
|
|
779
|
+
return isWindsurfConnected();
|
|
780
|
+
default:
|
|
781
|
+
return Promise.resolve(false);
|
|
782
|
+
}
|
|
783
|
+
}
|
|
755
784
|
async function promptPlatformSelection(ask) {
|
|
756
785
|
process.stderr.write(
|
|
757
|
-
"\n" + style.bold(style.violet("Which platform are you connecting?")) + "\n"
|
|
786
|
+
"\n" + style.bold(style.violet("Which platform are you connecting?")) + "\n\n"
|
|
758
787
|
);
|
|
759
|
-
const
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
const
|
|
767
|
-
|
|
768
|
-
|
|
788
|
+
const detectionSlugs = INIT_WIZARD_PLATFORM_REGISTRY.filter((e) => e.detectable).map(
|
|
789
|
+
(e) => e.slug
|
|
790
|
+
);
|
|
791
|
+
const connectedFlags = await Promise.all(
|
|
792
|
+
detectionSlugs.map((slug) => isPlatformDetectedForMenu(slug))
|
|
793
|
+
);
|
|
794
|
+
function markerFor(platform) {
|
|
795
|
+
const idx = detectionSlugs.indexOf(platform);
|
|
796
|
+
if (idx === -1) return "";
|
|
797
|
+
if (!connectedFlags[idx]) return "";
|
|
798
|
+
return " " + style.dim("\u25CF detected locally");
|
|
799
|
+
}
|
|
800
|
+
let optionNum = 1;
|
|
801
|
+
for (const section of INIT_WIZARD_MENU_SECTIONS) {
|
|
802
|
+
process.stderr.write(" " + style.dim(section.title) + "\n");
|
|
803
|
+
for (const item of section.items) {
|
|
804
|
+
const indent = optionNum >= 10 ? " " : " ";
|
|
805
|
+
process.stderr.write(
|
|
806
|
+
`${indent}${style.violet(String(optionNum))}. ${item.label}${markerFor(item.platform)}
|
|
769
807
|
`
|
|
770
|
-
|
|
808
|
+
);
|
|
809
|
+
optionNum++;
|
|
810
|
+
}
|
|
771
811
|
}
|
|
772
812
|
process.stderr.write(
|
|
773
|
-
|
|
813
|
+
"\n" + style.dim(
|
|
814
|
+
` Pick ${String(INIT_WIZARD_SELECTION_MAX)} to wrap a local MCP server with multicorn-shield --wrap.`
|
|
815
|
+
) + "\n"
|
|
774
816
|
);
|
|
775
817
|
let selection = 0;
|
|
776
818
|
while (selection === 0) {
|
|
777
|
-
const input = await ask(
|
|
819
|
+
const input = await ask(`Select (1-${String(INIT_WIZARD_SELECTION_MAX)}): `);
|
|
778
820
|
const num = parseInt(input.trim(), 10);
|
|
779
|
-
if (num >= 1 && num <=
|
|
821
|
+
if (num >= 1 && num <= INIT_WIZARD_SELECTION_MAX) {
|
|
780
822
|
selection = num;
|
|
781
823
|
}
|
|
782
824
|
}
|
|
@@ -847,12 +889,7 @@ async function promptProxyConfig(ask, agentName) {
|
|
|
847
889
|
}
|
|
848
890
|
targetUrl = input.trim();
|
|
849
891
|
}
|
|
850
|
-
const
|
|
851
|
-
const shortNameInput = await ask(
|
|
852
|
-
`
|
|
853
|
-
Short name (a nickname for this connection, used in your proxy URL): ${style.dim(`(${defaultShortName})`)} `
|
|
854
|
-
);
|
|
855
|
-
const shortName = shortNameInput.trim().length > 0 ? normalizeAgentName(shortNameInput.trim()) || defaultShortName : defaultShortName;
|
|
892
|
+
const shortName = normalizeAgentName(agentName) || "shield-mcp";
|
|
856
893
|
return { targetUrl, shortName };
|
|
857
894
|
}
|
|
858
895
|
async function createProxyConfig(baseUrl, apiKey, agentName, targetUrl, serverName, platform) {
|
|
@@ -896,24 +933,84 @@ async function createProxyConfig(baseUrl, apiKey, agentName, targetUrl, serverNa
|
|
|
896
933
|
const data = envelope["data"];
|
|
897
934
|
return typeof data?.["proxy_url"] === "string" ? data["proxy_url"] : "";
|
|
898
935
|
}
|
|
936
|
+
function gooseHostedProxyYaml(shortName, proxyUrl, bearerHeader) {
|
|
937
|
+
return `extensions:
|
|
938
|
+
${shortName}:
|
|
939
|
+
type: streamable_http
|
|
940
|
+
url: ${proxyUrl}
|
|
941
|
+
headers:
|
|
942
|
+
Authorization: ${bearerHeader}
|
|
943
|
+
enabled: true
|
|
944
|
+
timeout: 300
|
|
945
|
+
`;
|
|
946
|
+
}
|
|
899
947
|
function printPlatformSnippet(platform, routingToken, shortName, apiKey) {
|
|
900
|
-
const
|
|
948
|
+
const hostedInlinePlatforms = /* @__PURE__ */ new Set([
|
|
949
|
+
"cursor",
|
|
950
|
+
"claude-desktop",
|
|
951
|
+
"windsurf",
|
|
952
|
+
"cline",
|
|
953
|
+
"gemini-cli",
|
|
954
|
+
"kilo-code",
|
|
955
|
+
"github-copilot",
|
|
956
|
+
"continue-dev",
|
|
957
|
+
"goose"
|
|
958
|
+
]);
|
|
959
|
+
const usesInlineKey = hostedInlinePlatforms.has(platform);
|
|
901
960
|
const authHeader = usesInlineKey ? `Bearer ${apiKey}` : "Bearer YOUR_SHIELD_API_KEY";
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
961
|
+
let snippetText;
|
|
962
|
+
if (platform === "github-copilot") {
|
|
963
|
+
snippetText = JSON.stringify(
|
|
964
|
+
{
|
|
965
|
+
mcp: {
|
|
966
|
+
servers: {
|
|
967
|
+
[shortName]: {
|
|
968
|
+
type: "http",
|
|
969
|
+
url: routingToken,
|
|
970
|
+
headers: {
|
|
971
|
+
Authorization: authHeader
|
|
972
|
+
}
|
|
973
|
+
}
|
|
910
974
|
}
|
|
911
975
|
}
|
|
912
|
-
}
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
)
|
|
976
|
+
},
|
|
977
|
+
null,
|
|
978
|
+
2
|
|
979
|
+
);
|
|
980
|
+
} else if (platform === "goose") {
|
|
981
|
+
snippetText = gooseHostedProxyYaml(shortName, routingToken, authHeader);
|
|
982
|
+
} else if (platform === "gemini-cli") {
|
|
983
|
+
snippetText = JSON.stringify(
|
|
984
|
+
{
|
|
985
|
+
mcpServers: {
|
|
986
|
+
[shortName]: {
|
|
987
|
+
httpUrl: routingToken,
|
|
988
|
+
headers: {
|
|
989
|
+
Authorization: authHeader
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
},
|
|
994
|
+
null,
|
|
995
|
+
2
|
|
996
|
+
);
|
|
997
|
+
} else {
|
|
998
|
+
const urlKey = platform === "windsurf" ? "serverUrl" : "url";
|
|
999
|
+
snippetText = JSON.stringify(
|
|
1000
|
+
{
|
|
1001
|
+
mcpServers: {
|
|
1002
|
+
[shortName]: {
|
|
1003
|
+
[urlKey]: routingToken,
|
|
1004
|
+
headers: {
|
|
1005
|
+
Authorization: authHeader
|
|
1006
|
+
}
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
},
|
|
1010
|
+
null,
|
|
1011
|
+
2
|
|
1012
|
+
);
|
|
1013
|
+
}
|
|
917
1014
|
if (platform === "openclaw") {
|
|
918
1015
|
process.stderr.write("\n" + style.dim("Add this to your OpenClaw agent config:") + "\n\n");
|
|
919
1016
|
} else if (platform === "claude-code") {
|
|
@@ -947,10 +1044,28 @@ function printPlatformSnippet(platform, routingToken, shortName, apiKey) {
|
|
|
947
1044
|
"Add this to ~/.gemini/settings.json (create the file if it does not exist). For project-specific config, use .gemini/settings.json in your project root. Restart Gemini CLI after saving. Run /mcp to verify the server is connected."
|
|
948
1045
|
) + "\n\n"
|
|
949
1046
|
);
|
|
1047
|
+
} else if (platform === "kilo-code") {
|
|
1048
|
+
process.stderr.write(
|
|
1049
|
+
"\n" + style.dim("Add this to .kilocode/mcp.json in your project root.") + "\n\n"
|
|
1050
|
+
);
|
|
1051
|
+
} else if (platform === "github-copilot") {
|
|
1052
|
+
process.stderr.write(
|
|
1053
|
+
"\n" + style.dim(
|
|
1054
|
+
"Open VS Code Settings (JSON) and merge this under the mcp key. If you do not have an mcp section yet, add one. Copilot picks up MCP servers when you use Agent mode."
|
|
1055
|
+
) + "\n\n"
|
|
1056
|
+
);
|
|
1057
|
+
} else if (platform === "continue-dev") {
|
|
1058
|
+
process.stderr.write(
|
|
1059
|
+
"\n" + style.dim("Save this as .continue/mcpServers/shield.json in your workspace root.") + "\n\n"
|
|
1060
|
+
);
|
|
1061
|
+
} else if (platform === "goose") {
|
|
1062
|
+
process.stderr.write(
|
|
1063
|
+
"\n" + style.dim("Add this to ~/.config/goose/config.yaml under the extensions key.") + "\n\n"
|
|
1064
|
+
);
|
|
950
1065
|
} else {
|
|
951
1066
|
process.stderr.write("\n" + style.dim("Add this to ~/.cursor/mcp.json:") + "\n\n");
|
|
952
1067
|
}
|
|
953
|
-
process.stderr.write(style.cyan(
|
|
1068
|
+
process.stderr.write(style.cyan(snippetText) + "\n\n");
|
|
954
1069
|
if (!usesInlineKey) {
|
|
955
1070
|
process.stderr.write(
|
|
956
1071
|
style.dim(
|
|
@@ -988,6 +1103,14 @@ function printPlatformSnippet(platform, routingToken, shortName, apiKey) {
|
|
|
988
1103
|
) + "\n"
|
|
989
1104
|
);
|
|
990
1105
|
}
|
|
1106
|
+
if (platform === "github-copilot" || platform === "continue-dev") {
|
|
1107
|
+
process.stderr.write(
|
|
1108
|
+
style.dim("Reload the editor window if the MCP server does not appear immediately.") + "\n"
|
|
1109
|
+
);
|
|
1110
|
+
}
|
|
1111
|
+
if (platform === "goose") {
|
|
1112
|
+
process.stderr.write(style.dim("Start a new Goose session after updating config.") + "\n");
|
|
1113
|
+
}
|
|
991
1114
|
}
|
|
992
1115
|
async function runInit(explicitBaseUrl) {
|
|
993
1116
|
if (!process.stdin.isTTY) {
|
|
@@ -1076,8 +1199,8 @@ async function runInit(explicitBaseUrl) {
|
|
|
1076
1199
|
let postSaveNativeSkipNote = null;
|
|
1077
1200
|
const selection = await promptPlatformSelection(ask);
|
|
1078
1201
|
const selectedPlatform = PLATFORM_BY_SELECTION[selection] ?? "cursor";
|
|
1079
|
-
const selectedLabel =
|
|
1080
|
-
if (
|
|
1202
|
+
const selectedLabel = platformMenuLabelForSelection(selection);
|
|
1203
|
+
if (selectedPlatform === "other-mcp") {
|
|
1081
1204
|
const raw = existing !== null ? { ...existing } : {};
|
|
1082
1205
|
raw["apiKey"] = apiKey;
|
|
1083
1206
|
raw["baseUrl"] = resolvedBaseUrl;
|
|
@@ -1127,9 +1250,24 @@ An agent for ${selectedLabel} already exists: ${style.cyan(existingForPlatform.n
|
|
|
1127
1250
|
continue;
|
|
1128
1251
|
}
|
|
1129
1252
|
}
|
|
1253
|
+
const prereqEntry = INIT_WIZARD_PLATFORM_REGISTRY.find((e) => e.slug === selectedPlatform);
|
|
1254
|
+
if (prereqEntry?.prereqUrl !== void 0) {
|
|
1255
|
+
const proceed = await promptHostedProxyInstallPrereq(
|
|
1256
|
+
ask,
|
|
1257
|
+
prereqEntry.displayName,
|
|
1258
|
+
prereqEntry.prereqUrl
|
|
1259
|
+
);
|
|
1260
|
+
if (!proceed) {
|
|
1261
|
+
const another2 = await ask("\nConnect another agent? (Y/n) ");
|
|
1262
|
+
if (another2.trim().toLowerCase() === "n") {
|
|
1263
|
+
configuring = false;
|
|
1264
|
+
}
|
|
1265
|
+
continue;
|
|
1266
|
+
}
|
|
1267
|
+
}
|
|
1130
1268
|
const agentName = await promptAgentName(ask, selectedPlatform);
|
|
1131
1269
|
let setupSucceeded = false;
|
|
1132
|
-
if (
|
|
1270
|
+
if (selectedPlatform === "openclaw") {
|
|
1133
1271
|
let detection;
|
|
1134
1272
|
try {
|
|
1135
1273
|
detection = await detectOpenClaw();
|
|
@@ -1209,7 +1347,7 @@ An agent for ${selectedLabel} already exists: ${style.cyan(existingForPlatform.n
|
|
|
1209
1347
|
agentName
|
|
1210
1348
|
});
|
|
1211
1349
|
setupSucceeded = true;
|
|
1212
|
-
} else if (
|
|
1350
|
+
} else if (selectedPlatform === "claude-code") {
|
|
1213
1351
|
process.stderr.write("\nTo connect Claude Code to Shield:\n\n");
|
|
1214
1352
|
process.stderr.write(
|
|
1215
1353
|
" " + style.bold("Step 1") + " - Add the Multicorn marketplace:\n " + style.cyan("claude plugin marketplace add Multicorn-AI/multicorn-shield") + "\n\n"
|
|
@@ -1227,7 +1365,7 @@ An agent for ${selectedLabel} already exists: ${style.cyan(existingForPlatform.n
|
|
|
1227
1365
|
agentName
|
|
1228
1366
|
});
|
|
1229
1367
|
setupSucceeded = true;
|
|
1230
|
-
} else if (
|
|
1368
|
+
} else if (selectedPlatform === "windsurf") {
|
|
1231
1369
|
const windsurfMode = await promptWindsurfIntegrationMode(ask);
|
|
1232
1370
|
if (windsurfMode === "native") {
|
|
1233
1371
|
try {
|
|
@@ -1315,7 +1453,7 @@ An agent for ${selectedLabel} already exists: ${style.cyan(existingForPlatform.n
|
|
|
1315
1453
|
setupSucceeded = true;
|
|
1316
1454
|
}
|
|
1317
1455
|
}
|
|
1318
|
-
} else if (
|
|
1456
|
+
} else if (selectedPlatform === "gemini-cli") {
|
|
1319
1457
|
const geminiMode = await promptGeminiCliIntegrationMode(ask);
|
|
1320
1458
|
if (geminiMode === "native") {
|
|
1321
1459
|
try {
|
|
@@ -1400,7 +1538,7 @@ An agent for ${selectedLabel} already exists: ${style.cyan(existingForPlatform.n
|
|
|
1400
1538
|
setupSucceeded = true;
|
|
1401
1539
|
}
|
|
1402
1540
|
}
|
|
1403
|
-
} else if (
|
|
1541
|
+
} else if (selectedPlatform === "cline") {
|
|
1404
1542
|
const clineMode = await promptClineIntegrationMode(ask);
|
|
1405
1543
|
if (clineMode === "native") {
|
|
1406
1544
|
try {
|
|
@@ -1586,6 +1724,26 @@ An agent for ${selectedLabel} already exists: ${style.cyan(existingForPlatform.n
|
|
|
1586
1724
|
"\n" + style.bold("To complete your Cursor setup:") + "\n 1. If you don't have Cursor yet, download it from " + style.cyan("https://cursor.com/downloads") + "\n 2. Open " + style.cyan("~/.cursor/mcp.json") + " and paste the config snippet shown above\n 3. Restart Cursor (or launch it for the first time) to load the new MCP server\n"
|
|
1587
1725
|
);
|
|
1588
1726
|
}
|
|
1727
|
+
if (configuredPlatforms.has("kilo-code")) {
|
|
1728
|
+
blocks.push(
|
|
1729
|
+
"\n" + style.bold("To complete your Kilo Code setup:") + "\n 1. Save the snippet to " + style.cyan(".kilocode/mcp.json") + " in your project root, or under the mcp key in " + style.cyan("kilo.jsonc") + "\n 2. Run your next task in Kilo Code so it picks up the MCP server\n"
|
|
1730
|
+
);
|
|
1731
|
+
}
|
|
1732
|
+
if (configuredPlatforms.has("github-copilot")) {
|
|
1733
|
+
blocks.push(
|
|
1734
|
+
"\n" + style.bold("GitHub Copilot MCP:") + "\n 1. Open VS Code Command Palette: Preferences: Open User Settings (JSON)\n 2. Merge the snippet under the " + style.cyan("mcp") + " key and save\n 3. Use Copilot Agent mode and verify the MCP server connects\n"
|
|
1735
|
+
);
|
|
1736
|
+
}
|
|
1737
|
+
if (configuredPlatforms.has("continue-dev")) {
|
|
1738
|
+
blocks.push(
|
|
1739
|
+
"\n" + style.bold("Continue MCP:") + "\n 1. If you don't have Continue yet, install from " + style.cyan("https://docs.continue.dev/ide-extensions/install") + "\n 2. Save JSON as " + style.cyan(".continue/mcpServers/shield.json") + " in your workspace, or add to " + style.cyan("~/.continue/config.yaml") + "\n 3. Reload VS Code and open Continue agent mode\n"
|
|
1740
|
+
);
|
|
1741
|
+
}
|
|
1742
|
+
if (configuredPlatforms.has("goose")) {
|
|
1743
|
+
blocks.push(
|
|
1744
|
+
"\n" + style.bold("Goose MCP extension:") + "\n 1. Edit " + style.cyan("~/.config/goose/config.yaml") + " (or use goose configure)\n 2. Restart Goose CLI or Desktop\n"
|
|
1745
|
+
);
|
|
1746
|
+
}
|
|
1589
1747
|
const windsurfNativeConfigured = configuredAgents.some(
|
|
1590
1748
|
(a) => a.platform === "windsurf" && a.windsurfIntegration === "native"
|
|
1591
1749
|
);
|
|
@@ -1641,7 +1799,7 @@ An agent for ${selectedLabel} already exists: ${style.cyan(existingForPlatform.n
|
|
|
1641
1799
|
}
|
|
1642
1800
|
return lastConfig;
|
|
1643
1801
|
}
|
|
1644
|
-
var style, BANNER, NativePluginPrerequisiteMissingError, CONFIG_DIR, CONFIG_PATH, OPENCLAW_CONFIG_PATH, ANSI_PATTERN, OPENCLAW_MIN_VERSION,
|
|
1802
|
+
var style, BANNER, NativePluginPrerequisiteMissingError, CONFIG_DIR, CONFIG_PATH, OPENCLAW_CONFIG_PATH, ANSI_PATTERN, OPENCLAW_MIN_VERSION, INIT_WIZARD_PLATFORM_REGISTRY, INIT_WIZARD_MENU_SECTIONS, INIT_WIZARD_SELECTION_MAX, PLATFORM_BY_SELECTION, DEFAULT_AGENT_NAMES, DEFAULT_SHIELD_API_BASE_URL;
|
|
1645
1803
|
var init_config = __esm({
|
|
1646
1804
|
"src/proxy/config.ts"() {
|
|
1647
1805
|
style = {
|
|
@@ -1672,26 +1830,70 @@ var init_config = __esm({
|
|
|
1672
1830
|
OPENCLAW_CONFIG_PATH = join(homedir(), ".openclaw", "openclaw.json");
|
|
1673
1831
|
ANSI_PATTERN = new RegExp(String.fromCharCode(27) + "\\[[0-9;]*[a-zA-Z]", "g");
|
|
1674
1832
|
OPENCLAW_MIN_VERSION = "2026.2.26";
|
|
1675
|
-
|
|
1676
|
-
"OpenClaw",
|
|
1677
|
-
"Claude Code",
|
|
1678
|
-
"
|
|
1679
|
-
"
|
|
1680
|
-
"
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1833
|
+
INIT_WIZARD_PLATFORM_REGISTRY = [
|
|
1834
|
+
{ slug: "openclaw", displayName: "OpenClaw", section: "native", detectable: true },
|
|
1835
|
+
{ slug: "claude-code", displayName: "Claude Code", section: "native", detectable: true },
|
|
1836
|
+
{ slug: "windsurf", displayName: "Windsurf", section: "native", detectable: true },
|
|
1837
|
+
{ slug: "cline", displayName: "Cline", section: "native", detectable: false },
|
|
1838
|
+
{ slug: "gemini-cli", displayName: "Gemini CLI", section: "native", detectable: false },
|
|
1839
|
+
{
|
|
1840
|
+
slug: "cursor",
|
|
1841
|
+
displayName: "Cursor",
|
|
1842
|
+
section: "hosted",
|
|
1843
|
+
prereqUrl: "https://www.cursor.com/downloads",
|
|
1844
|
+
detectable: true
|
|
1845
|
+
},
|
|
1846
|
+
{
|
|
1847
|
+
slug: "claude-desktop",
|
|
1848
|
+
displayName: "Claude Desktop",
|
|
1849
|
+
section: "hosted",
|
|
1850
|
+
prereqUrl: "https://claude.ai/download",
|
|
1851
|
+
detectable: false
|
|
1852
|
+
},
|
|
1853
|
+
{
|
|
1854
|
+
slug: "github-copilot",
|
|
1855
|
+
displayName: "GitHub Copilot",
|
|
1856
|
+
section: "hosted",
|
|
1857
|
+
prereqUrl: "https://docs.github.com/en/copilot/get-started",
|
|
1858
|
+
detectable: false
|
|
1859
|
+
},
|
|
1860
|
+
{
|
|
1861
|
+
slug: "kilo-code",
|
|
1862
|
+
displayName: "Kilo Code",
|
|
1863
|
+
section: "hosted",
|
|
1864
|
+
prereqUrl: "https://kilocode.ai/docs/getting-started",
|
|
1865
|
+
detectable: false
|
|
1866
|
+
},
|
|
1867
|
+
{
|
|
1868
|
+
slug: "continue-dev",
|
|
1869
|
+
displayName: "Continue",
|
|
1870
|
+
section: "hosted",
|
|
1871
|
+
prereqUrl: "https://docs.continue.dev/ide-extensions/install",
|
|
1872
|
+
detectable: false
|
|
1873
|
+
},
|
|
1874
|
+
{
|
|
1875
|
+
slug: "goose",
|
|
1876
|
+
displayName: "Goose",
|
|
1877
|
+
section: "hosted",
|
|
1878
|
+
prereqUrl: "https://goose-docs.ai/docs/quickstart/",
|
|
1879
|
+
detectable: false
|
|
1880
|
+
},
|
|
1881
|
+
{ slug: "other-mcp", displayName: "Local MCP / Other", section: "hosted", detectable: false }
|
|
1684
1882
|
];
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
};
|
|
1883
|
+
INIT_WIZARD_MENU_SECTIONS = (() => {
|
|
1884
|
+
const itemsFor = (section) => INIT_WIZARD_PLATFORM_REGISTRY.filter((e) => e.section === section).map((e) => ({
|
|
1885
|
+
platform: e.slug,
|
|
1886
|
+
label: e.displayName
|
|
1887
|
+
}));
|
|
1888
|
+
return [
|
|
1889
|
+
{ title: "Recommended (native plugin)", items: itemsFor("native") },
|
|
1890
|
+
{ title: "Hosted proxy (MCP only)", items: itemsFor("hosted") }
|
|
1891
|
+
];
|
|
1892
|
+
})();
|
|
1893
|
+
INIT_WIZARD_SELECTION_MAX = INIT_WIZARD_PLATFORM_REGISTRY.length;
|
|
1894
|
+
PLATFORM_BY_SELECTION = Object.fromEntries(
|
|
1895
|
+
INIT_WIZARD_PLATFORM_REGISTRY.map((e, i) => [i + 1, e.slug])
|
|
1896
|
+
);
|
|
1695
1897
|
DEFAULT_AGENT_NAMES = {
|
|
1696
1898
|
openclaw: "my-openclaw-agent",
|
|
1697
1899
|
"claude-code": "my-claude-code-agent",
|
|
@@ -1699,7 +1901,11 @@ var init_config = __esm({
|
|
|
1699
1901
|
windsurf: "my-windsurf-agent",
|
|
1700
1902
|
cline: "my-cline-agent",
|
|
1701
1903
|
"claude-desktop": "my-claude-desktop-agent",
|
|
1702
|
-
"gemini-cli": "my-gemini-cli-agent"
|
|
1904
|
+
"gemini-cli": "my-gemini-cli-agent",
|
|
1905
|
+
"kilo-code": "my-kilo-code-agent",
|
|
1906
|
+
"github-copilot": "my-github-copilot-agent",
|
|
1907
|
+
"continue-dev": "my-continue-agent",
|
|
1908
|
+
goose: "my-goose-agent"
|
|
1703
1909
|
};
|
|
1704
1910
|
DEFAULT_SHIELD_API_BASE_URL = "https://api.multicorn.ai";
|
|
1705
1911
|
}
|
package/dist/multicorn-shield.js
CHANGED
|
@@ -771,26 +771,99 @@ function getClaudeDesktopConfigPath() {
|
|
|
771
771
|
);
|
|
772
772
|
}
|
|
773
773
|
}
|
|
774
|
-
var
|
|
775
|
-
"OpenClaw",
|
|
776
|
-
"Claude Code",
|
|
777
|
-
"
|
|
778
|
-
"
|
|
779
|
-
"
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
774
|
+
var INIT_WIZARD_PLATFORM_REGISTRY = [
|
|
775
|
+
{ slug: "openclaw", displayName: "OpenClaw", section: "native", detectable: true },
|
|
776
|
+
{ slug: "claude-code", displayName: "Claude Code", section: "native", detectable: true },
|
|
777
|
+
{ slug: "windsurf", displayName: "Windsurf", section: "native", detectable: true },
|
|
778
|
+
{ slug: "cline", displayName: "Cline", section: "native", detectable: false },
|
|
779
|
+
{ slug: "gemini-cli", displayName: "Gemini CLI", section: "native", detectable: false },
|
|
780
|
+
{
|
|
781
|
+
slug: "cursor",
|
|
782
|
+
displayName: "Cursor",
|
|
783
|
+
section: "hosted",
|
|
784
|
+
prereqUrl: "https://www.cursor.com/downloads",
|
|
785
|
+
detectable: true
|
|
786
|
+
},
|
|
787
|
+
{
|
|
788
|
+
slug: "claude-desktop",
|
|
789
|
+
displayName: "Claude Desktop",
|
|
790
|
+
section: "hosted",
|
|
791
|
+
prereqUrl: "https://claude.ai/download",
|
|
792
|
+
detectable: false
|
|
793
|
+
},
|
|
794
|
+
{
|
|
795
|
+
slug: "github-copilot",
|
|
796
|
+
displayName: "GitHub Copilot",
|
|
797
|
+
section: "hosted",
|
|
798
|
+
prereqUrl: "https://docs.github.com/en/copilot/get-started",
|
|
799
|
+
detectable: false
|
|
800
|
+
},
|
|
801
|
+
{
|
|
802
|
+
slug: "kilo-code",
|
|
803
|
+
displayName: "Kilo Code",
|
|
804
|
+
section: "hosted",
|
|
805
|
+
prereqUrl: "https://kilocode.ai/docs/getting-started",
|
|
806
|
+
detectable: false
|
|
807
|
+
},
|
|
808
|
+
{
|
|
809
|
+
slug: "continue-dev",
|
|
810
|
+
displayName: "Continue",
|
|
811
|
+
section: "hosted",
|
|
812
|
+
prereqUrl: "https://docs.continue.dev/ide-extensions/install",
|
|
813
|
+
detectable: false
|
|
814
|
+
},
|
|
815
|
+
{
|
|
816
|
+
slug: "goose",
|
|
817
|
+
displayName: "Goose",
|
|
818
|
+
section: "hosted",
|
|
819
|
+
prereqUrl: "https://goose-docs.ai/docs/quickstart/",
|
|
820
|
+
detectable: false
|
|
821
|
+
},
|
|
822
|
+
{ slug: "other-mcp", displayName: "Local MCP / Other", section: "hosted", detectable: false }
|
|
783
823
|
];
|
|
784
|
-
var
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
};
|
|
824
|
+
var INIT_WIZARD_MENU_SECTIONS = (() => {
|
|
825
|
+
const itemsFor = (section) => INIT_WIZARD_PLATFORM_REGISTRY.filter((e) => e.section === section).map((e) => ({
|
|
826
|
+
platform: e.slug,
|
|
827
|
+
label: e.displayName
|
|
828
|
+
}));
|
|
829
|
+
return [
|
|
830
|
+
{ title: "Recommended (native plugin)", items: itemsFor("native") },
|
|
831
|
+
{ title: "Hosted proxy (MCP only)", items: itemsFor("hosted") }
|
|
832
|
+
];
|
|
833
|
+
})();
|
|
834
|
+
var INIT_WIZARD_SELECTION_MAX = INIT_WIZARD_PLATFORM_REGISTRY.length;
|
|
835
|
+
var PLATFORM_BY_SELECTION = Object.fromEntries(
|
|
836
|
+
INIT_WIZARD_PLATFORM_REGISTRY.map((e, i) => [i + 1, e.slug])
|
|
837
|
+
);
|
|
838
|
+
function platformMenuLabelForSelection(sel) {
|
|
839
|
+
const slug = PLATFORM_BY_SELECTION[sel];
|
|
840
|
+
if (slug === void 0) return "Unknown";
|
|
841
|
+
const entry = INIT_WIZARD_PLATFORM_REGISTRY.find((e) => e.slug === slug);
|
|
842
|
+
return entry?.displayName ?? slug;
|
|
843
|
+
}
|
|
844
|
+
async function promptHostedProxyInstallPrereq(ask, platformLabel, prereqUrl) {
|
|
845
|
+
process.stderr.write("\n");
|
|
846
|
+
process.stderr.write(
|
|
847
|
+
style.bold("Before continuing, make sure you have ") + platformLabel + style.bold(" installed.") + "\n"
|
|
848
|
+
);
|
|
849
|
+
process.stderr.write(" \u2192 " + style.cyan(prereqUrl) + "\n\n");
|
|
850
|
+
const answer = await ask("Ready to continue? (Y/n) ");
|
|
851
|
+
return answer.trim().toLowerCase() !== "n";
|
|
852
|
+
}
|
|
853
|
+
function isPlatformDetectedForMenu(slug) {
|
|
854
|
+
switch (slug) {
|
|
855
|
+
case "openclaw":
|
|
856
|
+
return isOpenClawConnected();
|
|
857
|
+
case "claude-code":
|
|
858
|
+
return Promise.resolve(isClaudeCodeConnected());
|
|
859
|
+
case "cursor":
|
|
860
|
+
return isCursorConnected();
|
|
861
|
+
case "windsurf":
|
|
862
|
+
return isWindsurfConnected();
|
|
863
|
+
default:
|
|
864
|
+
return Promise.resolve(false);
|
|
865
|
+
}
|
|
866
|
+
}
|
|
794
867
|
var DEFAULT_AGENT_NAMES = {
|
|
795
868
|
openclaw: "my-openclaw-agent",
|
|
796
869
|
"claude-code": "my-claude-code-agent",
|
|
@@ -798,33 +871,50 @@ var DEFAULT_AGENT_NAMES = {
|
|
|
798
871
|
windsurf: "my-windsurf-agent",
|
|
799
872
|
cline: "my-cline-agent",
|
|
800
873
|
"claude-desktop": "my-claude-desktop-agent",
|
|
801
|
-
"gemini-cli": "my-gemini-cli-agent"
|
|
874
|
+
"gemini-cli": "my-gemini-cli-agent",
|
|
875
|
+
"kilo-code": "my-kilo-code-agent",
|
|
876
|
+
"github-copilot": "my-github-copilot-agent",
|
|
877
|
+
"continue-dev": "my-continue-agent",
|
|
878
|
+
goose: "my-goose-agent"
|
|
802
879
|
};
|
|
803
880
|
async function promptPlatformSelection(ask) {
|
|
804
881
|
process.stderr.write(
|
|
805
|
-
"\n" + style.bold(style.violet("Which platform are you connecting?")) + "\n"
|
|
882
|
+
"\n" + style.bold(style.violet("Which platform are you connecting?")) + "\n\n"
|
|
806
883
|
);
|
|
807
|
-
const
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
const
|
|
815
|
-
|
|
816
|
-
|
|
884
|
+
const detectionSlugs = INIT_WIZARD_PLATFORM_REGISTRY.filter((e) => e.detectable).map(
|
|
885
|
+
(e) => e.slug
|
|
886
|
+
);
|
|
887
|
+
const connectedFlags = await Promise.all(
|
|
888
|
+
detectionSlugs.map((slug) => isPlatformDetectedForMenu(slug))
|
|
889
|
+
);
|
|
890
|
+
function markerFor(platform) {
|
|
891
|
+
const idx = detectionSlugs.indexOf(platform);
|
|
892
|
+
if (idx === -1) return "";
|
|
893
|
+
if (!connectedFlags[idx]) return "";
|
|
894
|
+
return " " + style.dim("\u25CF detected locally");
|
|
895
|
+
}
|
|
896
|
+
let optionNum = 1;
|
|
897
|
+
for (const section of INIT_WIZARD_MENU_SECTIONS) {
|
|
898
|
+
process.stderr.write(" " + style.dim(section.title) + "\n");
|
|
899
|
+
for (const item of section.items) {
|
|
900
|
+
const indent = optionNum >= 10 ? " " : " ";
|
|
901
|
+
process.stderr.write(
|
|
902
|
+
`${indent}${style.violet(String(optionNum))}. ${item.label}${markerFor(item.platform)}
|
|
817
903
|
`
|
|
818
|
-
|
|
904
|
+
);
|
|
905
|
+
optionNum++;
|
|
906
|
+
}
|
|
819
907
|
}
|
|
820
908
|
process.stderr.write(
|
|
821
|
-
|
|
909
|
+
"\n" + style.dim(
|
|
910
|
+
` Pick ${String(INIT_WIZARD_SELECTION_MAX)} to wrap a local MCP server with multicorn-shield --wrap.`
|
|
911
|
+
) + "\n"
|
|
822
912
|
);
|
|
823
913
|
let selection = 0;
|
|
824
914
|
while (selection === 0) {
|
|
825
|
-
const input = await ask(
|
|
915
|
+
const input = await ask(`Select (1-${String(INIT_WIZARD_SELECTION_MAX)}): `);
|
|
826
916
|
const num = parseInt(input.trim(), 10);
|
|
827
|
-
if (num >= 1 && num <=
|
|
917
|
+
if (num >= 1 && num <= INIT_WIZARD_SELECTION_MAX) {
|
|
828
918
|
selection = num;
|
|
829
919
|
}
|
|
830
920
|
}
|
|
@@ -895,12 +985,7 @@ async function promptProxyConfig(ask, agentName) {
|
|
|
895
985
|
}
|
|
896
986
|
targetUrl = input.trim();
|
|
897
987
|
}
|
|
898
|
-
const
|
|
899
|
-
const shortNameInput = await ask(
|
|
900
|
-
`
|
|
901
|
-
Short name (a nickname for this connection, used in your proxy URL): ${style.dim(`(${defaultShortName})`)} `
|
|
902
|
-
);
|
|
903
|
-
const shortName = shortNameInput.trim().length > 0 ? normalizeAgentName(shortNameInput.trim()) || defaultShortName : defaultShortName;
|
|
988
|
+
const shortName = normalizeAgentName(agentName) || "shield-mcp";
|
|
904
989
|
return { targetUrl, shortName };
|
|
905
990
|
}
|
|
906
991
|
async function createProxyConfig(baseUrl, apiKey, agentName, targetUrl, serverName, platform) {
|
|
@@ -944,24 +1029,84 @@ async function createProxyConfig(baseUrl, apiKey, agentName, targetUrl, serverNa
|
|
|
944
1029
|
const data = envelope["data"];
|
|
945
1030
|
return typeof data?.["proxy_url"] === "string" ? data["proxy_url"] : "";
|
|
946
1031
|
}
|
|
1032
|
+
function gooseHostedProxyYaml(shortName, proxyUrl, bearerHeader) {
|
|
1033
|
+
return `extensions:
|
|
1034
|
+
${shortName}:
|
|
1035
|
+
type: streamable_http
|
|
1036
|
+
url: ${proxyUrl}
|
|
1037
|
+
headers:
|
|
1038
|
+
Authorization: ${bearerHeader}
|
|
1039
|
+
enabled: true
|
|
1040
|
+
timeout: 300
|
|
1041
|
+
`;
|
|
1042
|
+
}
|
|
947
1043
|
function printPlatformSnippet(platform, routingToken, shortName, apiKey) {
|
|
948
|
-
const
|
|
1044
|
+
const hostedInlinePlatforms = /* @__PURE__ */ new Set([
|
|
1045
|
+
"cursor",
|
|
1046
|
+
"claude-desktop",
|
|
1047
|
+
"windsurf",
|
|
1048
|
+
"cline",
|
|
1049
|
+
"gemini-cli",
|
|
1050
|
+
"kilo-code",
|
|
1051
|
+
"github-copilot",
|
|
1052
|
+
"continue-dev",
|
|
1053
|
+
"goose"
|
|
1054
|
+
]);
|
|
1055
|
+
const usesInlineKey = hostedInlinePlatforms.has(platform);
|
|
949
1056
|
const authHeader = usesInlineKey ? `Bearer ${apiKey}` : "Bearer YOUR_SHIELD_API_KEY";
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
1057
|
+
let snippetText;
|
|
1058
|
+
if (platform === "github-copilot") {
|
|
1059
|
+
snippetText = JSON.stringify(
|
|
1060
|
+
{
|
|
1061
|
+
mcp: {
|
|
1062
|
+
servers: {
|
|
1063
|
+
[shortName]: {
|
|
1064
|
+
type: "http",
|
|
1065
|
+
url: routingToken,
|
|
1066
|
+
headers: {
|
|
1067
|
+
Authorization: authHeader
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
958
1070
|
}
|
|
959
1071
|
}
|
|
960
|
-
}
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
)
|
|
1072
|
+
},
|
|
1073
|
+
null,
|
|
1074
|
+
2
|
|
1075
|
+
);
|
|
1076
|
+
} else if (platform === "goose") {
|
|
1077
|
+
snippetText = gooseHostedProxyYaml(shortName, routingToken, authHeader);
|
|
1078
|
+
} else if (platform === "gemini-cli") {
|
|
1079
|
+
snippetText = JSON.stringify(
|
|
1080
|
+
{
|
|
1081
|
+
mcpServers: {
|
|
1082
|
+
[shortName]: {
|
|
1083
|
+
httpUrl: routingToken,
|
|
1084
|
+
headers: {
|
|
1085
|
+
Authorization: authHeader
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
1088
|
+
}
|
|
1089
|
+
},
|
|
1090
|
+
null,
|
|
1091
|
+
2
|
|
1092
|
+
);
|
|
1093
|
+
} else {
|
|
1094
|
+
const urlKey = platform === "windsurf" ? "serverUrl" : "url";
|
|
1095
|
+
snippetText = JSON.stringify(
|
|
1096
|
+
{
|
|
1097
|
+
mcpServers: {
|
|
1098
|
+
[shortName]: {
|
|
1099
|
+
[urlKey]: routingToken,
|
|
1100
|
+
headers: {
|
|
1101
|
+
Authorization: authHeader
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
},
|
|
1106
|
+
null,
|
|
1107
|
+
2
|
|
1108
|
+
);
|
|
1109
|
+
}
|
|
965
1110
|
if (platform === "openclaw") {
|
|
966
1111
|
process.stderr.write("\n" + style.dim("Add this to your OpenClaw agent config:") + "\n\n");
|
|
967
1112
|
} else if (platform === "claude-code") {
|
|
@@ -995,10 +1140,28 @@ function printPlatformSnippet(platform, routingToken, shortName, apiKey) {
|
|
|
995
1140
|
"Add this to ~/.gemini/settings.json (create the file if it does not exist). For project-specific config, use .gemini/settings.json in your project root. Restart Gemini CLI after saving. Run /mcp to verify the server is connected."
|
|
996
1141
|
) + "\n\n"
|
|
997
1142
|
);
|
|
1143
|
+
} else if (platform === "kilo-code") {
|
|
1144
|
+
process.stderr.write(
|
|
1145
|
+
"\n" + style.dim("Add this to .kilocode/mcp.json in your project root.") + "\n\n"
|
|
1146
|
+
);
|
|
1147
|
+
} else if (platform === "github-copilot") {
|
|
1148
|
+
process.stderr.write(
|
|
1149
|
+
"\n" + style.dim(
|
|
1150
|
+
"Open VS Code Settings (JSON) and merge this under the mcp key. If you do not have an mcp section yet, add one. Copilot picks up MCP servers when you use Agent mode."
|
|
1151
|
+
) + "\n\n"
|
|
1152
|
+
);
|
|
1153
|
+
} else if (platform === "continue-dev") {
|
|
1154
|
+
process.stderr.write(
|
|
1155
|
+
"\n" + style.dim("Save this as .continue/mcpServers/shield.json in your workspace root.") + "\n\n"
|
|
1156
|
+
);
|
|
1157
|
+
} else if (platform === "goose") {
|
|
1158
|
+
process.stderr.write(
|
|
1159
|
+
"\n" + style.dim("Add this to ~/.config/goose/config.yaml under the extensions key.") + "\n\n"
|
|
1160
|
+
);
|
|
998
1161
|
} else {
|
|
999
1162
|
process.stderr.write("\n" + style.dim("Add this to ~/.cursor/mcp.json:") + "\n\n");
|
|
1000
1163
|
}
|
|
1001
|
-
process.stderr.write(style.cyan(
|
|
1164
|
+
process.stderr.write(style.cyan(snippetText) + "\n\n");
|
|
1002
1165
|
if (!usesInlineKey) {
|
|
1003
1166
|
process.stderr.write(
|
|
1004
1167
|
style.dim(
|
|
@@ -1036,6 +1199,14 @@ function printPlatformSnippet(platform, routingToken, shortName, apiKey) {
|
|
|
1036
1199
|
) + "\n"
|
|
1037
1200
|
);
|
|
1038
1201
|
}
|
|
1202
|
+
if (platform === "github-copilot" || platform === "continue-dev") {
|
|
1203
|
+
process.stderr.write(
|
|
1204
|
+
style.dim("Reload the editor window if the MCP server does not appear immediately.") + "\n"
|
|
1205
|
+
);
|
|
1206
|
+
}
|
|
1207
|
+
if (platform === "goose") {
|
|
1208
|
+
process.stderr.write(style.dim("Start a new Goose session after updating config.") + "\n");
|
|
1209
|
+
}
|
|
1039
1210
|
}
|
|
1040
1211
|
var DEFAULT_SHIELD_API_BASE_URL = "https://api.multicorn.ai";
|
|
1041
1212
|
async function runInit(explicitBaseUrl) {
|
|
@@ -1125,8 +1296,8 @@ async function runInit(explicitBaseUrl) {
|
|
|
1125
1296
|
let postSaveNativeSkipNote = null;
|
|
1126
1297
|
const selection = await promptPlatformSelection(ask);
|
|
1127
1298
|
const selectedPlatform = PLATFORM_BY_SELECTION[selection] ?? "cursor";
|
|
1128
|
-
const selectedLabel =
|
|
1129
|
-
if (
|
|
1299
|
+
const selectedLabel = platformMenuLabelForSelection(selection);
|
|
1300
|
+
if (selectedPlatform === "other-mcp") {
|
|
1130
1301
|
const raw = existing !== null ? { ...existing } : {};
|
|
1131
1302
|
raw["apiKey"] = apiKey;
|
|
1132
1303
|
raw["baseUrl"] = resolvedBaseUrl;
|
|
@@ -1176,9 +1347,24 @@ An agent for ${selectedLabel} already exists: ${style.cyan(existingForPlatform.n
|
|
|
1176
1347
|
continue;
|
|
1177
1348
|
}
|
|
1178
1349
|
}
|
|
1350
|
+
const prereqEntry = INIT_WIZARD_PLATFORM_REGISTRY.find((e) => e.slug === selectedPlatform);
|
|
1351
|
+
if (prereqEntry?.prereqUrl !== void 0) {
|
|
1352
|
+
const proceed = await promptHostedProxyInstallPrereq(
|
|
1353
|
+
ask,
|
|
1354
|
+
prereqEntry.displayName,
|
|
1355
|
+
prereqEntry.prereqUrl
|
|
1356
|
+
);
|
|
1357
|
+
if (!proceed) {
|
|
1358
|
+
const another2 = await ask("\nConnect another agent? (Y/n) ");
|
|
1359
|
+
if (another2.trim().toLowerCase() === "n") {
|
|
1360
|
+
configuring = false;
|
|
1361
|
+
}
|
|
1362
|
+
continue;
|
|
1363
|
+
}
|
|
1364
|
+
}
|
|
1179
1365
|
const agentName = await promptAgentName(ask, selectedPlatform);
|
|
1180
1366
|
let setupSucceeded = false;
|
|
1181
|
-
if (
|
|
1367
|
+
if (selectedPlatform === "openclaw") {
|
|
1182
1368
|
let detection;
|
|
1183
1369
|
try {
|
|
1184
1370
|
detection = await detectOpenClaw();
|
|
@@ -1258,7 +1444,7 @@ An agent for ${selectedLabel} already exists: ${style.cyan(existingForPlatform.n
|
|
|
1258
1444
|
agentName
|
|
1259
1445
|
});
|
|
1260
1446
|
setupSucceeded = true;
|
|
1261
|
-
} else if (
|
|
1447
|
+
} else if (selectedPlatform === "claude-code") {
|
|
1262
1448
|
process.stderr.write("\nTo connect Claude Code to Shield:\n\n");
|
|
1263
1449
|
process.stderr.write(
|
|
1264
1450
|
" " + style.bold("Step 1") + " - Add the Multicorn marketplace:\n " + style.cyan("claude plugin marketplace add Multicorn-AI/multicorn-shield") + "\n\n"
|
|
@@ -1276,7 +1462,7 @@ An agent for ${selectedLabel} already exists: ${style.cyan(existingForPlatform.n
|
|
|
1276
1462
|
agentName
|
|
1277
1463
|
});
|
|
1278
1464
|
setupSucceeded = true;
|
|
1279
|
-
} else if (
|
|
1465
|
+
} else if (selectedPlatform === "windsurf") {
|
|
1280
1466
|
const windsurfMode = await promptWindsurfIntegrationMode(ask);
|
|
1281
1467
|
if (windsurfMode === "native") {
|
|
1282
1468
|
try {
|
|
@@ -1364,7 +1550,7 @@ An agent for ${selectedLabel} already exists: ${style.cyan(existingForPlatform.n
|
|
|
1364
1550
|
setupSucceeded = true;
|
|
1365
1551
|
}
|
|
1366
1552
|
}
|
|
1367
|
-
} else if (
|
|
1553
|
+
} else if (selectedPlatform === "gemini-cli") {
|
|
1368
1554
|
const geminiMode = await promptGeminiCliIntegrationMode(ask);
|
|
1369
1555
|
if (geminiMode === "native") {
|
|
1370
1556
|
try {
|
|
@@ -1449,7 +1635,7 @@ An agent for ${selectedLabel} already exists: ${style.cyan(existingForPlatform.n
|
|
|
1449
1635
|
setupSucceeded = true;
|
|
1450
1636
|
}
|
|
1451
1637
|
}
|
|
1452
|
-
} else if (
|
|
1638
|
+
} else if (selectedPlatform === "cline") {
|
|
1453
1639
|
const clineMode = await promptClineIntegrationMode(ask);
|
|
1454
1640
|
if (clineMode === "native") {
|
|
1455
1641
|
try {
|
|
@@ -1635,6 +1821,26 @@ An agent for ${selectedLabel} already exists: ${style.cyan(existingForPlatform.n
|
|
|
1635
1821
|
"\n" + style.bold("To complete your Cursor setup:") + "\n 1. If you don't have Cursor yet, download it from " + style.cyan("https://cursor.com/downloads") + "\n 2. Open " + style.cyan("~/.cursor/mcp.json") + " and paste the config snippet shown above\n 3. Restart Cursor (or launch it for the first time) to load the new MCP server\n"
|
|
1636
1822
|
);
|
|
1637
1823
|
}
|
|
1824
|
+
if (configuredPlatforms.has("kilo-code")) {
|
|
1825
|
+
blocks.push(
|
|
1826
|
+
"\n" + style.bold("To complete your Kilo Code setup:") + "\n 1. Save the snippet to " + style.cyan(".kilocode/mcp.json") + " in your project root, or under the mcp key in " + style.cyan("kilo.jsonc") + "\n 2. Run your next task in Kilo Code so it picks up the MCP server\n"
|
|
1827
|
+
);
|
|
1828
|
+
}
|
|
1829
|
+
if (configuredPlatforms.has("github-copilot")) {
|
|
1830
|
+
blocks.push(
|
|
1831
|
+
"\n" + style.bold("GitHub Copilot MCP:") + "\n 1. Open VS Code Command Palette: Preferences: Open User Settings (JSON)\n 2. Merge the snippet under the " + style.cyan("mcp") + " key and save\n 3. Use Copilot Agent mode and verify the MCP server connects\n"
|
|
1832
|
+
);
|
|
1833
|
+
}
|
|
1834
|
+
if (configuredPlatforms.has("continue-dev")) {
|
|
1835
|
+
blocks.push(
|
|
1836
|
+
"\n" + style.bold("Continue MCP:") + "\n 1. If you don't have Continue yet, install from " + style.cyan("https://docs.continue.dev/ide-extensions/install") + "\n 2. Save JSON as " + style.cyan(".continue/mcpServers/shield.json") + " in your workspace, or add to " + style.cyan("~/.continue/config.yaml") + "\n 3. Reload VS Code and open Continue agent mode\n"
|
|
1837
|
+
);
|
|
1838
|
+
}
|
|
1839
|
+
if (configuredPlatforms.has("goose")) {
|
|
1840
|
+
blocks.push(
|
|
1841
|
+
"\n" + style.bold("Goose MCP extension:") + "\n 1. Edit " + style.cyan("~/.config/goose/config.yaml") + " (or use goose configure)\n 2. Restart Goose CLI or Desktop\n"
|
|
1842
|
+
);
|
|
1843
|
+
}
|
|
1638
1844
|
const windsurfNativeConfigured = configuredAgents.some(
|
|
1639
1845
|
(a) => a.platform === "windsurf" && a.windsurfIntegration === "native"
|
|
1640
1846
|
);
|
package/dist/shield-extension.js
CHANGED
|
@@ -22259,6 +22259,69 @@ function getClaudeDesktopConfigPath() {
|
|
|
22259
22259
|
);
|
|
22260
22260
|
}
|
|
22261
22261
|
}
|
|
22262
|
+
var INIT_WIZARD_PLATFORM_REGISTRY = [
|
|
22263
|
+
{ slug: "openclaw", displayName: "OpenClaw", section: "native", detectable: true },
|
|
22264
|
+
{ slug: "claude-code", displayName: "Claude Code", section: "native", detectable: true },
|
|
22265
|
+
{ slug: "windsurf", displayName: "Windsurf", section: "native", detectable: true },
|
|
22266
|
+
{ slug: "cline", displayName: "Cline", section: "native", detectable: false },
|
|
22267
|
+
{ slug: "gemini-cli", displayName: "Gemini CLI", section: "native", detectable: false },
|
|
22268
|
+
{
|
|
22269
|
+
slug: "cursor",
|
|
22270
|
+
displayName: "Cursor",
|
|
22271
|
+
section: "hosted",
|
|
22272
|
+
prereqUrl: "https://www.cursor.com/downloads",
|
|
22273
|
+
detectable: true
|
|
22274
|
+
},
|
|
22275
|
+
{
|
|
22276
|
+
slug: "claude-desktop",
|
|
22277
|
+
displayName: "Claude Desktop",
|
|
22278
|
+
section: "hosted",
|
|
22279
|
+
prereqUrl: "https://claude.ai/download",
|
|
22280
|
+
detectable: false
|
|
22281
|
+
},
|
|
22282
|
+
{
|
|
22283
|
+
slug: "github-copilot",
|
|
22284
|
+
displayName: "GitHub Copilot",
|
|
22285
|
+
section: "hosted",
|
|
22286
|
+
prereqUrl: "https://docs.github.com/en/copilot/get-started",
|
|
22287
|
+
detectable: false
|
|
22288
|
+
},
|
|
22289
|
+
{
|
|
22290
|
+
slug: "kilo-code",
|
|
22291
|
+
displayName: "Kilo Code",
|
|
22292
|
+
section: "hosted",
|
|
22293
|
+
prereqUrl: "https://kilocode.ai/docs/getting-started",
|
|
22294
|
+
detectable: false
|
|
22295
|
+
},
|
|
22296
|
+
{
|
|
22297
|
+
slug: "continue-dev",
|
|
22298
|
+
displayName: "Continue",
|
|
22299
|
+
section: "hosted",
|
|
22300
|
+
prereqUrl: "https://docs.continue.dev/ide-extensions/install",
|
|
22301
|
+
detectable: false
|
|
22302
|
+
},
|
|
22303
|
+
{
|
|
22304
|
+
slug: "goose",
|
|
22305
|
+
displayName: "Goose",
|
|
22306
|
+
section: "hosted",
|
|
22307
|
+
prereqUrl: "https://goose-docs.ai/docs/quickstart/",
|
|
22308
|
+
detectable: false
|
|
22309
|
+
},
|
|
22310
|
+
{ slug: "other-mcp", displayName: "Local MCP / Other", section: "hosted", detectable: false }
|
|
22311
|
+
];
|
|
22312
|
+
(() => {
|
|
22313
|
+
const itemsFor = (section) => INIT_WIZARD_PLATFORM_REGISTRY.filter((e) => e.section === section).map((e) => ({
|
|
22314
|
+
platform: e.slug,
|
|
22315
|
+
label: e.displayName
|
|
22316
|
+
}));
|
|
22317
|
+
return [
|
|
22318
|
+
{ title: "Recommended (native plugin)", items: itemsFor("native") },
|
|
22319
|
+
{ title: "Hosted proxy (MCP only)", items: itemsFor("hosted") }
|
|
22320
|
+
];
|
|
22321
|
+
})();
|
|
22322
|
+
Object.fromEntries(
|
|
22323
|
+
INIT_WIZARD_PLATFORM_REGISTRY.map((e, i) => [i + 1, e.slug])
|
|
22324
|
+
);
|
|
22262
22325
|
|
|
22263
22326
|
// src/extension/config-reader.ts
|
|
22264
22327
|
var EXTENSION_BACKUP_FILENAME = "extension-backup.json";
|
|
@@ -22359,7 +22422,7 @@ async function writeExtensionBackup(claudeDesktopConfigPath, mcpServers) {
|
|
|
22359
22422
|
|
|
22360
22423
|
// package.json
|
|
22361
22424
|
var package_default = {
|
|
22362
|
-
version: "1.
|
|
22425
|
+
version: "1.1.0"};
|
|
22363
22426
|
|
|
22364
22427
|
// src/package-meta.ts
|
|
22365
22428
|
var PACKAGE_VERSION = package_default.version;
|
package/package.json
CHANGED