multicorn-shield 1.11.1 → 1.12.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 +24 -0
- package/README.md +10 -2
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/dist/multicorn-proxy.js +250 -201
- package/dist/multicorn-shield.js +246 -199
- package/dist/openclaw-hook/HOOK.md +5 -3
- package/dist/openclaw-hook/handler.js +1 -1
- package/dist/openclaw-plugin/multicorn-shield.js +28 -7
- package/dist/openclaw-plugin/openclaw.plugin.json +1 -1
- package/dist/shield-extension.js +3 -12
- package/package.json +4 -2
- package/plugins/windsurf/hooks/scripts/pre-action.cjs +126 -17
package/dist/multicorn-shield.js
CHANGED
|
@@ -658,7 +658,35 @@ function isVersionAtLeast(version, minimum) {
|
|
|
658
658
|
}
|
|
659
659
|
return true;
|
|
660
660
|
}
|
|
661
|
-
|
|
661
|
+
var OPENCLAW_SHIELD_API_KEY_ENV_REF = "${MULTICORN_API_KEY}";
|
|
662
|
+
function buildOpenClawShieldPluginConfig(params) {
|
|
663
|
+
return {
|
|
664
|
+
apiKey: OPENCLAW_SHIELD_API_KEY_ENV_REF,
|
|
665
|
+
baseUrl: params.baseUrl,
|
|
666
|
+
agentName: params.agentName,
|
|
667
|
+
failMode: "closed"
|
|
668
|
+
};
|
|
669
|
+
}
|
|
670
|
+
function detectStaleOpenClawHookIntegration(openclawConfig) {
|
|
671
|
+
const hooks = openclawConfig["hooks"];
|
|
672
|
+
if (typeof hooks !== "object" || hooks === null) return false;
|
|
673
|
+
const internal = hooks["internal"];
|
|
674
|
+
if (typeof internal !== "object" || internal === null) return false;
|
|
675
|
+
const entries = internal["entries"];
|
|
676
|
+
if (typeof entries !== "object" || entries === null) return false;
|
|
677
|
+
return Object.prototype.hasOwnProperty.call(entries, "multicorn-shield");
|
|
678
|
+
}
|
|
679
|
+
function staleOpenClawHookIntegrationMessage() {
|
|
680
|
+
return "Deprecated OpenClaw gateway hook config detected at hooks.internal.entries.multicorn-shield. Shield now uses the multicorn-shield plugin under plugins.entries. Disable the old hook manually (for example openclaw hooks disable multicorn-shield) and remove hooks.internal.entries.multicorn-shield when you are ready.";
|
|
681
|
+
}
|
|
682
|
+
function stripLegacyOpenClawShieldEntryFields(shield) {
|
|
683
|
+
delete shield["env"];
|
|
684
|
+
delete shield["apiKey"];
|
|
685
|
+
delete shield["baseUrl"];
|
|
686
|
+
delete shield["agentName"];
|
|
687
|
+
delete shield["failMode"];
|
|
688
|
+
}
|
|
689
|
+
async function updateOpenClawConfigIfPresent(_apiKey, baseUrl, agentName) {
|
|
662
690
|
let raw;
|
|
663
691
|
try {
|
|
664
692
|
raw = await readFile(OPENCLAW_CONFIG_PATH, "utf8");
|
|
@@ -674,49 +702,66 @@ async function updateOpenClawConfigIfPresent(apiKey, baseUrl, agentName) {
|
|
|
674
702
|
} catch {
|
|
675
703
|
return "parse-error";
|
|
676
704
|
}
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
705
|
+
if (detectStaleOpenClawHookIntegration(obj)) {
|
|
706
|
+
process.stderr.write(
|
|
707
|
+
style.yellow("\u26A0") + " " + staleOpenClawHookIntegrationMessage() + "\n"
|
|
708
|
+
);
|
|
681
709
|
}
|
|
682
|
-
let
|
|
683
|
-
if (
|
|
684
|
-
|
|
685
|
-
|
|
710
|
+
let plugins = obj["plugins"];
|
|
711
|
+
if (plugins === void 0 || typeof plugins !== "object") {
|
|
712
|
+
plugins = {};
|
|
713
|
+
obj["plugins"] = plugins;
|
|
686
714
|
}
|
|
687
|
-
let
|
|
688
|
-
if (
|
|
689
|
-
|
|
690
|
-
|
|
715
|
+
let pluginEntries = plugins["entries"];
|
|
716
|
+
if (pluginEntries === void 0 || typeof pluginEntries !== "object") {
|
|
717
|
+
pluginEntries = {};
|
|
718
|
+
plugins["entries"] = pluginEntries;
|
|
691
719
|
}
|
|
692
|
-
let shield =
|
|
720
|
+
let shield = pluginEntries["multicorn-shield"];
|
|
693
721
|
if (shield === void 0 || typeof shield !== "object") {
|
|
694
|
-
shield = { enabled: true
|
|
695
|
-
|
|
696
|
-
}
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
shield["
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
env["MULTICORN_AGENT_NAME"] = agentName;
|
|
722
|
+
shield = { enabled: true };
|
|
723
|
+
pluginEntries["multicorn-shield"] = shield;
|
|
724
|
+
}
|
|
725
|
+
stripLegacyOpenClawShieldEntryFields(shield);
|
|
726
|
+
const resolvedAgentName = agentName ?? (typeof shield["config"] === "object" && shield["config"] !== null && typeof shield["config"]["agentName"] === "string" ? String(shield["config"]["agentName"]) : void 0);
|
|
727
|
+
if (resolvedAgentName !== void 0) {
|
|
728
|
+
shield["enabled"] = true;
|
|
729
|
+
shield["config"] = buildOpenClawShieldPluginConfig({
|
|
730
|
+
baseUrl,
|
|
731
|
+
agentName: resolvedAgentName
|
|
732
|
+
});
|
|
706
733
|
const agentsList = obj["agents"];
|
|
707
734
|
const list = agentsList?.["list"];
|
|
708
735
|
if (Array.isArray(list) && list.length > 0) {
|
|
709
736
|
const first = list[0];
|
|
710
|
-
if (first["id"] !==
|
|
711
|
-
first["id"] =
|
|
712
|
-
first["name"] =
|
|
737
|
+
if (first["id"] !== resolvedAgentName) {
|
|
738
|
+
first["id"] = resolvedAgentName;
|
|
739
|
+
first["name"] = resolvedAgentName;
|
|
713
740
|
}
|
|
714
741
|
} else {
|
|
715
742
|
if (agentsList !== void 0 && typeof agentsList === "object") {
|
|
716
|
-
agentsList["list"] = [{ id:
|
|
743
|
+
agentsList["list"] = [{ id: resolvedAgentName, name: resolvedAgentName }];
|
|
717
744
|
} else {
|
|
718
|
-
obj["agents"] = { list: [{ id:
|
|
745
|
+
obj["agents"] = { list: [{ id: resolvedAgentName, name: resolvedAgentName }] };
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
} else {
|
|
749
|
+
shield["enabled"] = true;
|
|
750
|
+
const existingConfig = shield["config"];
|
|
751
|
+
if (typeof existingConfig === "object" && existingConfig !== null) {
|
|
752
|
+
const cfg = { ...existingConfig };
|
|
753
|
+
cfg["apiKey"] = OPENCLAW_SHIELD_API_KEY_ENV_REF;
|
|
754
|
+
cfg["baseUrl"] = baseUrl;
|
|
755
|
+
if (cfg["failMode"] !== "open" && cfg["failMode"] !== "closed") {
|
|
756
|
+
cfg["failMode"] = "closed";
|
|
719
757
|
}
|
|
758
|
+
shield["config"] = cfg;
|
|
759
|
+
} else {
|
|
760
|
+
shield["config"] = {
|
|
761
|
+
apiKey: OPENCLAW_SHIELD_API_KEY_ENV_REF,
|
|
762
|
+
baseUrl,
|
|
763
|
+
failMode: "closed"
|
|
764
|
+
};
|
|
720
765
|
}
|
|
721
766
|
}
|
|
722
767
|
await writeFile(
|
|
@@ -726,6 +771,10 @@ async function updateOpenClawConfigIfPresent(apiKey, baseUrl, agentName) {
|
|
|
726
771
|
);
|
|
727
772
|
return "updated";
|
|
728
773
|
}
|
|
774
|
+
function isPastedShieldApiKeyInput(input) {
|
|
775
|
+
const trimmed = input.trim();
|
|
776
|
+
return trimmed.startsWith("mcs_") && trimmed.length >= 8;
|
|
777
|
+
}
|
|
729
778
|
async function validateApiKey(apiKey, baseUrl) {
|
|
730
779
|
try {
|
|
731
780
|
const response = await fetch(`${baseUrl}/api/v1/agents`, {
|
|
@@ -1095,40 +1144,6 @@ async function installCodexCliNativeHooks() {
|
|
|
1095
1144
|
};
|
|
1096
1145
|
await writeFile(getCodexHooksJsonPath(), JSON.stringify(hooksConfig, null, 2) + "\n", "utf8");
|
|
1097
1146
|
}
|
|
1098
|
-
async function promptCodexCliIntegrationMode(ask) {
|
|
1099
|
-
process.stderr.write("\n" + style.bold("Codex CLI integration") + "\n");
|
|
1100
|
-
process.stderr.write(
|
|
1101
|
-
" " + style.violet("1") + ". Native plugin - Shield checks terminal (Bash) commands via Codex Hooks\n"
|
|
1102
|
-
);
|
|
1103
|
-
process.stderr.write(
|
|
1104
|
-
" " + style.violet("2") + ". Hosted proxy - govern MCP server traffic via config.toml\n"
|
|
1105
|
-
);
|
|
1106
|
-
let choice = 0;
|
|
1107
|
-
while (choice === 0) {
|
|
1108
|
-
const input = await ask("Choose integration (1-2): ");
|
|
1109
|
-
const num = parseInt(input.trim(), 10);
|
|
1110
|
-
if (num === 1) choice = 1;
|
|
1111
|
-
if (num === 2) choice = 2;
|
|
1112
|
-
}
|
|
1113
|
-
return choice === 1 ? "native" : "hosted";
|
|
1114
|
-
}
|
|
1115
|
-
async function promptClineIntegrationMode(ask) {
|
|
1116
|
-
process.stderr.write("\n" + style.bold("Cline integration") + "\n");
|
|
1117
|
-
process.stderr.write(
|
|
1118
|
-
" " + style.violet("1") + ". Native plugin (recommended) - Cline Hooks see every file, terminal, browser, and MCP action\n"
|
|
1119
|
-
);
|
|
1120
|
-
process.stderr.write(
|
|
1121
|
-
" " + style.violet("2") + ". Hosted proxy - govern MCP traffic only (paste proxy URL into Cline MCP settings)\n"
|
|
1122
|
-
);
|
|
1123
|
-
let choice = 0;
|
|
1124
|
-
while (choice === 0) {
|
|
1125
|
-
const input = await ask("Choose integration (1-2): ");
|
|
1126
|
-
const num = parseInt(input.trim(), 10);
|
|
1127
|
-
if (num === 1) choice = 1;
|
|
1128
|
-
if (num === 2) choice = 2;
|
|
1129
|
-
}
|
|
1130
|
-
return choice === 1 ? "native" : "hosted";
|
|
1131
|
-
}
|
|
1132
1147
|
function getGeminiCliHooksInstallDir() {
|
|
1133
1148
|
return join(homedir(), ".multicorn", "gemini-cli-hooks");
|
|
1134
1149
|
}
|
|
@@ -1454,40 +1469,6 @@ async function installGeminiCliNativeHooks(ask) {
|
|
|
1454
1469
|
await mkdir(dirname(settingsPath), { recursive: true });
|
|
1455
1470
|
await writeFile(settingsPath, JSON.stringify(existing, null, 2) + "\n", SECRET_JSON_FILE_OPTIONS);
|
|
1456
1471
|
}
|
|
1457
|
-
async function promptGeminiCliIntegrationMode(ask) {
|
|
1458
|
-
process.stderr.write("\n" + style.bold("Gemini CLI integration") + "\n");
|
|
1459
|
-
process.stderr.write(
|
|
1460
|
-
" " + style.violet("1") + ". Native plugin (recommended) - Gemini CLI Hooks see every file, terminal, web, and MCP action\n"
|
|
1461
|
-
);
|
|
1462
|
-
process.stderr.write(
|
|
1463
|
-
" " + style.violet("2") + ". Hosted proxy - govern MCP traffic only (paste proxy URL into Gemini CLI settings)\n"
|
|
1464
|
-
);
|
|
1465
|
-
let choice = 0;
|
|
1466
|
-
while (choice === 0) {
|
|
1467
|
-
const input = await ask("Choose integration (1-2): ");
|
|
1468
|
-
const num = parseInt(input.trim(), 10);
|
|
1469
|
-
if (num === 1) choice = 1;
|
|
1470
|
-
if (num === 2) choice = 2;
|
|
1471
|
-
}
|
|
1472
|
-
return choice === 1 ? "native" : "hosted";
|
|
1473
|
-
}
|
|
1474
|
-
async function promptOpencodeIntegrationMode(ask) {
|
|
1475
|
-
process.stderr.write("\n" + style.bold("OpenCode integration") + "\n");
|
|
1476
|
-
process.stderr.write(
|
|
1477
|
-
" " + style.violet("1") + ". Native plugin (recommended) - Shield checks primary-agent tool execution via OpenCode Hooks\n"
|
|
1478
|
-
);
|
|
1479
|
-
process.stderr.write(
|
|
1480
|
-
" " + style.violet("2") + ". Hosted proxy - govern MCP server traffic via opencode.json (full subagent coverage when tools use MCP through Shield)\n"
|
|
1481
|
-
);
|
|
1482
|
-
let choice = 0;
|
|
1483
|
-
while (choice === 0) {
|
|
1484
|
-
const input = await ask("Choose integration (1-2): ");
|
|
1485
|
-
const num = parseInt(input.trim(), 10);
|
|
1486
|
-
if (num === 1) choice = 1;
|
|
1487
|
-
if (num === 2) choice = 2;
|
|
1488
|
-
}
|
|
1489
|
-
return choice === 1 ? "native" : "hosted";
|
|
1490
|
-
}
|
|
1491
1472
|
function getClaudeDesktopConfigPath() {
|
|
1492
1473
|
switch (process.platform) {
|
|
1493
1474
|
case "win32":
|
|
@@ -1607,27 +1588,22 @@ var INIT_WIZARD_PLATFORM_REGISTRY = [
|
|
|
1607
1588
|
},
|
|
1608
1589
|
{ slug: "other-mcp", displayName: "Local MCP / Other", section: "hosted" }
|
|
1609
1590
|
];
|
|
1610
|
-
var
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
{ title: "Recommended (native plugin)", items: itemsFor("native") },
|
|
1617
|
-
{ title: "Hosted proxy (MCP only)", items: itemsFor("hosted") }
|
|
1618
|
-
];
|
|
1619
|
-
})();
|
|
1620
|
-
var INIT_WIZARD_SELECTION_MAX = INIT_WIZARD_PLATFORM_REGISTRY.length;
|
|
1591
|
+
var INIT_WIZARD_PICKER_NATIVE_SLUGS = INIT_WIZARD_PLATFORM_REGISTRY.filter((e) => e.section === "native").map((e) => e.slug);
|
|
1592
|
+
var INIT_WIZARD_DASHBOARD_AGENTS_URL = "https://app.multicorn.ai/agents/new";
|
|
1593
|
+
var INIT_WIZARD_PICKER_SELECTION_MAX = INIT_WIZARD_PICKER_NATIVE_SLUGS.length;
|
|
1594
|
+
var PICKER_SLUG_BY_SELECTION = Object.fromEntries(
|
|
1595
|
+
INIT_WIZARD_PICKER_NATIVE_SLUGS.map((slug, i) => [i + 1, slug])
|
|
1596
|
+
);
|
|
1621
1597
|
var INIT_EXISTING_AGENTS_PLATFORM_ACTIONS = [
|
|
1622
1598
|
"Add a new agent alongside these",
|
|
1623
1599
|
"Replace an existing agent",
|
|
1624
1600
|
"Skip - choose a different platform"
|
|
1625
1601
|
];
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
function
|
|
1630
|
-
const slug =
|
|
1602
|
+
function resolveInitHybridIntegrationMode(explicit) {
|
|
1603
|
+
return explicit ?? "native";
|
|
1604
|
+
}
|
|
1605
|
+
function platformMenuLabelForPickerSelection(sel) {
|
|
1606
|
+
const slug = PICKER_SLUG_BY_SELECTION[sel];
|
|
1631
1607
|
if (slug === void 0) return "Unknown";
|
|
1632
1608
|
const entry = INIT_WIZARD_PLATFORM_REGISTRY.find((e) => e.slug === slug);
|
|
1633
1609
|
return entry?.displayName ?? slug;
|
|
@@ -1645,48 +1621,31 @@ async function promptPlatformSelection(ask) {
|
|
|
1645
1621
|
process.stderr.write(
|
|
1646
1622
|
"\n" + style.bold(style.violet("Which platform are you connecting?")) + "\n\n"
|
|
1647
1623
|
);
|
|
1624
|
+
process.stderr.write(" " + style.dim("Native plugin (files, terminal, browser)") + "\n");
|
|
1648
1625
|
let optionNum = 1;
|
|
1649
|
-
for (const
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1626
|
+
for (const slug of INIT_WIZARD_PICKER_NATIVE_SLUGS) {
|
|
1627
|
+
const entry = INIT_WIZARD_PLATFORM_REGISTRY.find((e) => e.slug === slug);
|
|
1628
|
+
const label = entry?.displayName ?? slug;
|
|
1629
|
+
const indent = optionNum >= 10 ? " " : " ";
|
|
1630
|
+
process.stderr.write(`${indent}${style.violet(String(optionNum))}. ${label}
|
|
1654
1631
|
`);
|
|
1655
|
-
|
|
1656
|
-
}
|
|
1632
|
+
optionNum++;
|
|
1657
1633
|
}
|
|
1658
|
-
process.stderr.write(
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1634
|
+
process.stderr.write("\n");
|
|
1635
|
+
process.stderr.write(" MCP agents (Cursor, Copilot, others) are set up\n");
|
|
1636
|
+
process.stderr.write(` in the dashboard: ${INIT_WIZARD_DASHBOARD_AGENTS_URL}
|
|
1637
|
+
|
|
1638
|
+
`);
|
|
1663
1639
|
let selection = 0;
|
|
1664
1640
|
while (selection === 0) {
|
|
1665
|
-
const input = await ask(`Select (1-${String(
|
|
1641
|
+
const input = await ask(`Select (1-${String(INIT_WIZARD_PICKER_SELECTION_MAX)}): `);
|
|
1666
1642
|
const num = parseInt(input.trim(), 10);
|
|
1667
|
-
if (num >= 1 && num <=
|
|
1643
|
+
if (num >= 1 && num <= INIT_WIZARD_PICKER_SELECTION_MAX) {
|
|
1668
1644
|
selection = num;
|
|
1669
1645
|
}
|
|
1670
1646
|
}
|
|
1671
1647
|
return selection;
|
|
1672
1648
|
}
|
|
1673
|
-
async function promptWindsurfIntegrationMode(ask) {
|
|
1674
|
-
process.stderr.write("\n" + style.bold("Windsurf integration") + "\n");
|
|
1675
|
-
process.stderr.write(
|
|
1676
|
-
" " + style.violet("1") + ". Native plugin (recommended) - Cascade Hooks see every file, terminal, and MCP action\n"
|
|
1677
|
-
);
|
|
1678
|
-
process.stderr.write(
|
|
1679
|
-
" " + style.violet("2") + ". Hosted proxy - govern MCP traffic only (paste proxy URL into mcp_config)\n"
|
|
1680
|
-
);
|
|
1681
|
-
let choice = 0;
|
|
1682
|
-
while (choice === 0) {
|
|
1683
|
-
const input = await ask("Choose integration (1-2): ");
|
|
1684
|
-
const num = parseInt(input.trim(), 10);
|
|
1685
|
-
if (num === 1) choice = 1;
|
|
1686
|
-
if (num === 2) choice = 2;
|
|
1687
|
-
}
|
|
1688
|
-
return choice === 1 ? "native" : "hosted";
|
|
1689
|
-
}
|
|
1690
1649
|
async function arrowSelect(options, ask, fallbackLabel) {
|
|
1691
1650
|
if (options.length === 1) {
|
|
1692
1651
|
const only = options[0] ?? "";
|
|
@@ -1899,6 +1858,14 @@ var HOSTED_PROXY_PLATFORMS_WITH_URL_KEY = /* @__PURE__ */ new Set([
|
|
|
1899
1858
|
function shouldEmbedKeyInHostedProxyUrl(platform) {
|
|
1900
1859
|
return HOSTED_PROXY_PLATFORMS_WITH_URL_KEY.has(platform);
|
|
1901
1860
|
}
|
|
1861
|
+
function buildClineHostedMcpEntry(url) {
|
|
1862
|
+
return {
|
|
1863
|
+
type: "streamableHttp",
|
|
1864
|
+
url,
|
|
1865
|
+
timeout: 60,
|
|
1866
|
+
disabled: false
|
|
1867
|
+
};
|
|
1868
|
+
}
|
|
1902
1869
|
function hostedProxyUrlWithKeyParam(proxyUrl, apiKey) {
|
|
1903
1870
|
if (apiKey.length === 0) {
|
|
1904
1871
|
process.stderr.write(
|
|
@@ -2303,9 +2270,11 @@ async function applyHostedProxyMcpConfig(platform, proxyUrl, shortName, apiKey,
|
|
|
2303
2270
|
printHostedProxyJsonParseWarning(getWindsurfMcpConfigPath());
|
|
2304
2271
|
}
|
|
2305
2272
|
} else if (platform === "cline") {
|
|
2306
|
-
result = await mergeMcpServersObjectStyle(
|
|
2307
|
-
|
|
2308
|
-
|
|
2273
|
+
result = await mergeMcpServersObjectStyle(
|
|
2274
|
+
getClineMcpSettingsPath(),
|
|
2275
|
+
shortName,
|
|
2276
|
+
buildClineHostedMcpEntry(proxyUrlWithKeyWhenNeeded)
|
|
2277
|
+
);
|
|
2309
2278
|
if (result === "parse-error") {
|
|
2310
2279
|
printHostedProxyJsonParseWarning(getClineMcpSettingsPath());
|
|
2311
2280
|
}
|
|
@@ -2595,9 +2564,7 @@ Authorization = "Bearer ${bearerToken}"
|
|
|
2595
2564
|
snippetText = platform === "cline" ? JSON.stringify(
|
|
2596
2565
|
{
|
|
2597
2566
|
mcpServers: {
|
|
2598
|
-
[shortName]:
|
|
2599
|
-
[urlKey]: urlInSnippet
|
|
2600
|
-
}
|
|
2567
|
+
[shortName]: buildClineHostedMcpEntry(urlInSnippet)
|
|
2601
2568
|
}
|
|
2602
2569
|
},
|
|
2603
2570
|
null,
|
|
@@ -2761,6 +2728,7 @@ function mergeAgentsForPlatform(localAgents, remoteAgents, selectedPlatform) {
|
|
|
2761
2728
|
var DEFAULT_SHIELD_API_BASE_URL = "https://api.multicorn.ai";
|
|
2762
2729
|
async function runInit(explicitBaseUrl, options) {
|
|
2763
2730
|
const verbose = options?.verbose === true;
|
|
2731
|
+
const hybridIntegration = resolveInitHybridIntegrationMode(options?.integration);
|
|
2764
2732
|
if (!process.stdin.isTTY) {
|
|
2765
2733
|
process.stderr.write(
|
|
2766
2734
|
style.red("Error: interactive terminal required. Cannot run init with piped input.") + "\n"
|
|
@@ -2805,9 +2773,31 @@ async function runInit(explicitBaseUrl, options) {
|
|
|
2805
2773
|
if (existing !== null && existing.apiKey.startsWith("mcs_") && existing.apiKey.length >= 8) {
|
|
2806
2774
|
const masked = "mcs_..." + existing.apiKey.slice(-4);
|
|
2807
2775
|
process.stderr.write("Found existing API key: " + style.cyan(masked) + "\n");
|
|
2808
|
-
const answer = await ask("Use this key? (Y/n) ");
|
|
2809
|
-
|
|
2810
|
-
|
|
2776
|
+
const answer = await ask("Use this key? (Y/n, or paste a new mcs_ key) ");
|
|
2777
|
+
const trimmed = answer.trim();
|
|
2778
|
+
if (trimmed.toLowerCase() !== "n") {
|
|
2779
|
+
const candidate = isPastedShieldApiKeyInput(trimmed) ? trimmed : existing.apiKey;
|
|
2780
|
+
const spinner = withSpinner("Validating key...");
|
|
2781
|
+
let reuseResult;
|
|
2782
|
+
try {
|
|
2783
|
+
reuseResult = await validateApiKey(candidate, resolvedBaseUrl);
|
|
2784
|
+
} catch (error) {
|
|
2785
|
+
spinner.stop(false, "Validation failed");
|
|
2786
|
+
throw error;
|
|
2787
|
+
}
|
|
2788
|
+
if (reuseResult.valid) {
|
|
2789
|
+
spinner.stop(true, "Key validated");
|
|
2790
|
+
apiKey = candidate;
|
|
2791
|
+
} else {
|
|
2792
|
+
spinner.stop(false, reuseResult.error ?? "Validation failed.");
|
|
2793
|
+
if (isPastedShieldApiKeyInput(trimmed)) {
|
|
2794
|
+
process.stderr.write(style.red("That key was rejected. Enter a new key below.") + "\n");
|
|
2795
|
+
} else {
|
|
2796
|
+
process.stderr.write(
|
|
2797
|
+
style.yellow("Existing key is no longer valid. Enter a new key below.") + "\n"
|
|
2798
|
+
);
|
|
2799
|
+
}
|
|
2800
|
+
}
|
|
2811
2801
|
}
|
|
2812
2802
|
}
|
|
2813
2803
|
if (apiKey.length === 0) {
|
|
@@ -2859,8 +2849,8 @@ async function runInit(explicitBaseUrl, options) {
|
|
|
2859
2849
|
let removeAgentNameBeforeSave = void 0;
|
|
2860
2850
|
const initWorkspacePath = resolve(process.cwd());
|
|
2861
2851
|
const selection = await promptPlatformSelection(ask);
|
|
2862
|
-
const selectedPlatform =
|
|
2863
|
-
const selectedLabel =
|
|
2852
|
+
const selectedPlatform = PICKER_SLUG_BY_SELECTION[selection] ?? "openclaw";
|
|
2853
|
+
const selectedLabel = platformMenuLabelForPickerSelection(selection);
|
|
2864
2854
|
if (selectedPlatform === "other-mcp") {
|
|
2865
2855
|
const raw = existing !== null ? { ...existing } : {};
|
|
2866
2856
|
raw["apiKey"] = apiKey;
|
|
@@ -2994,7 +2984,7 @@ You have ${String(agentsForPlatform.length)} agent(s) connected for ${selectedLa
|
|
|
2994
2984
|
}
|
|
2995
2985
|
if (detection.status === "parse-error") {
|
|
2996
2986
|
process.stderr.write(
|
|
2997
|
-
style.red("\u2717") + " Could not update OpenClaw config. Set
|
|
2987
|
+
style.red("\u2717") + " Could not update OpenClaw config. Set plugins.entries.multicorn-shield.config.apiKey in ~/.openclaw/openclaw.json, or run npx multicorn-shield init.\n"
|
|
2998
2988
|
);
|
|
2999
2989
|
}
|
|
3000
2990
|
if (detection.status === "detected") {
|
|
@@ -3034,7 +3024,7 @@ You have ${String(agentsForPlatform.length)} agent(s) connected for ${selectedLa
|
|
|
3034
3024
|
if (result === "parse-error") {
|
|
3035
3025
|
spinner.stop(
|
|
3036
3026
|
false,
|
|
3037
|
-
"Could not update OpenClaw config. Set
|
|
3027
|
+
"Could not update OpenClaw config. Set plugins.entries.multicorn-shield.config.apiKey in ~/.openclaw/openclaw.json, or run npx multicorn-shield init."
|
|
3038
3028
|
);
|
|
3039
3029
|
} else {
|
|
3040
3030
|
spinner.stop(
|
|
@@ -3081,7 +3071,7 @@ You have ${String(agentsForPlatform.length)} agent(s) connected for ${selectedLa
|
|
|
3081
3071
|
});
|
|
3082
3072
|
setupSucceeded = true;
|
|
3083
3073
|
} else if (selectedPlatform === "windsurf") {
|
|
3084
|
-
const windsurfMode =
|
|
3074
|
+
const windsurfMode = hybridIntegration;
|
|
3085
3075
|
if (windsurfMode === "native") {
|
|
3086
3076
|
try {
|
|
3087
3077
|
await installWindsurfNativeHooks();
|
|
@@ -3180,7 +3170,7 @@ You have ${String(agentsForPlatform.length)} agent(s) connected for ${selectedLa
|
|
|
3180
3170
|
}
|
|
3181
3171
|
}
|
|
3182
3172
|
} else if (selectedPlatform === "gemini-cli") {
|
|
3183
|
-
const geminiMode =
|
|
3173
|
+
const geminiMode = hybridIntegration;
|
|
3184
3174
|
if (geminiMode === "native") {
|
|
3185
3175
|
try {
|
|
3186
3176
|
await installGeminiCliNativeHooks(ask);
|
|
@@ -3274,7 +3264,7 @@ You have ${String(agentsForPlatform.length)} agent(s) connected for ${selectedLa
|
|
|
3274
3264
|
}
|
|
3275
3265
|
}
|
|
3276
3266
|
} else if (selectedPlatform === "opencode") {
|
|
3277
|
-
const opencodeMode =
|
|
3267
|
+
const opencodeMode = hybridIntegration;
|
|
3278
3268
|
if (opencodeMode === "native") {
|
|
3279
3269
|
try {
|
|
3280
3270
|
await installOpenCodeNativePlugin();
|
|
@@ -3363,7 +3353,7 @@ You have ${String(agentsForPlatform.length)} agent(s) connected for ${selectedLa
|
|
|
3363
3353
|
}
|
|
3364
3354
|
}
|
|
3365
3355
|
} else if (selectedPlatform === "codex-cli") {
|
|
3366
|
-
const codexMode =
|
|
3356
|
+
const codexMode = hybridIntegration;
|
|
3367
3357
|
if (codexMode === "native") {
|
|
3368
3358
|
try {
|
|
3369
3359
|
await installCodexCliNativeHooks();
|
|
@@ -3452,7 +3442,7 @@ You have ${String(agentsForPlatform.length)} agent(s) connected for ${selectedLa
|
|
|
3452
3442
|
}
|
|
3453
3443
|
}
|
|
3454
3444
|
} else if (selectedPlatform === "cline") {
|
|
3455
|
-
const clineMode =
|
|
3445
|
+
const clineMode = hybridIntegration;
|
|
3456
3446
|
if (clineMode === "native") {
|
|
3457
3447
|
try {
|
|
3458
3448
|
await installClineNativeHooks();
|
|
@@ -3935,9 +3925,7 @@ async function writeLocalMcpEntry(client, agentName, localProxyUrl, apiKey, work
|
|
|
3935
3925
|
return await mergeMcpServersObjectStyle(
|
|
3936
3926
|
filePath,
|
|
3937
3927
|
entryKey,
|
|
3938
|
-
|
|
3939
|
-
url
|
|
3940
|
-
},
|
|
3928
|
+
buildClineHostedMcpEntry(url),
|
|
3941
3929
|
legacyKeys
|
|
3942
3930
|
) === "ok" ? filePath : null;
|
|
3943
3931
|
case "windsurf":
|
|
@@ -4985,7 +4973,7 @@ async function restoreClaudeDesktopMcpFromBackup() {
|
|
|
4985
4973
|
|
|
4986
4974
|
// package.json
|
|
4987
4975
|
var package_default = {
|
|
4988
|
-
version: "1.
|
|
4976
|
+
version: "1.12.0"};
|
|
4989
4977
|
|
|
4990
4978
|
// src/package-meta.ts
|
|
4991
4979
|
var PACKAGE_VERSION = package_default.version;
|
|
@@ -5108,6 +5096,16 @@ function readPidfile(agent) {
|
|
|
5108
5096
|
return null;
|
|
5109
5097
|
}
|
|
5110
5098
|
}
|
|
5099
|
+
function supervisorPidFromSession(data) {
|
|
5100
|
+
if (typeof data.supervisorPid === "number") return data.supervisorPid;
|
|
5101
|
+
if (typeof data.pid === "number") return data.pid;
|
|
5102
|
+
return void 0;
|
|
5103
|
+
}
|
|
5104
|
+
function isAgentSessionRunning(data) {
|
|
5105
|
+
if (data === null) return false;
|
|
5106
|
+
const pid = supervisorPidFromSession(data);
|
|
5107
|
+
return typeof pid === "number" && isProcessAlive(pid);
|
|
5108
|
+
}
|
|
5111
5109
|
function removePidfile(agent) {
|
|
5112
5110
|
const p = pidfilePath(agent);
|
|
5113
5111
|
try {
|
|
@@ -5148,7 +5146,7 @@ function runStatus() {
|
|
|
5148
5146
|
const fsReg = readFsRegistry();
|
|
5149
5147
|
process.stderr.write("Active sessions:\n\n");
|
|
5150
5148
|
for (const s of sessions) {
|
|
5151
|
-
const supervisorAlive =
|
|
5149
|
+
const supervisorAlive = isAgentSessionRunning(s);
|
|
5152
5150
|
const fsEntry = fsReg[s.dir];
|
|
5153
5151
|
const fsAlive = fsEntry !== void 0 && isProcessAlive(fsEntry.pid);
|
|
5154
5152
|
const proxyAlive = proxyReg !== null && proxyReg.port === s.proxyPort && isProcessAlive(proxyReg.pid);
|
|
@@ -5295,9 +5293,7 @@ async function withResourceLock(fn) {
|
|
|
5295
5293
|
}
|
|
5296
5294
|
}
|
|
5297
5295
|
function liveAgents() {
|
|
5298
|
-
return listAllPidfiles().filter(
|
|
5299
|
-
(p) => typeof p.supervisorPid === "number" && isProcessAlive(p.supervisorPid)
|
|
5300
|
-
);
|
|
5296
|
+
return listAllPidfiles().filter((p) => isAgentSessionRunning(p));
|
|
5301
5297
|
}
|
|
5302
5298
|
function agentsReferencingProxy(proxyPort, agents, excludeAgent) {
|
|
5303
5299
|
return agents.filter((a) => a.agent !== excludeAgent && a.proxyPort === proxyPort);
|
|
@@ -5315,27 +5311,37 @@ async function nextFreePort(start, claimed, isBusy, range = FS_PORT_SCAN_RANGE)
|
|
|
5315
5311
|
`No free port for the filesystem server in range ${String(start)}-${String(start + range)}.`
|
|
5316
5312
|
);
|
|
5317
5313
|
}
|
|
5314
|
+
async function resolveBaseUrl(explicitBaseUrl) {
|
|
5315
|
+
if (explicitBaseUrl !== void 0 && explicitBaseUrl.trim().length > 0) {
|
|
5316
|
+
return explicitBaseUrl.trim();
|
|
5317
|
+
}
|
|
5318
|
+
const envBaseUrl = process.env["MULTICORN_BASE_URL"];
|
|
5319
|
+
if (typeof envBaseUrl === "string" && envBaseUrl.trim().length > 0) {
|
|
5320
|
+
return envBaseUrl.trim();
|
|
5321
|
+
}
|
|
5322
|
+
const config = await loadConfig();
|
|
5323
|
+
if (config !== null && config.baseUrl.length > 0) {
|
|
5324
|
+
return config.baseUrl;
|
|
5325
|
+
}
|
|
5326
|
+
const fromFile = await readBaseUrlFromConfig();
|
|
5327
|
+
if (fromFile !== void 0 && fromFile.length > 0) {
|
|
5328
|
+
return fromFile;
|
|
5329
|
+
}
|
|
5330
|
+
return DEFAULT_SHIELD_API_BASE_URL;
|
|
5331
|
+
}
|
|
5318
5332
|
async function resolveConfig(opts) {
|
|
5333
|
+
const baseUrl = await resolveBaseUrl(opts.baseUrl);
|
|
5319
5334
|
const fromFlag = opts.apiKey;
|
|
5320
5335
|
if (fromFlag && fromFlag.length > 0) {
|
|
5321
|
-
return {
|
|
5322
|
-
apiKey: fromFlag,
|
|
5323
|
-
baseUrl: opts.baseUrl ?? DEFAULT_SHIELD_API_BASE_URL
|
|
5324
|
-
};
|
|
5336
|
+
return { apiKey: fromFlag, baseUrl };
|
|
5325
5337
|
}
|
|
5326
5338
|
const envKey = process.env["MULTICORN_API_KEY"];
|
|
5327
5339
|
if (typeof envKey === "string" && envKey.length > 0) {
|
|
5328
|
-
return {
|
|
5329
|
-
apiKey: envKey,
|
|
5330
|
-
baseUrl: opts.baseUrl ?? DEFAULT_SHIELD_API_BASE_URL
|
|
5331
|
-
};
|
|
5340
|
+
return { apiKey: envKey, baseUrl };
|
|
5332
5341
|
}
|
|
5333
5342
|
const config = await loadConfig();
|
|
5334
5343
|
if (config !== null) {
|
|
5335
|
-
return {
|
|
5336
|
-
apiKey: config.apiKey,
|
|
5337
|
-
baseUrl: opts.baseUrl ?? config.baseUrl
|
|
5338
|
-
};
|
|
5344
|
+
return { apiKey: config.apiKey, baseUrl };
|
|
5339
5345
|
}
|
|
5340
5346
|
process.stderr.write(
|
|
5341
5347
|
"No API key found. Pass --api-key <key> or add it to ~/.multicorn/config.json.\n"
|
|
@@ -5391,8 +5397,24 @@ function startLocalProxyDetached(port, apiBaseUrl) {
|
|
|
5391
5397
|
child.unref();
|
|
5392
5398
|
return child;
|
|
5393
5399
|
}
|
|
5394
|
-
async function ensureProxy(proxyPort, apiBaseUrl) {
|
|
5395
|
-
|
|
5400
|
+
async function ensureProxy(proxyPort, apiBaseUrl, options) {
|
|
5401
|
+
const forceRespawn = options?.forceRespawn === true;
|
|
5402
|
+
if (forceRespawn) {
|
|
5403
|
+
const reg2 = readProxyRegistry();
|
|
5404
|
+
if (reg2 !== null && reg2.port === proxyPort && isProcessAlive(reg2.pid)) {
|
|
5405
|
+
killWithEscalation(reg2.pid, true);
|
|
5406
|
+
}
|
|
5407
|
+
if (reg2 !== null && reg2.port === proxyPort) {
|
|
5408
|
+
try {
|
|
5409
|
+
unlinkSync(PROXY_REGISTRY);
|
|
5410
|
+
} catch {
|
|
5411
|
+
}
|
|
5412
|
+
}
|
|
5413
|
+
for (let i = 0; i < 20; i++) {
|
|
5414
|
+
if (!await isPortListening(proxyPort)) break;
|
|
5415
|
+
await sleep3(100);
|
|
5416
|
+
}
|
|
5417
|
+
} else if (await probeProxyHealth(proxyPort)) {
|
|
5396
5418
|
const reg2 = readProxyRegistry();
|
|
5397
5419
|
const managed = reg2 !== null && reg2.port === proxyPort && isProcessAlive(reg2.pid);
|
|
5398
5420
|
return { reused: true, managed };
|
|
@@ -5629,8 +5651,9 @@ async function runStop(agent) {
|
|
|
5629
5651
|
process.exit(1);
|
|
5630
5652
|
}
|
|
5631
5653
|
await withResourceLock(() => {
|
|
5632
|
-
|
|
5633
|
-
|
|
5654
|
+
const supervisorPid = supervisorPidFromSession(data);
|
|
5655
|
+
if (typeof supervisorPid === "number" && isProcessAlive(supervisorPid)) {
|
|
5656
|
+
killWithEscalation(supervisorPid);
|
|
5634
5657
|
}
|
|
5635
5658
|
removePidfile(agent);
|
|
5636
5659
|
releaseFsServerIfUnused(data.dir, agent);
|
|
@@ -5660,7 +5683,8 @@ Run it once with the folder: npx multicorn-shield files restart <dir> --agent ${
|
|
|
5660
5683
|
await runDetached({
|
|
5661
5684
|
...opts,
|
|
5662
5685
|
dir,
|
|
5663
|
-
proxyPort: opts.proxyPort ?? existing?.proxyPort
|
|
5686
|
+
proxyPort: opts.proxyPort ?? existing?.proxyPort,
|
|
5687
|
+
respawnProxy: true});
|
|
5664
5688
|
}
|
|
5665
5689
|
async function runDetached(opts) {
|
|
5666
5690
|
const absDir = resolve(opts.dir);
|
|
@@ -5671,8 +5695,7 @@ async function runDetached(opts) {
|
|
|
5671
5695
|
}
|
|
5672
5696
|
const existing = readPidfile(opts.agent);
|
|
5673
5697
|
if (existing !== null) {
|
|
5674
|
-
|
|
5675
|
-
if (alive) {
|
|
5698
|
+
if (isAgentSessionRunning(existing)) {
|
|
5676
5699
|
process.stderr.write(
|
|
5677
5700
|
`Already running for agent "${opts.agent}" (fs :${String(existing.fsPort)}, proxy :${String(existing.proxyPort)}).
|
|
5678
5701
|
Stop with: npx multicorn-shield files stop --agent ${opts.agent}
|
|
@@ -5687,6 +5710,7 @@ Stop with: npx multicorn-shield files stop --agent ${opts.agent}
|
|
|
5687
5710
|
if (opts.proxyPort !== void 0) args.push("--proxy-port", String(opts.proxyPort));
|
|
5688
5711
|
if (opts.apiKey !== void 0) args.push("--api-key", opts.apiKey);
|
|
5689
5712
|
if (opts.baseUrl !== void 0) args.push("--base-url", opts.baseUrl);
|
|
5713
|
+
if (opts.respawnProxy) args.push("--respawn-proxy");
|
|
5690
5714
|
if (opts.client !== void 0) args.push("--client", opts.client);
|
|
5691
5715
|
const scriptPath = process.argv[1] ?? resolve("dist/multicorn-shield.js");
|
|
5692
5716
|
const logFile = join(PIDFILE_DIR, `files-${opts.agent}.log`);
|
|
@@ -5770,8 +5794,7 @@ async function runFilesCommand(opts) {
|
|
|
5770
5794
|
const proxyPort = opts.proxyPort ?? DEFAULT_PROXY_PORT;
|
|
5771
5795
|
const existingPidfile = readPidfile(opts.agent);
|
|
5772
5796
|
if (existingPidfile !== null) {
|
|
5773
|
-
|
|
5774
|
-
if (supervisorAlive) {
|
|
5797
|
+
if (isAgentSessionRunning(existingPidfile)) {
|
|
5775
5798
|
process.stderr.write(
|
|
5776
5799
|
`A session for agent "${opts.agent}" is already running. Run 'files stop --agent ${opts.agent}' first, or use a different --agent name.
|
|
5777
5800
|
`
|
|
@@ -5785,7 +5808,9 @@ async function runFilesCommand(opts) {
|
|
|
5785
5808
|
let fsReused;
|
|
5786
5809
|
try {
|
|
5787
5810
|
const ensured = await withResourceLock(async () => {
|
|
5788
|
-
const proxyRes = await ensureProxy(proxyPort, config.baseUrl
|
|
5811
|
+
const proxyRes = await ensureProxy(proxyPort, config.baseUrl, {
|
|
5812
|
+
forceRespawn: opts.respawnProxy
|
|
5813
|
+
});
|
|
5789
5814
|
const fsRes = await ensureFsServer(realDir, opts.port);
|
|
5790
5815
|
writePidfile({
|
|
5791
5816
|
agent: opts.agent,
|
|
@@ -6052,6 +6077,8 @@ function parseArgs(argv) {
|
|
|
6052
6077
|
let filesForeground = false;
|
|
6053
6078
|
let filesStatus = false;
|
|
6054
6079
|
let filesRestart = false;
|
|
6080
|
+
let filesRespawnProxy = false;
|
|
6081
|
+
let initIntegration = void 0;
|
|
6055
6082
|
for (let i = 0; i < args.length; i++) {
|
|
6056
6083
|
const arg = args[i];
|
|
6057
6084
|
if (arg === "init") {
|
|
@@ -6102,6 +6129,8 @@ function parseArgs(argv) {
|
|
|
6102
6129
|
filesStop = true;
|
|
6103
6130
|
} else if (token === "--foreground") {
|
|
6104
6131
|
filesForeground = true;
|
|
6132
|
+
} else if (token === "--respawn-proxy") {
|
|
6133
|
+
filesRespawnProxy = true;
|
|
6105
6134
|
} else if (token === "--detach") ; else if (token === "stop") {
|
|
6106
6135
|
filesStop = true;
|
|
6107
6136
|
} else if (token === "status") {
|
|
@@ -6210,6 +6239,12 @@ function parseArgs(argv) {
|
|
|
6210
6239
|
}
|
|
6211
6240
|
} else if (arg === "--verbose" || arg === "--debug") {
|
|
6212
6241
|
verbose = true;
|
|
6242
|
+
} else if (arg === "--integration") {
|
|
6243
|
+
const next = args[i + 1];
|
|
6244
|
+
if (next === "native" || next === "hosted") {
|
|
6245
|
+
initIntegration = next;
|
|
6246
|
+
i++;
|
|
6247
|
+
}
|
|
6213
6248
|
}
|
|
6214
6249
|
}
|
|
6215
6250
|
return {
|
|
@@ -6223,6 +6258,7 @@ function parseArgs(argv) {
|
|
|
6223
6258
|
deleteAgentName,
|
|
6224
6259
|
apiKey,
|
|
6225
6260
|
verbose,
|
|
6261
|
+
initIntegration,
|
|
6226
6262
|
filesDir,
|
|
6227
6263
|
filesPort,
|
|
6228
6264
|
filesProxyPort,
|
|
@@ -6230,7 +6266,8 @@ function parseArgs(argv) {
|
|
|
6230
6266
|
filesClient,
|
|
6231
6267
|
filesForeground,
|
|
6232
6268
|
filesStatus,
|
|
6233
|
-
filesRestart
|
|
6269
|
+
filesRestart,
|
|
6270
|
+
filesRespawnProxy
|
|
6234
6271
|
};
|
|
6235
6272
|
}
|
|
6236
6273
|
function printHelp() {
|
|
@@ -6240,7 +6277,12 @@ function printHelp() {
|
|
|
6240
6277
|
"",
|
|
6241
6278
|
"Usage:",
|
|
6242
6279
|
" npx multicorn-shield init",
|
|
6243
|
-
" Interactive setup
|
|
6280
|
+
" Interactive setup for native plugins (files, terminal, browser).",
|
|
6281
|
+
" Native: OpenClaw, Claude Code, Windsurf, Cline, Gemini CLI, OpenCode, Codex CLI.",
|
|
6282
|
+
" MCP-only clients (Cursor, Copilot, etc.): https://app.multicorn.ai/agents/new",
|
|
6283
|
+
" Saves API key to ~/.multicorn/config.json.",
|
|
6284
|
+
" --integration hosted Use hosted MCP proxy for Windsurf, Cline, Gemini CLI,",
|
|
6285
|
+
" OpenCode, or Codex CLI (default: native).",
|
|
6244
6286
|
"",
|
|
6245
6287
|
" npx multicorn-shield files <dir> --agent <name> [--client <client>]",
|
|
6246
6288
|
" Share a local folder with a coding agent. Starts a filesystem MCP server",
|
|
@@ -6321,7 +6363,10 @@ async function runCli() {
|
|
|
6321
6363
|
process.exit(0);
|
|
6322
6364
|
}
|
|
6323
6365
|
if (cli.subcommand === "init") {
|
|
6324
|
-
await runInit(cli.baseUrl, {
|
|
6366
|
+
await runInit(cli.baseUrl, {
|
|
6367
|
+
verbose: cli.verbose,
|
|
6368
|
+
...cli.initIntegration !== void 0 ? { integration: cli.initIntegration } : {}
|
|
6369
|
+
});
|
|
6325
6370
|
return;
|
|
6326
6371
|
}
|
|
6327
6372
|
if (cli.subcommand === "files") {
|
|
@@ -6337,7 +6382,8 @@ async function runCli() {
|
|
|
6337
6382
|
client: void 0,
|
|
6338
6383
|
foreground: true,
|
|
6339
6384
|
status: true,
|
|
6340
|
-
restart: false
|
|
6385
|
+
restart: false,
|
|
6386
|
+
respawnProxy: false
|
|
6341
6387
|
});
|
|
6342
6388
|
return;
|
|
6343
6389
|
}
|
|
@@ -6362,7 +6408,8 @@ async function runCli() {
|
|
|
6362
6408
|
client: cli.filesClient,
|
|
6363
6409
|
foreground: cli.filesForeground,
|
|
6364
6410
|
status: false,
|
|
6365
|
-
restart: cli.filesRestart
|
|
6411
|
+
restart: cli.filesRestart,
|
|
6412
|
+
respawnProxy: cli.filesRespawnProxy
|
|
6366
6413
|
});
|
|
6367
6414
|
return;
|
|
6368
6415
|
}
|