multicorn-shield 1.3.2 → 1.3.5

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.
@@ -691,9 +691,11 @@ async function updateOpenClawConfigIfPresent(apiKey, baseUrl, agentName) {
691
691
  }
692
692
  }
693
693
  }
694
- await writeFile(OPENCLAW_CONFIG_PATH, JSON.stringify(obj, null, 2) + "\n", {
695
- encoding: "utf8"
696
- });
694
+ await writeFile(
695
+ OPENCLAW_CONFIG_PATH,
696
+ JSON.stringify(obj, null, 2) + "\n",
697
+ SECRET_JSON_FILE_OPTIONS
698
+ );
697
699
  return "updated";
698
700
  }
699
701
  async function validateApiKey(apiKey, baseUrl) {
@@ -855,7 +857,7 @@ async function installWindsurfNativeHooks() {
855
857
  base["hooks"] = nextHooks;
856
858
  const hooksDir = dirname(hooksPath);
857
859
  await mkdir(hooksDir, { recursive: true });
858
- await writeFile(hooksPath, JSON.stringify(base, null, 2) + "\n", { encoding: "utf8" });
860
+ await writeFile(hooksPath, JSON.stringify(base, null, 2) + "\n", SECRET_JSON_FILE_OPTIONS);
859
861
  }
860
862
  function getClineHooksInstallDir() {
861
863
  return join(homedir(), ".multicorn", "cline-hooks");
@@ -934,6 +936,37 @@ function getGeminiCliHooksInstallDir() {
934
936
  function getGeminiCliSettingsPath() {
935
937
  return join(homedir(), ".gemini", "settings.json");
936
938
  }
939
+ async function mergeGeminiHostedMcpServersIntoSettings(shortName, proxyUrl, apiKey) {
940
+ const settingsPath = getGeminiCliSettingsPath();
941
+ let existing = {};
942
+ try {
943
+ const rawText = await readFile(settingsPath, "utf8");
944
+ const parsed = JSON.parse(rawText);
945
+ if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) {
946
+ existing = parsed;
947
+ }
948
+ } catch (err) {
949
+ if (isErrnoException(err) && err.code === "ENOENT") {
950
+ existing = {};
951
+ } else {
952
+ const detail = err instanceof Error ? err.message : String(err);
953
+ throw new Error(`Could not read or parse Gemini CLI settings at ${settingsPath}: ${detail}`);
954
+ }
955
+ }
956
+ const mcpRaw = existing["mcpServers"];
957
+ const mcpServers = typeof mcpRaw === "object" && mcpRaw !== null && !Array.isArray(mcpRaw) ? { ...mcpRaw } : {};
958
+ mcpServers[shortName] = {
959
+ httpUrl: proxyUrl,
960
+ headers: {
961
+ Authorization: `Bearer ${apiKey}`
962
+ }
963
+ };
964
+ const out = { ...existing, mcpServers };
965
+ await mkdir(dirname(settingsPath), { recursive: true });
966
+ const serialized = JSON.stringify(out, null, 2) + "\n";
967
+ await writeFile(settingsPath, serialized, SECRET_JSON_FILE_OPTIONS);
968
+ writeMcpAddedLine(shortName, settingsPath);
969
+ }
937
970
  function geminiInnerHooksReferenceShield(inner, multicornName) {
938
971
  if (!Array.isArray(inner)) return false;
939
972
  for (const h of inner) {
@@ -1118,7 +1151,7 @@ async function installClaudeCodeUserSettingsHooks(ask) {
1118
1151
  hooksObj["PostToolUse"] = postArr;
1119
1152
  const out = { ...existing, hooks: hooksObj };
1120
1153
  const serialized = JSON.stringify(out, null, 2) + "\n";
1121
- await writeFile(settingsPath, serialized, "utf8");
1154
+ await writeFile(settingsPath, serialized, SECRET_JSON_FILE_OPTIONS);
1122
1155
  process.stderr.write(
1123
1156
  "\n" + style.dim("Wrote ") + style.cyan(settingsPath) + style.dim(":") + "\n"
1124
1157
  );
@@ -1220,7 +1253,7 @@ async function installGeminiCliNativeHooks(ask) {
1220
1253
  AfterTool: afterArr
1221
1254
  };
1222
1255
  await mkdir(dirname(settingsPath), { recursive: true });
1223
- await writeFile(settingsPath, JSON.stringify(existing, null, 2) + "\n", "utf8");
1256
+ await writeFile(settingsPath, JSON.stringify(existing, null, 2) + "\n", SECRET_JSON_FILE_OPTIONS);
1224
1257
  }
1225
1258
  async function promptGeminiCliIntegrationMode(ask) {
1226
1259
  process.stderr.write("\n" + style.bold("Gemini CLI integration") + "\n");
@@ -1259,6 +1292,52 @@ function getClaudeDesktopConfigPath() {
1259
1292
  );
1260
1293
  }
1261
1294
  }
1295
+ function getCursorMcpJsonPath() {
1296
+ return join(homedir(), ".cursor", "mcp.json");
1297
+ }
1298
+ function getWindsurfMcpConfigPath() {
1299
+ return join(homedir(), ".codeium", "windsurf", "mcp_config.json");
1300
+ }
1301
+ function getClineMcpSettingsPath() {
1302
+ switch (process.platform) {
1303
+ case "win32":
1304
+ return join(
1305
+ process.env["APPDATA"] ?? join(homedir(), "AppData", "Roaming"),
1306
+ "Code",
1307
+ "User",
1308
+ "globalStorage",
1309
+ "saoudrizwan.claude-dev",
1310
+ "settings",
1311
+ "cline_mcp_settings.json"
1312
+ );
1313
+ case "linux":
1314
+ return join(
1315
+ homedir(),
1316
+ ".config",
1317
+ "Code",
1318
+ "User",
1319
+ "globalStorage",
1320
+ "saoudrizwan.claude-dev",
1321
+ "settings",
1322
+ "cline_mcp_settings.json"
1323
+ );
1324
+ default:
1325
+ return join(
1326
+ homedir(),
1327
+ "Library",
1328
+ "Application Support",
1329
+ "Code",
1330
+ "User",
1331
+ "globalStorage",
1332
+ "saoudrizwan.claude-dev",
1333
+ "settings",
1334
+ "cline_mcp_settings.json"
1335
+ );
1336
+ }
1337
+ }
1338
+ function getContinueConfigJsonPath() {
1339
+ return join(homedir(), ".continue", "config.json");
1340
+ }
1262
1341
  function platformMenuLabelForSelection(sel) {
1263
1342
  const slug = PLATFORM_BY_SELECTION[sel];
1264
1343
  if (slug === void 0) return "Unknown";
@@ -1390,9 +1469,11 @@ async function arrowSelect(options, ask, fallbackLabel) {
1390
1469
  process.stdin.on("data", onData);
1391
1470
  });
1392
1471
  }
1393
- async function promptAgentName(ask, platform) {
1472
+ async function promptAgentName(ask, platform, defaultNameOverride) {
1394
1473
  const dirPart = normalizeAgentName(basename(process.cwd()));
1395
- const defaultAgentName = dirPart.length > 0 ? normalizeAgentName(`${dirPart}-${platform}`) || platform : normalizeAgentName(platform) || platform;
1474
+ const computedDefault = dirPart.length > 0 ? normalizeAgentName(`${dirPart}-${platform}`) || platform : normalizeAgentName(platform) || platform;
1475
+ const fromOverride = defaultNameOverride !== void 0 && defaultNameOverride.trim().length > 0 ? normalizeAgentName(defaultNameOverride.trim()) : "";
1476
+ const defaultAgentName = fromOverride.length > 0 ? fromOverride : computedDefault;
1396
1477
  let agentName = "";
1397
1478
  while (agentName.length === 0) {
1398
1479
  const input = await ask(
@@ -1483,6 +1564,240 @@ async function createProxyConfig(baseUrl, apiKey, agentName, targetUrl, serverNa
1483
1564
  const data = envelope["data"];
1484
1565
  return typeof data?.["proxy_url"] === "string" ? data["proxy_url"] : "";
1485
1566
  }
1567
+ function writeMcpAddedLine(shortName, filePath) {
1568
+ process.stderr.write(
1569
+ style.green("\u2713") + ' MCP server "' + shortName + '" added to ' + style.cyan(filePath) + "\n"
1570
+ );
1571
+ }
1572
+ async function mergeMcpServersObjectStyle(filePath, shortName, entry) {
1573
+ let root = {};
1574
+ try {
1575
+ const raw = await readFile(filePath, "utf8");
1576
+ let parsed;
1577
+ try {
1578
+ parsed = JSON.parse(raw);
1579
+ } catch {
1580
+ return "parse-error";
1581
+ }
1582
+ if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) {
1583
+ root = parsed;
1584
+ } else {
1585
+ return "parse-error";
1586
+ }
1587
+ } catch (e) {
1588
+ if (isErrnoException(e) && e.code === "ENOENT") {
1589
+ root = {};
1590
+ } else {
1591
+ throw e;
1592
+ }
1593
+ }
1594
+ const mcpRaw = root["mcpServers"];
1595
+ const mcpServers = typeof mcpRaw === "object" && mcpRaw !== null && !Array.isArray(mcpRaw) ? { ...mcpRaw } : {};
1596
+ mcpServers[shortName] = entry;
1597
+ root["mcpServers"] = mcpServers;
1598
+ await mkdir(dirname(filePath), { recursive: true });
1599
+ await writeFile(filePath, JSON.stringify(root, null, 2) + "\n", SECRET_JSON_FILE_OPTIONS);
1600
+ writeMcpAddedLine(shortName, filePath);
1601
+ return "ok";
1602
+ }
1603
+ async function mergeClaudeDesktopHostedMcpRemote(shortName, proxyUrl, apiKey) {
1604
+ const entry = {
1605
+ command: "npx",
1606
+ args: ["-y", "mcp-remote", proxyUrl, "--header", `Authorization: Bearer ${apiKey}`]
1607
+ };
1608
+ return mergeMcpServersObjectStyle(getClaudeDesktopConfigPath(), shortName, entry);
1609
+ }
1610
+ async function mergeContinueHostedMcp(shortName, proxyUrl, apiKey) {
1611
+ const filePath = getContinueConfigJsonPath();
1612
+ let root = {};
1613
+ try {
1614
+ const raw = await readFile(filePath, "utf8");
1615
+ let parsed;
1616
+ try {
1617
+ parsed = JSON.parse(raw);
1618
+ } catch {
1619
+ return "parse-error";
1620
+ }
1621
+ if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) {
1622
+ root = parsed;
1623
+ } else {
1624
+ return "parse-error";
1625
+ }
1626
+ } catch (e) {
1627
+ if (isErrnoException(e) && e.code === "ENOENT") {
1628
+ root = {};
1629
+ } else {
1630
+ throw e;
1631
+ }
1632
+ }
1633
+ const rawServers = root["mcpServers"];
1634
+ if (rawServers !== void 0) {
1635
+ if (Array.isArray(rawServers)) ; else if (typeof rawServers === "object" && rawServers !== null) {
1636
+ return "parse-error";
1637
+ } else {
1638
+ return "parse-error";
1639
+ }
1640
+ }
1641
+ const servers = Array.isArray(rawServers) ? rawServers.map((s) => ({ ...s })) : [];
1642
+ const entry = {
1643
+ name: shortName,
1644
+ type: "streamable-http",
1645
+ url: proxyUrl,
1646
+ headers: {
1647
+ Authorization: `Bearer ${apiKey}`
1648
+ }
1649
+ };
1650
+ const idx = servers.findIndex((s) => s["name"] === shortName);
1651
+ if (idx >= 0) {
1652
+ servers[idx] = entry;
1653
+ } else {
1654
+ servers.push(entry);
1655
+ }
1656
+ root["mcpServers"] = servers;
1657
+ await mkdir(dirname(filePath), { recursive: true });
1658
+ await writeFile(filePath, JSON.stringify(root, null, 2) + "\n", SECRET_JSON_FILE_OPTIONS);
1659
+ writeMcpAddedLine(shortName, filePath);
1660
+ return "ok";
1661
+ }
1662
+ async function mergeKiloCodeProjectMcp(workspacePath, shortName, proxyUrl, apiKey) {
1663
+ const filePath = join(workspacePath, ".kilocode", "mcp.json");
1664
+ return mergeMcpServersObjectStyle(filePath, shortName, {
1665
+ url: proxyUrl,
1666
+ headers: {
1667
+ Authorization: `Bearer ${apiKey}`
1668
+ }
1669
+ });
1670
+ }
1671
+ function printHostedProxyJsonParseWarning(filePath) {
1672
+ process.stderr.write(
1673
+ style.yellow("\u26A0") + " Could not parse JSON at " + style.cyan(filePath) + style.dim(" - showing paste snippet instead.") + "\n"
1674
+ );
1675
+ }
1676
+ function printHostedProxyPostWriteHints(platform, shortName) {
1677
+ if (platform === "cursor") {
1678
+ process.stderr.write(
1679
+ style.dim("Restart Cursor and check Settings > Tools & MCPs for a green status indicator. ") + style.dim(`Ask Cursor to use your MCP server by its short name (e.g. ${shortName}).`) + "\n"
1680
+ );
1681
+ }
1682
+ if (platform === "claude-desktop") {
1683
+ process.stderr.write(style.dim("Restart Claude Desktop to load the MCP server.") + "\n");
1684
+ }
1685
+ if (platform === "cline") {
1686
+ process.stderr.write(
1687
+ style.dim(
1688
+ "Restart Cline or reload the VS Code window. Cline will discover the Shield tools automatically."
1689
+ ) + "\n"
1690
+ );
1691
+ }
1692
+ if (platform === "windsurf") {
1693
+ process.stderr.write(style.dim("Restart Windsurf (Cmd/Ctrl+Q, then reopen).") + "\n");
1694
+ process.stderr.write(
1695
+ style.dim(
1696
+ "Open the Cascade panel and verify the server appears with a green status indicator."
1697
+ ) + "\n"
1698
+ );
1699
+ }
1700
+ if (platform === "github-copilot" || platform === "continue-dev") {
1701
+ process.stderr.write(
1702
+ style.dim("Reload the editor window if the MCP server does not appear immediately.") + "\n"
1703
+ );
1704
+ }
1705
+ if (platform === "goose") {
1706
+ process.stderr.write(style.dim("Start a new Goose session after updating config.") + "\n");
1707
+ }
1708
+ if (platform === "kilo-code") {
1709
+ process.stderr.write(
1710
+ style.dim("Restart Kilo Code or reload the window so it picks up .kilocode/mcp.json.") + "\n"
1711
+ );
1712
+ }
1713
+ }
1714
+ async function applyHostedProxyMcpConfig(platform, proxyUrl, shortName, apiKey, workspacePath) {
1715
+ const authHeader = `Bearer ${apiKey}`;
1716
+ if (platform === "gemini-cli") {
1717
+ await mergeGeminiHostedMcpServersIntoSettings(shortName, proxyUrl, apiKey);
1718
+ process.stderr.write(
1719
+ style.dim(
1720
+ "For project-specific config, copy the mcpServers entry into .gemini/settings.json in your project root. Restart Gemini CLI if it is already running."
1721
+ ) + "\n"
1722
+ );
1723
+ return;
1724
+ }
1725
+ if (platform === "github-copilot") {
1726
+ process.stderr.write(
1727
+ "\n" + style.dim(
1728
+ "GitHub Copilot uses VS Code settings - paste the snippet below into your VS Code Settings (JSON)."
1729
+ ) + "\n"
1730
+ );
1731
+ printPlatformSnippet(platform, proxyUrl, shortName, apiKey);
1732
+ return;
1733
+ }
1734
+ if (platform === "goose") {
1735
+ printPlatformSnippet(platform, proxyUrl, shortName, apiKey);
1736
+ return;
1737
+ }
1738
+ try {
1739
+ let result = "parse-error";
1740
+ if (platform === "cursor") {
1741
+ result = await mergeMcpServersObjectStyle(getCursorMcpJsonPath(), shortName, {
1742
+ url: proxyUrl,
1743
+ headers: { Authorization: authHeader }
1744
+ });
1745
+ if (result === "parse-error") {
1746
+ printHostedProxyJsonParseWarning(getCursorMcpJsonPath());
1747
+ }
1748
+ } else if (platform === "claude-desktop") {
1749
+ result = await mergeClaudeDesktopHostedMcpRemote(shortName, proxyUrl, apiKey);
1750
+ if (result === "parse-error") {
1751
+ printHostedProxyJsonParseWarning(getClaudeDesktopConfigPath());
1752
+ }
1753
+ } else if (platform === "windsurf") {
1754
+ result = await mergeMcpServersObjectStyle(getWindsurfMcpConfigPath(), shortName, {
1755
+ serverUrl: proxyUrl,
1756
+ headers: { Authorization: authHeader }
1757
+ });
1758
+ if (result === "parse-error") {
1759
+ printHostedProxyJsonParseWarning(getWindsurfMcpConfigPath());
1760
+ }
1761
+ } else if (platform === "cline") {
1762
+ result = await mergeMcpServersObjectStyle(getClineMcpSettingsPath(), shortName, {
1763
+ url: proxyUrl,
1764
+ headers: { Authorization: authHeader }
1765
+ });
1766
+ if (result === "parse-error") {
1767
+ printHostedProxyJsonParseWarning(getClineMcpSettingsPath());
1768
+ }
1769
+ } else if (platform === "kilo-code") {
1770
+ result = await mergeKiloCodeProjectMcp(workspacePath, shortName, proxyUrl, apiKey);
1771
+ if (result === "parse-error") {
1772
+ printHostedProxyJsonParseWarning(join(workspacePath, ".kilocode", "mcp.json"));
1773
+ }
1774
+ } else if (platform === "continue-dev") {
1775
+ result = await mergeContinueHostedMcp(shortName, proxyUrl, apiKey);
1776
+ if (result === "parse-error") {
1777
+ printHostedProxyJsonParseWarning(getContinueConfigJsonPath());
1778
+ }
1779
+ } else {
1780
+ result = await mergeMcpServersObjectStyle(getCursorMcpJsonPath(), shortName, {
1781
+ url: proxyUrl,
1782
+ headers: { Authorization: authHeader }
1783
+ });
1784
+ if (result === "parse-error") {
1785
+ printHostedProxyJsonParseWarning(getCursorMcpJsonPath());
1786
+ }
1787
+ }
1788
+ if (result === "ok") {
1789
+ printHostedProxyPostWriteHints(platform, shortName);
1790
+ return;
1791
+ }
1792
+ } catch (e) {
1793
+ const detail = e instanceof Error ? e.message : String(e);
1794
+ process.stderr.write(
1795
+ style.yellow("\u26A0") + ` Could not write MCP config automatically (${detail}).
1796
+ `
1797
+ );
1798
+ }
1799
+ printPlatformSnippet(platform, proxyUrl, shortName, apiKey);
1800
+ }
1486
1801
  function gooseHostedProxyYaml(shortName, proxyUrl, bearerHeader) {
1487
1802
  return `extensions:
1488
1803
  ${shortName}:
@@ -1544,6 +1859,36 @@ function printPlatformSnippet(platform, routingToken, shortName, apiKey) {
1544
1859
  null,
1545
1860
  2
1546
1861
  );
1862
+ } else if (platform === "claude-desktop") {
1863
+ snippetText = JSON.stringify(
1864
+ {
1865
+ mcpServers: {
1866
+ [shortName]: {
1867
+ command: "npx",
1868
+ args: ["-y", "mcp-remote", routingToken, "--header", `Authorization: ${authHeader}`]
1869
+ }
1870
+ }
1871
+ },
1872
+ null,
1873
+ 2
1874
+ );
1875
+ } else if (platform === "continue-dev") {
1876
+ snippetText = JSON.stringify(
1877
+ {
1878
+ mcpServers: [
1879
+ {
1880
+ name: shortName,
1881
+ type: "streamable-http",
1882
+ url: routingToken,
1883
+ headers: {
1884
+ Authorization: authHeader
1885
+ }
1886
+ }
1887
+ ]
1888
+ },
1889
+ null,
1890
+ 2
1891
+ );
1547
1892
  } else {
1548
1893
  const urlKey = platform === "windsurf" ? "serverUrl" : "url";
1549
1894
  snippetText = JSON.stringify(
@@ -1568,52 +1913,33 @@ function printPlatformSnippet(platform, routingToken, shortName, apiKey) {
1568
1913
  } else if (platform === "claude-desktop") {
1569
1914
  process.stderr.write("\n" + style.dim(`Add this to ${getClaudeDesktopConfigPath()}:`) + "\n\n");
1570
1915
  } else if (platform === "windsurf") {
1571
- process.stderr.write(
1572
- "\n" + style.dim("Add this to ~/.codeium/windsurf/mcp_config.json:") + "\n\n"
1573
- );
1916
+ process.stderr.write("\n" + style.dim(`Add this to ${getWindsurfMcpConfigPath()}:`) + "\n\n");
1574
1917
  } else if (platform === "cline") {
1575
- process.stderr.write("\n" + style.dim("Add this to your Cline MCP settings file:") + "\n");
1576
- process.stderr.write(
1577
- style.dim(
1578
- " macOS: ~/Library/Application Support/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json"
1579
- ) + "\n"
1580
- );
1581
- process.stderr.write(
1582
- style.dim(
1583
- " Windows: %APPDATA%\\Code\\User\\globalStorage\\saoudrizwan.claude-dev\\settings\\cline_mcp_settings.json"
1584
- ) + "\n"
1585
- );
1586
- process.stderr.write(
1587
- style.dim(
1588
- " Linux: ~/.config/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json"
1589
- ) + "\n\n"
1590
- );
1918
+ process.stderr.write("\n" + style.dim(`Add this to ${getClineMcpSettingsPath()}:`) + "\n\n");
1591
1919
  } else if (platform === "gemini-cli") {
1592
1920
  process.stderr.write(
1593
1921
  "\n" + style.dim(
1594
- "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."
1922
+ `Merge the snippet below into ${getGeminiCliSettingsPath()} (keep existing hooks and other keys). Restart Gemini CLI if it is already running.`
1595
1923
  ) + "\n\n"
1596
1924
  );
1597
1925
  } else if (platform === "kilo-code") {
1598
1926
  process.stderr.write(
1599
- "\n" + style.dim("Add this to .kilocode/mcp.json in your project root.") + "\n\n"
1927
+ "\n" + style.dim(`Add this to ${join(resolve(process.cwd()), ".kilocode", "mcp.json")}:`) + "\n\n"
1600
1928
  );
1601
1929
  } else if (platform === "github-copilot") {
1602
1930
  process.stderr.write(
1603
1931
  "\n" + style.dim(
1604
- "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."
1932
+ "Merge this snippet under the mcp key in your VS Code Settings (JSON). If you do not have an mcp section yet, add one. Copilot picks up MCP servers when you use Agent mode."
1605
1933
  ) + "\n\n"
1606
1934
  );
1607
1935
  } else if (platform === "continue-dev") {
1608
- process.stderr.write(
1609
- "\n" + style.dim("Save this as .continue/mcpServers/shield.json in your workspace root.") + "\n\n"
1610
- );
1936
+ process.stderr.write("\n" + style.dim(`Add this to ${getContinueConfigJsonPath()}:`) + "\n\n");
1611
1937
  } else if (platform === "goose") {
1612
1938
  process.stderr.write(
1613
1939
  "\n" + style.dim("Add this to ~/.config/goose/config.yaml under the extensions key.") + "\n\n"
1614
1940
  );
1615
1941
  } else {
1616
- process.stderr.write("\n" + style.dim("Add this to ~/.cursor/mcp.json:") + "\n\n");
1942
+ process.stderr.write("\n" + style.dim(`Add this to ${getCursorMcpJsonPath()}:`) + "\n\n");
1617
1943
  }
1618
1944
  process.stderr.write(style.cyan(snippetText) + "\n\n");
1619
1945
  if (!usesInlineKey) {
@@ -1662,19 +1988,44 @@ function printPlatformSnippet(platform, routingToken, shortName, apiKey) {
1662
1988
  process.stderr.write(style.dim("Start a new Goose session after updating config.") + "\n");
1663
1989
  }
1664
1990
  }
1991
+ function agentDisplayNameDedupeKey(name) {
1992
+ return name.trim().toLowerCase();
1993
+ }
1994
+ function normalizeAgentEntryForMerge(a) {
1995
+ const name = a.name.trim();
1996
+ const ws = typeof a.workspacePath === "string" && a.workspacePath.length > 0 ? a.workspacePath : void 0;
1997
+ return ws !== void 0 ? { name, platform: a.platform, workspacePath: ws } : { name, platform: a.platform };
1998
+ }
1999
+ function mergeAgentEntryDupPair(first, second) {
2000
+ const name = first.name.trim();
2001
+ const platform = first.platform;
2002
+ const ws = typeof first.workspacePath === "string" && first.workspacePath.length > 0 ? first.workspacePath : typeof second.workspacePath === "string" && second.workspacePath.length > 0 ? second.workspacePath : void 0;
2003
+ return ws !== void 0 ? { name, platform, workspacePath: ws } : { name, platform };
2004
+ }
2005
+ function mergeAgentsForUniqueNames(agents) {
2006
+ const byKey = /* @__PURE__ */ new Map();
2007
+ for (const raw of agents) {
2008
+ const key = agentDisplayNameDedupeKey(raw.name);
2009
+ const candidate = normalizeAgentEntryForMerge(raw);
2010
+ const prev = byKey.get(key);
2011
+ byKey.set(key, prev === void 0 ? candidate : mergeAgentEntryDupPair(prev, candidate));
2012
+ }
2013
+ return [...byKey.values()];
2014
+ }
1665
2015
  function mergeAgentsForPlatform(localAgents, remoteAgents, selectedPlatform) {
1666
- const localMatches = localAgents.filter((a) => a.platform === selectedPlatform);
1667
- const seen = new Set(localMatches.map((a) => a.name));
1668
- const out = localMatches.map((a) => ({ ...a }));
2016
+ const merged = [];
2017
+ for (const a of localAgents) {
2018
+ if (a.platform !== selectedPlatform) continue;
2019
+ merged.push(a);
2020
+ }
1669
2021
  for (const r of remoteAgents) {
1670
2022
  if (r.platform !== selectedPlatform) continue;
1671
- if (seen.has(r.name)) continue;
1672
- seen.add(r.name);
1673
- out.push({ name: r.name, platform: selectedPlatform });
2023
+ merged.push({ name: r.name, platform: selectedPlatform });
1674
2024
  }
1675
- return out;
2025
+ return mergeAgentsForUniqueNames(merged);
1676
2026
  }
1677
- async function runInit(explicitBaseUrl) {
2027
+ async function runInit(explicitBaseUrl, options) {
2028
+ const verbose = options?.verbose === true;
1678
2029
  if (!process.stdin.isTTY) {
1679
2030
  process.stderr.write(
1680
2031
  style.red("Error: interactive terminal required. Cannot run init with piped input.") + "\n"
@@ -1789,7 +2140,7 @@ async function runInit(explicitBaseUrl) {
1789
2140
  `
1790
2141
  );
1791
2142
  process.stderr.write(
1792
- "\n" + style.bold("Try it:") + " " + style.cyan(
2143
+ "\n" + style.bold("Try it:") + " make a request in your coding agent - Shield will intercept the first tool call and ask for your consent.\n" + style.dim("Example wrap command: ") + style.cyan(
1793
2144
  "npx multicorn-shield --wrap npx @modelcontextprotocol/server-filesystem /tmp"
1794
2145
  ) + "\n"
1795
2146
  );
@@ -1822,11 +2173,13 @@ async function runInit(explicitBaseUrl) {
1822
2173
  (r) => r.platform === selectedPlatform
1823
2174
  ).length;
1824
2175
  const savedSummary = currentAgents.length === 0 ? "none on disk" : currentAgents.map((a) => `${a.name} (${a.platform})`).join(", ");
1825
- process.stderr.write(
1826
- style.dim(
1827
- `[shield init] Menu option ${String(selection)} -> platform slug "${selectedPlatform}". ${String(agentsForPlatform.length)} agent(s) for this platform (local file: ${String(localForPlatformCount)}, account API: ${String(accountForPlatformCount)}). On-disk entries: ${savedSummary}.`
1828
- ) + "\n"
1829
- );
2176
+ if (verbose) {
2177
+ process.stderr.write(
2178
+ style.dim(
2179
+ `[shield init] Menu option ${String(selection)} -> platform slug "${selectedPlatform}". ${String(agentsForPlatform.length)} agent(s) for this platform (local file: ${String(localForPlatformCount)}, account API: ${String(accountForPlatformCount)}). On-disk entries: ${savedSummary}.`
2180
+ ) + "\n"
2181
+ );
2182
+ }
1830
2183
  if (agentsForPlatform.length > 0) {
1831
2184
  process.stderr.write(
1832
2185
  `
@@ -1866,6 +2219,14 @@ You have ${String(agentsForPlatform.length)} agent(s) connected for ${selectedLa
1866
2219
  }
1867
2220
  }
1868
2221
  }
2222
+ if (selectedPlatform === "cursor" || selectedPlatform === "github-copilot") {
2223
+ const where = selectedPlatform === "cursor" ? "Cursor" : "GitHub Copilot";
2224
+ process.stderr.write(
2225
+ "\n" + style.dim(
2226
+ `Using Claude models (Sonnet, Opus, Haiku) in ${where}? The Claude Code native plugin is recommended - it governs all tool calls, not just MCP traffic. Run init again and select Claude Code.`
2227
+ ) + "\n\n"
2228
+ );
2229
+ }
1869
2230
  const prereqEntry = INIT_WIZARD_PLATFORM_REGISTRY.find((e) => e.slug === selectedPlatform);
1870
2231
  if (prereqEntry?.prereqUrl !== void 0) {
1871
2232
  const proceed = await promptHostedProxyInstallPrereq(
@@ -1881,7 +2242,7 @@ You have ${String(agentsForPlatform.length)} agent(s) connected for ${selectedLa
1881
2242
  continue;
1882
2243
  }
1883
2244
  }
1884
- const agentName = await promptAgentName(ask, selectedPlatform);
2245
+ const agentName = await promptAgentName(ask, selectedPlatform, removeAgentNameBeforeSave);
1885
2246
  let setupSucceeded = false;
1886
2247
  if (selectedPlatform === "openclaw") {
1887
2248
  let detection;
@@ -2007,7 +2368,9 @@ You have ${String(agentsForPlatform.length)} agent(s) connected for ${selectedLa
2007
2368
  ) + style.cyan("~/.multicorn/windsurf-hooks") + style.dim(" if that is a concern.") + "\n\n"
2008
2369
  );
2009
2370
  process.stderr.write(
2010
- style.dim("Restart Windsurf (quit fully, then reopen) so hooks load.") + "\n"
2371
+ style.dim(
2372
+ "Try it: make a request in Windsurf - Shield will intercept the first tool call and ask for your consent."
2373
+ ) + "\n"
2011
2374
  );
2012
2375
  configuredAgents.push({
2013
2376
  selection,
@@ -2064,7 +2427,13 @@ You have ${String(agentsForPlatform.length)} agent(s) connected for ${selectedLa
2064
2427
  if (created && proxyUrl.length > 0) {
2065
2428
  process.stderr.write("\n" + style.bold("Your Shield proxy URL:") + "\n");
2066
2429
  process.stderr.write(" " + style.cyan(proxyUrl) + "\n");
2067
- printPlatformSnippet(selectedPlatform, proxyUrl, shortName, apiKey);
2430
+ await applyHostedProxyMcpConfig(
2431
+ selectedPlatform,
2432
+ proxyUrl,
2433
+ shortName,
2434
+ apiKey,
2435
+ initWorkspacePath
2436
+ );
2068
2437
  configuredAgents.push({
2069
2438
  selection,
2070
2439
  platform: selectedPlatform,
@@ -2149,7 +2518,13 @@ You have ${String(agentsForPlatform.length)} agent(s) connected for ${selectedLa
2149
2518
  if (created && proxyUrl.length > 0) {
2150
2519
  process.stderr.write("\n" + style.bold("Your Shield proxy URL:") + "\n");
2151
2520
  process.stderr.write(" " + style.cyan(proxyUrl) + "\n");
2152
- printPlatformSnippet(selectedPlatform, proxyUrl, shortName, apiKey);
2521
+ await applyHostedProxyMcpConfig(
2522
+ selectedPlatform,
2523
+ proxyUrl,
2524
+ shortName,
2525
+ apiKey,
2526
+ initWorkspacePath
2527
+ );
2153
2528
  configuredAgents.push({
2154
2529
  selection,
2155
2530
  platform: selectedPlatform,
@@ -2228,7 +2603,13 @@ You have ${String(agentsForPlatform.length)} agent(s) connected for ${selectedLa
2228
2603
  if (created && proxyUrl.length > 0) {
2229
2604
  process.stderr.write("\n" + style.bold("Your Shield proxy URL:") + "\n");
2230
2605
  process.stderr.write(" " + style.cyan(proxyUrl) + "\n");
2231
- printPlatformSnippet(selectedPlatform, proxyUrl, shortName, apiKey);
2606
+ await applyHostedProxyMcpConfig(
2607
+ selectedPlatform,
2608
+ proxyUrl,
2609
+ shortName,
2610
+ apiKey,
2611
+ initWorkspacePath
2612
+ );
2232
2613
  configuredAgents.push({
2233
2614
  selection,
2234
2615
  platform: selectedPlatform,
@@ -2270,7 +2651,13 @@ You have ${String(agentsForPlatform.length)} agent(s) connected for ${selectedLa
2270
2651
  if (created && proxyUrl.length > 0) {
2271
2652
  process.stderr.write("\n" + style.bold("Your Shield proxy URL:") + "\n");
2272
2653
  process.stderr.write(" " + style.cyan(proxyUrl) + "\n");
2273
- printPlatformSnippet(selectedPlatform, proxyUrl, shortName, apiKey);
2654
+ await applyHostedProxyMcpConfig(
2655
+ selectedPlatform,
2656
+ proxyUrl,
2657
+ shortName,
2658
+ apiKey,
2659
+ initWorkspacePath
2660
+ );
2274
2661
  configuredAgents.push({
2275
2662
  selection,
2276
2663
  platform: selectedPlatform,
@@ -2284,7 +2671,10 @@ You have ${String(agentsForPlatform.length)} agent(s) connected for ${selectedLa
2284
2671
  }
2285
2672
  if (setupSucceeded) {
2286
2673
  if (removeAgentNameBeforeSave !== void 0) {
2287
- currentAgents = currentAgents.filter((a) => a.name !== removeAgentNameBeforeSave);
2674
+ const removeKey = agentDisplayNameDedupeKey(removeAgentNameBeforeSave);
2675
+ currentAgents = currentAgents.filter(
2676
+ (a) => agentDisplayNameDedupeKey(a.name) !== removeKey
2677
+ );
2288
2678
  }
2289
2679
  currentAgents.push({
2290
2680
  name: agentName,
@@ -2336,42 +2726,42 @@ You have ${String(agentsForPlatform.length)} agent(s) connected for ${selectedLa
2336
2726
  const blocks = [];
2337
2727
  if (configuredPlatforms.has("openclaw")) {
2338
2728
  blocks.push(
2339
- "\n" + style.bold("OpenClaw") + "\n \u2192 Restart your gateway: " + style.cyan("openclaw gateway restart") + "\n \u2192 Start a session: " + style.cyan("openclaw tui") + "\n"
2729
+ "\n" + style.bold("OpenClaw") + "\n \u2192 Restart your gateway: " + style.cyan("openclaw gateway restart") + "\n \u2192 Start a session: " + style.cyan("openclaw tui") + "\n \u2192 Try it: make a request in OpenClaw - Shield will intercept the first tool call and ask for your consent\n"
2340
2730
  );
2341
2731
  }
2342
2732
  if (configuredPlatforms.has("claude-code")) {
2343
2733
  blocks.push(
2344
- "\n" + style.bold("Claude Code") + "\n \u2192 Start Claude Code: " + style.cyan("claude") + "\n \u2192 Shield will intercept tool calls automatically.\n"
2734
+ "\n" + style.bold("Claude Code") + "\n \u2192 Start coding: run " + style.cyan("claude") + " in the terminal, or use Cursor with a Claude model - Shield hooks apply to both\n \u2192 Try it: make a request in Claude Code - Shield will intercept the first tool call and ask for your consent\n"
2345
2735
  );
2346
2736
  }
2347
2737
  if (configuredPlatforms.has("claude-desktop")) {
2348
2738
  blocks.push(
2349
- "\n" + style.bold("Claude Desktop") + "\n \u2192 Restart Claude Desktop to pick up config changes\n"
2739
+ "\n" + style.bold("Claude Desktop") + "\n \u2192 Restart Claude Desktop to pick up config changes\n \u2192 Try it: make a request in Claude Desktop - Shield will intercept the first tool call and ask for your consent\n"
2350
2740
  );
2351
2741
  }
2352
2742
  if (configuredPlatforms.has("cursor")) {
2353
2743
  blocks.push(
2354
- "\n" + style.bold("Cursor") + "\n \u2192 If needed, download Cursor from " + style.cyan("https://cursor.com/downloads") + "\n \u2192 Restart Cursor so it loads the MCP server\n \u2192 Ask the agent to use your Shield MCP tools by short name\n"
2744
+ "\n" + style.bold("Cursor") + "\n \u2192 If needed, download Cursor from " + style.cyan("https://www.cursor.com/downloads") + "\n \u2192 Restart Cursor so it loads the MCP server\n \u2192 Try it: make a request in Cursor - Shield will intercept the first tool call and ask for your consent\n"
2355
2745
  );
2356
2746
  }
2357
2747
  if (configuredPlatforms.has("kilo-code")) {
2358
2748
  blocks.push(
2359
- "\n" + style.bold("Kilo Code") + "\n \u2192 Restart the editor or reload the window if the MCP server does not appear\n \u2192 Run your next task in Kilo Code so it picks up Shield\n"
2749
+ "\n" + style.bold("Kilo Code") + "\n \u2192 Restart the editor or reload the window if the MCP server does not appear\n \u2192 Try it: make a request in Kilo Code - Shield will intercept the first tool call and ask for your consent\n"
2360
2750
  );
2361
2751
  }
2362
2752
  if (configuredPlatforms.has("github-copilot")) {
2363
2753
  blocks.push(
2364
- "\n" + style.bold("GitHub Copilot") + "\n \u2192 Reload the editor window if the MCP server does not appear\n \u2192 Use Copilot Agent mode and verify the MCP server connects\n"
2754
+ "\n" + style.bold("GitHub Copilot") + "\n \u2192 Reload the editor window if the MCP server does not appear\n \u2192 Open Copilot Agent mode and confirm the MCP server connects\n \u2192 Try it: make a request in GitHub Copilot - Shield will intercept the first tool call and ask for your consent\n"
2365
2755
  );
2366
2756
  }
2367
2757
  if (configuredPlatforms.has("continue-dev")) {
2368
2758
  blocks.push(
2369
- "\n" + style.bold("Continue") + "\n \u2192 If needed, install Continue from " + style.cyan("https://docs.continue.dev/ide-extensions/install") + "\n \u2192 Reload VS Code and open Continue agent mode\n"
2759
+ "\n" + style.bold("Continue") + "\n \u2192 If needed, install Continue from " + style.cyan("https://docs.continue.dev/ide-extensions/install") + "\n \u2192 Reload VS Code and open Continue agent mode\n \u2192 Try it: make a request in Continue - Shield will intercept the first tool call and ask for your consent\n"
2370
2760
  );
2371
2761
  }
2372
2762
  if (configuredPlatforms.has("goose")) {
2373
2763
  blocks.push(
2374
- "\n" + style.bold("Goose") + "\n \u2192 Start a new Goose session after updating config\n"
2764
+ "\n" + style.bold("Goose") + "\n \u2192 Start a new Goose session after updating config\n \u2192 Try it: make a request in Goose - Shield will intercept the first tool call and ask for your consent\n"
2375
2765
  );
2376
2766
  }
2377
2767
  const windsurfNativeConfigured = configuredAgents.some(
@@ -2382,12 +2772,12 @@ You have ${String(agentsForPlatform.length)} agent(s) connected for ${selectedLa
2382
2772
  );
2383
2773
  if (windsurfNativeConfigured) {
2384
2774
  blocks.push(
2385
- "\n" + style.bold("Windsurf (native)") + "\n \u2192 Restart Windsurf (quit fully, then reopen)\n"
2775
+ "\n" + style.bold("Windsurf (native)") + "\n \u2192 Open Windsurf (or restart if it is already running)\n \u2192 Try it: make a request in Windsurf - Shield will intercept the first tool call and ask for your consent\n"
2386
2776
  );
2387
2777
  }
2388
2778
  if (windsurfHostedConfigured) {
2389
2779
  blocks.push(
2390
- "\n" + style.bold("Windsurf (hosted)") + "\n \u2192 If needed, install from " + style.cyan("https://windsurf.com/download") + "\n \u2192 Restart Windsurf so it loads the MCP server\n"
2780
+ "\n" + style.bold("Windsurf (hosted)") + "\n \u2192 If needed, install from " + style.cyan("https://windsurf.com/download") + "\n \u2192 Restart Windsurf so it loads the MCP server\n \u2192 In Windsurf, open the three-dot menu (top-right of Cascade panel), find your Shield server at the bottom of the list, and toggle it on\n \u2192 Try it: make a request in Windsurf - Shield will intercept the first tool call and ask for your consent\n"
2391
2781
  );
2392
2782
  }
2393
2783
  const clineNativeConfigured = configuredAgents.some(
@@ -2398,12 +2788,12 @@ You have ${String(agentsForPlatform.length)} agent(s) connected for ${selectedLa
2398
2788
  );
2399
2789
  if (clineNativeConfigured) {
2400
2790
  blocks.push(
2401
- "\n" + style.bold("Cline (native)") + "\n \u2192 Enable Hooks in Cline settings (Advanced), then reload the VS Code window\n \u2192 Trigger a tool call to verify Shield is intercepting\n"
2791
+ "\n" + style.bold("Cline (native)") + "\n \u2192 In Cline, click the settings icon \u2192 Feature Settings \u2192 scroll down to Advanced \u2192 enable Hooks, then reload the VS Code window\n \u2192 Try it: make a request in Cline - Shield will intercept the first tool call and ask for your consent\n"
2402
2792
  );
2403
2793
  }
2404
2794
  if (clineHostedConfigured) {
2405
2795
  blocks.push(
2406
- "\n" + style.bold("Cline (hosted)") + "\n \u2192 Restart Cline or reload the VS Code window\n"
2796
+ "\n" + style.bold("Cline (hosted)") + "\n \u2192 Restart Cline or reload the VS Code window\n \u2192 In Cline, open server settings using the plug icon, open the Configure tab, and confirm your Shield server is listed and toggled on\n \u2192 Try it: make a request in Cline - Shield will intercept the first tool call and ask for your consent\n"
2407
2797
  );
2408
2798
  }
2409
2799
  const geminiCliNativeConfigured = configuredAgents.some(
@@ -2414,12 +2804,17 @@ You have ${String(agentsForPlatform.length)} agent(s) connected for ${selectedLa
2414
2804
  );
2415
2805
  if (geminiCliNativeConfigured) {
2416
2806
  blocks.push(
2417
- "\n" + style.bold("Gemini CLI (native)") + "\n \u2192 Restart Gemini CLI to activate Shield governance\n"
2807
+ "\n" + style.bold("Gemini CLI (native)") + "\n \u2192 Start Gemini CLI: run " + style.cyan("gemini") + " in your terminal (exit any existing session first)\n \u2192 Try it: make a request in Gemini CLI - Shield will intercept the first tool call and ask for your consent\n"
2418
2808
  );
2419
2809
  }
2420
2810
  if (geminiCliHostedConfigured) {
2421
2811
  blocks.push(
2422
- "\n" + style.bold("Gemini CLI (hosted)") + "\n \u2192 Restart Gemini CLI, then run " + style.cyan("/mcp") + " to verify the server\n"
2812
+ "\n" + style.bold("Gemini CLI (hosted)") + "\n \u2192 Try it: make a request in Gemini CLI - Shield will intercept the first tool call and ask for your consent\n"
2813
+ );
2814
+ }
2815
+ if (configuredPlatforms.has("other-mcp")) {
2816
+ blocks.push(
2817
+ "\n" + style.bold("Local MCP / Other") + "\n \u2192 Run your configured wrap command (for example " + style.cyan("npx multicorn-shield --wrap ...") + ")\n \u2192 Try it: make a request in your coding agent - Shield will intercept the first tool call and ask for your consent\n"
2423
2818
  );
2424
2819
  }
2425
2820
  if (blocks.length > 0) {
@@ -2436,10 +2831,11 @@ You have ${String(agentsForPlatform.length)} agent(s) connected for ${selectedLa
2436
2831
  }
2437
2832
  return lastConfig;
2438
2833
  }
2439
- 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_SHIELD_API_BASE_URL;
2834
+ var SECRET_JSON_FILE_OPTIONS, 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_SHIELD_API_BASE_URL;
2440
2835
  var init_config = __esm({
2441
2836
  "src/proxy/config.ts"() {
2442
2837
  init_consent();
2838
+ SECRET_JSON_FILE_OPTIONS = { encoding: "utf8", mode: 384 };
2443
2839
  style = {
2444
2840
  violet: (s) => `\x1B[38;2;124;58;237m${s}\x1B[0m`,
2445
2841
  violetLight: (s) => `\x1B[38;2;167;139;250m${s}\x1B[0m`,
@@ -3448,7 +3844,10 @@ async function restoreClaudeDesktopMcpFromBackup() {
3448
3844
  }
3449
3845
  root["mcpServers"] = backup.mcpServers;
3450
3846
  await mkdir(dirname(configPath), { recursive: true });
3451
- await writeFile(configPath, JSON.stringify(root, null, 2) + "\n", { encoding: "utf8" });
3847
+ await writeFile(configPath, JSON.stringify(root, null, 2) + "\n", {
3848
+ encoding: "utf8",
3849
+ mode: 384
3850
+ });
3452
3851
  }
3453
3852
  var init_restore = __esm({
3454
3853
  "src/extension/restore.ts"() {
@@ -3475,6 +3874,7 @@ function parseArgs(argv) {
3475
3874
  let agentName = "";
3476
3875
  let deleteAgentName = "";
3477
3876
  let apiKey = void 0;
3877
+ let verbose = false;
3478
3878
  for (let i = 0; i < args.length; i++) {
3479
3879
  const arg = args[i];
3480
3880
  if (arg === "init") {
@@ -3574,6 +3974,8 @@ function parseArgs(argv) {
3574
3974
  apiKey = next;
3575
3975
  i++;
3576
3976
  }
3977
+ } else if (arg === "--verbose" || arg === "--debug") {
3978
+ verbose = true;
3577
3979
  }
3578
3980
  }
3579
3981
  return {
@@ -3585,7 +3987,8 @@ function parseArgs(argv) {
3585
3987
  dashboardUrl,
3586
3988
  agentName,
3587
3989
  deleteAgentName,
3588
- apiKey
3990
+ apiKey,
3991
+ verbose
3589
3992
  };
3590
3993
  }
3591
3994
  function printHelp() {
@@ -3611,6 +4014,7 @@ function printHelp() {
3611
4014
  " Shield's permission layer.",
3612
4015
  "",
3613
4016
  "Options:",
4017
+ " --verbose, --debug Print extra diagnostics during init (menu selection, agent counts)",
3614
4018
  " --api-key <key> Multicorn API key (overrides MULTICORN_API_KEY env var and config file)",
3615
4019
  " --log-level <level> Log level: debug | info | warn | error (default: info)",
3616
4020
  " --base-url <url> Multicorn API base URL (default: https://api.multicorn.ai)",
@@ -3641,7 +4045,7 @@ async function runCli() {
3641
4045
  process.exit(0);
3642
4046
  }
3643
4047
  if (cli.subcommand === "init") {
3644
- await runInit(cli.baseUrl);
4048
+ await runInit(cli.baseUrl, { verbose: cli.verbose });
3645
4049
  return;
3646
4050
  }
3647
4051
  if (cli.subcommand === "agents") {