multicorn-shield 1.4.0 → 1.6.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 CHANGED
@@ -9,6 +9,35 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
9
9
 
10
10
  - Bump `version` in `package.json` before publishing to npm.
11
11
 
12
+ ## [1.5.0] - 2026-05-10
13
+
14
+ ### Added
15
+
16
+ - Claude Code promotion note when selecting Cursor in the CLI
17
+ - Example usage prompt in CLI "Next steps" output
18
+ - `--version` flag prints version number and exits
19
+ - Consent-required errors now display a clear multi-line message with the approval URL on its own line
20
+
21
+ ### Changed
22
+
23
+ - Auth prompt detects token pasted at the y/N confirmation and treats it as the token value directly
24
+ - Single-item arrow select skips the interactive picker and selects immediately
25
+ - Blocked response message reformatted for clarity
26
+
27
+ ### Fixed
28
+
29
+ - Hosted proxy blocks `.well-known` OAuth discovery probes to prevent `mcp-remote` entering OAuth mode
30
+
31
+ ## [1.4.1] - 2026-05-09
32
+
33
+ ### Changed
34
+
35
+ - Upstream auth prompt accepts a raw API token (`Bearer` added automatically) or a full Authorization-style value (`Bearer`, `Basic`, `Token`, `ApiKey` prefixes are passed through unchanged)
36
+
37
+ ### Fixed
38
+
39
+ - CLI replace flow no longer shows duplicate agent entries
40
+
12
41
  ## [1.4.0] - 2026-05-08
13
42
 
14
43
  ### Added
@@ -420,6 +420,17 @@ function stripAnsi(str) {
420
420
  function normalizeAgentName(raw) {
421
421
  return raw.toLowerCase().replace(/\s+/g, "-").replace(/[^a-z0-9-]/g, "").replace(/-{2,}/g, "-").replace(/^-+|-+$/g, "").slice(0, 50);
422
422
  }
423
+ function formatUpstreamAuthorizationBearerHeader(raw) {
424
+ const t = raw.trim();
425
+ if (t.length === 0) return void 0;
426
+ if (UPSTREAM_AUTH_KNOWN_SCHEME_WITH_PAYLOAD.test(t)) {
427
+ return t;
428
+ }
429
+ if (/^(Bearer|Basic|Token|ApiKey)$/i.test(t)) {
430
+ return void 0;
431
+ }
432
+ return `Bearer ${t}`;
433
+ }
423
434
  function isErrnoException(e) {
424
435
  return typeof e === "object" && e !== null && "code" in e;
425
436
  }
@@ -1400,6 +1411,12 @@ async function promptWindsurfIntegrationMode(ask) {
1400
1411
  return choice === 1 ? "native" : "hosted";
1401
1412
  }
1402
1413
  async function arrowSelect(options, ask, fallbackLabel) {
1414
+ if (options.length === 1) {
1415
+ const only = options[0] ?? "";
1416
+ process.stderr.write(`${style.violet("\u276F")} ${style.cyan(only)}
1417
+ `);
1418
+ return 0;
1419
+ }
1403
1420
  const canRaw = process.stdin.isTTY && typeof process.stdin.setRawMode === "function";
1404
1421
  if (!canRaw) {
1405
1422
  for (let i = 0; i < options.length; i++) {
@@ -1452,7 +1469,7 @@ async function arrowSelect(options, ask, fallbackLabel) {
1452
1469
  cleanup();
1453
1470
  clearLines();
1454
1471
  const chosen = options.at(idx);
1455
- if (chosen !== void 0) {
1472
+ if (chosen !== void 0 && options.length > 1) {
1456
1473
  process.stderr.write(`${style.violet("\u276F")} ${style.cyan(chosen)}
1457
1474
  `);
1458
1475
  }
@@ -1534,12 +1551,12 @@ async function promptProxyConfig(ask, agentName) {
1534
1551
  let upstreamHeaders;
1535
1552
  if (wantsAuth) {
1536
1553
  process.stderr.write(
1537
- "\n" + style.bold("Enter the Authorization header value.") + "\n" + style.dim(" For Bearer tokens: Bearer ghp_xxxxxxxxxxxx") + "\n" + style.dim(" For API keys: Bearer sk-xxxxxxxxxxxx") + "\n"
1554
+ "\n" + style.bold("Enter your API token or full Authorization header value.") + "\n" + style.dim(" Bearer tokens: ghp_xxxxxxxxxxxx (Bearer is added automatically)") + "\n" + style.dim(" Other schemes: Basic dXNlcjpwYXNz (passed as-is)") + "\n"
1538
1555
  );
1539
1556
  const headerVal = await ask("Value: ");
1540
- const trimmed = headerVal.trim();
1541
- if (trimmed.length > 0) {
1542
- upstreamHeaders = { Authorization: trimmed };
1557
+ const authHeader = formatUpstreamAuthorizationBearerHeader(headerVal);
1558
+ if (authHeader !== void 0) {
1559
+ upstreamHeaders = { Authorization: authHeader };
1543
1560
  }
1544
1561
  }
1545
1562
  return {
@@ -2064,7 +2081,7 @@ function printPlatformSnippet(platform, routingToken, shortName, apiKey) {
2064
2081
  }
2065
2082
  }
2066
2083
  function agentDisplayNameDedupeKey(name) {
2067
- return name.trim().toLowerCase();
2084
+ return name.trim().normalize("NFKC").toLowerCase();
2068
2085
  }
2069
2086
  function normalizeAgentEntryForMerge(a) {
2070
2087
  const name = a.name.trim();
@@ -2291,6 +2308,9 @@ You have ${String(agentsForPlatform.length)} agent(s) connected for ${selectedLa
2291
2308
  const victim = agentsForPlatform[replaceIdx];
2292
2309
  if (victim !== void 0) {
2293
2310
  removeAgentNameBeforeSave = victim.name;
2311
+ process.stderr.write(
2312
+ "\n" + style.dim("Replacing agent ") + style.cyan(victim.name) + style.dim("...") + "\n"
2313
+ );
2294
2314
  }
2295
2315
  }
2296
2316
  }
@@ -2799,6 +2819,14 @@ You have ${String(agentsForPlatform.length)} agent(s) connected for ${selectedLa
2799
2819
  }
2800
2820
  rl.close();
2801
2821
  if (configuredAgents.length > 0) {
2822
+ let mcpPromptLabel2 = function(platformSlug) {
2823
+ const rows = configuredAgents.filter((a) => a.platform === platformSlug);
2824
+ const last = rows[rows.length - 1];
2825
+ if (last === void 0) return "shield-mcp";
2826
+ const s = typeof last.shortName === "string" ? last.shortName.trim() : "";
2827
+ if (s.length > 0) return s;
2828
+ return last.agentName.trim().length > 0 ? last.agentName.trim() : "shield-mcp";
2829
+ };
2802
2830
  process.stderr.write("\n" + style.bold(style.violet("Setup complete")) + "\n\n");
2803
2831
  for (const agent of configuredAgents) {
2804
2832
  const namePart = agent.agentName.length > 0 ? ` - ${style.cyan(agent.agentName)}` : "";
@@ -2822,13 +2850,15 @@ You have ${String(agentsForPlatform.length)} agent(s) connected for ${selectedLa
2822
2850
  );
2823
2851
  }
2824
2852
  if (configuredPlatforms.has("claude-desktop")) {
2853
+ const cdLabel = mcpPromptLabel2("claude-desktop");
2825
2854
  blocks.push(
2826
- "\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"
2855
+ "\n" + style.bold("Claude Desktop") + '\n \u2192 Restart Claude Desktop to load the updated configuration\n \u2192 Confirm connection: click your profile (bottom-left) \u2192 Settings \u2192 Developer\n Check that "' + cdLabel + '" shows a green "running" status\n \u2192 Try it: paste this into Claude Desktop:\n "Use the ' + cdLabel + ' MCP server to list my GitHub repositories"\n'
2827
2856
  );
2828
2857
  }
2829
2858
  if (configuredPlatforms.has("cursor")) {
2859
+ const cursorLabel = mcpPromptLabel2("cursor");
2830
2860
  blocks.push(
2831
- "\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"
2861
+ "\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 Confirm connection: open Settings \u2192 Tools & MCPs\n Check that "' + cursorLabel + '" shows a green status indicator\n \u2192 Try it: paste this into Cursor:\n "Use the ' + cursorLabel + ' MCP server to list my GitHub repositories"\n'
2832
2862
  );
2833
2863
  }
2834
2864
  if (configuredPlatforms.has("kilo-code")) {
@@ -2918,7 +2948,7 @@ You have ${String(agentsForPlatform.length)} agent(s) connected for ${selectedLa
2918
2948
  }
2919
2949
  return lastConfig;
2920
2950
  }
2921
- 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, HOSTED_PROXY_PLATFORMS_WITH_URL_KEY, DEFAULT_SHIELD_API_BASE_URL;
2951
+ var SECRET_JSON_FILE_OPTIONS, style, BANNER, NativePluginPrerequisiteMissingError, CONFIG_DIR, CONFIG_PATH, OPENCLAW_CONFIG_PATH, ANSI_PATTERN, UPSTREAM_AUTH_KNOWN_SCHEME_WITH_PAYLOAD, OPENCLAW_MIN_VERSION, INIT_WIZARD_PLATFORM_REGISTRY, INIT_WIZARD_MENU_SECTIONS, INIT_WIZARD_SELECTION_MAX, PLATFORM_BY_SELECTION, HOSTED_PROXY_PLATFORMS_WITH_URL_KEY, DEFAULT_SHIELD_API_BASE_URL;
2922
2952
  var init_config = __esm({
2923
2953
  "src/proxy/config.ts"() {
2924
2954
  init_consent();
@@ -2950,6 +2980,7 @@ var init_config = __esm({
2950
2980
  CONFIG_PATH = join(CONFIG_DIR, "config.json");
2951
2981
  OPENCLAW_CONFIG_PATH = join(homedir(), ".openclaw", "openclaw.json");
2952
2982
  ANSI_PATTERN = new RegExp(String.fromCharCode(27) + "\\[[0-9;]*[a-zA-Z]", "g");
2983
+ UPSTREAM_AUTH_KNOWN_SCHEME_WITH_PAYLOAD = /^(Bearer|Basic|Token|ApiKey)(\s+)(.+)$/is;
2953
2984
  OPENCLAW_MIN_VERSION = "2026.2.26";
2954
2985
  INIT_WIZARD_PLATFORM_REGISTRY = [
2955
2986
  { slug: "openclaw", displayName: "OpenClaw", section: "native" },
@@ -3415,9 +3446,13 @@ function extractToolCallParams(request) {
3415
3446
  if (typeof args !== "object" || args === null) return null;
3416
3447
  return { name, arguments: args };
3417
3448
  }
3418
- function buildBlockedResponse(id, service, permissionLevel, dashboardUrl) {
3449
+ function buildBlockedResponse(id, service, _permissionLevel, dashboardUrl) {
3419
3450
  const displayService = capitalize(service);
3420
- const message = `Action blocked by Multicorn Shield: agent does not have ${permissionLevel} access to ${displayService}. Configure permissions at ${dashboardUrl}`;
3451
+ const message = `Action blocked by Shield
3452
+
3453
+ This agent cannot use ${displayService}.
3454
+
3455
+ Configure permissions: ${dashboardUrl}`;
3421
3456
  return {
3422
3457
  jsonrpc: "2.0",
3423
3458
  id,
@@ -3951,6 +3986,192 @@ var init_restore = __esm({
3951
3986
  }
3952
3987
  });
3953
3988
 
3989
+ // package.json
3990
+ var package_default;
3991
+ var init_package = __esm({
3992
+ "package.json"() {
3993
+ package_default = {
3994
+ name: "multicorn-shield",
3995
+ version: "1.6.0",
3996
+ description: "The control layer for AI agents: permissions, consent, spending limits, and audit logging.",
3997
+ license: "MIT",
3998
+ author: "Multicorn AI Pty Ltd",
3999
+ type: "module",
4000
+ main: "./dist/index.cjs",
4001
+ module: "./dist/index.js",
4002
+ types: "./dist/index.d.ts",
4003
+ exports: {
4004
+ ".": {
4005
+ import: {
4006
+ types: "./dist/index.d.ts",
4007
+ default: "./dist/index.js"
4008
+ },
4009
+ require: {
4010
+ types: "./dist/index.d.cts",
4011
+ default: "./dist/index.cjs"
4012
+ }
4013
+ },
4014
+ "./proxy": {
4015
+ import: {
4016
+ types: "./dist/proxy.d.ts",
4017
+ default: "./dist/proxy.js"
4018
+ },
4019
+ require: {
4020
+ types: "./dist/proxy.d.cts",
4021
+ default: "./dist/proxy.cjs"
4022
+ }
4023
+ }
4024
+ },
4025
+ bin: {
4026
+ "multicorn-shield": "./dist/multicorn-shield.js",
4027
+ "multicorn-proxy": "./dist/multicorn-proxy.js"
4028
+ },
4029
+ files: [
4030
+ "dist",
4031
+ "plugins/multicorn-shield",
4032
+ "plugins/windsurf",
4033
+ "plugins/cline",
4034
+ "plugins/gemini-cli",
4035
+ "LICENSE",
4036
+ "README.md",
4037
+ "CHANGELOG.md"
4038
+ ],
4039
+ publishConfig: {
4040
+ access: "public",
4041
+ provenance: true
4042
+ },
4043
+ sideEffects: [
4044
+ "dist/index.js",
4045
+ "dist/index.cjs",
4046
+ "dist/badge.js",
4047
+ "src/badge/multicorn-badge.ts"
4048
+ ],
4049
+ engines: {
4050
+ node: ">=20"
4051
+ },
4052
+ scripts: {
4053
+ build: "tsup",
4054
+ dev: "tsup --watch",
4055
+ lint: "eslint . --no-warn-ignored && prettier --check .",
4056
+ "lint:fix": "eslint --fix . --no-warn-ignored && prettier --write .",
4057
+ test: "vitest run",
4058
+ "test:watch": "vitest",
4059
+ "test:coverage": "vitest run --coverage",
4060
+ typecheck: "tsc --noEmit",
4061
+ docs: "typedoc",
4062
+ clean: "rm -rf dist coverage docs/api extension-pack",
4063
+ "stage-extension-pack": "rm -rf extension-pack && mkdir -p extension-pack/server && cp manifest.json extension-pack/ && cp icon.png extension-pack/ && cp dist/shield-extension.js extension-pack/server/index.js",
4064
+ "validate:extension": "pnpm run stage-extension-pack && mcpb validate extension-pack/manifest.json",
4065
+ "build:extension": "tsup",
4066
+ "pack:extension": "pnpm run build && pnpm run stage-extension-pack && mcpb validate extension-pack/manifest.json && mcpb pack extension-pack dist/multicorn-shield.mcpb",
4067
+ size: "size-limit",
4068
+ prepublishOnly: "pnpm run clean && pnpm run typecheck && pnpm run lint && pnpm run test && pnpm run build",
4069
+ prepare: "husky || true",
4070
+ "release:patch": "npm version patch && pnpm publish",
4071
+ "release:minor": "npm version minor && pnpm publish",
4072
+ "release:major": "npm version major && pnpm publish"
4073
+ },
4074
+ "lint-staged": {
4075
+ "*.ts": [
4076
+ "eslint --fix --no-warn-ignored",
4077
+ "prettier --write"
4078
+ ],
4079
+ "*.{json,md}": [
4080
+ "prettier --write"
4081
+ ]
4082
+ },
4083
+ dependencies: {
4084
+ "@modelcontextprotocol/sdk": "^1.27.1",
4085
+ lit: "^3.2.0",
4086
+ zod: "^4.3.6"
4087
+ },
4088
+ devDependencies: {
4089
+ "@anthropic-ai/mcpb": "^2.1.2",
4090
+ "@eslint/js": "^9.19.0",
4091
+ "@open-wc/testing-helpers": "^3.0.1",
4092
+ "@size-limit/file": "^11.1.6",
4093
+ "@types/node": "^22.0.0",
4094
+ "@vitest/coverage-v8": "^3.0.5",
4095
+ eslint: "^9.19.0",
4096
+ "eslint-config-prettier": "^10.0.1",
4097
+ "eslint-plugin-unicorn": "^57.0.0",
4098
+ globals: "^15.14.0",
4099
+ husky: "^9.1.7",
4100
+ jiti: "^2.4.2",
4101
+ jsdom: "^25.0.1",
4102
+ "lint-staged": "^16.2.7",
4103
+ prettier: "^3.4.2",
4104
+ "size-limit": "^11.1.6",
4105
+ tsup: "^8.3.6",
4106
+ typedoc: "^0.28.17",
4107
+ typescript: "^5.7.3",
4108
+ "typescript-eslint": "^8.22.0",
4109
+ vite: "^7.3.2",
4110
+ vitest: "^3.0.5"
4111
+ },
4112
+ "size-limit": [
4113
+ {
4114
+ path: "dist/index.js",
4115
+ limit: "50 kB",
4116
+ gzip: true
4117
+ },
4118
+ {
4119
+ path: "dist/index.cjs",
4120
+ limit: "50 kB",
4121
+ gzip: true
4122
+ },
4123
+ {
4124
+ path: "dist/badge.js",
4125
+ limit: "5 kB",
4126
+ gzip: true
4127
+ }
4128
+ ],
4129
+ keywords: [
4130
+ "ai",
4131
+ "agents",
4132
+ "permissions",
4133
+ "sdk",
4134
+ "typescript",
4135
+ "consent",
4136
+ "spending-limits",
4137
+ "audit-log",
4138
+ "mcp",
4139
+ "shield",
4140
+ "multicorn"
4141
+ ],
4142
+ repository: {
4143
+ type: "git",
4144
+ url: "git+https://github.com/Multicorn-AI/multicorn-shield.git"
4145
+ },
4146
+ bugs: {
4147
+ url: "https://github.com/Multicorn-AI/multicorn-shield/issues"
4148
+ },
4149
+ homepage: "https://multicorn.ai",
4150
+ pnpm: {
4151
+ overrides: {
4152
+ vite: ">=7.3.2",
4153
+ flatted: ">=3.4.2",
4154
+ minimatch: ">=10.2.3",
4155
+ rollup: ">=4.59.0",
4156
+ picomatch: ">=4.0.4",
4157
+ "path-to-regexp": ">=8.4.0",
4158
+ "node-forge": ">=1.4.0",
4159
+ "fast-uri": ">=3.1.2"
4160
+ }
4161
+ }
4162
+ };
4163
+ }
4164
+ });
4165
+
4166
+ // src/package-meta.ts
4167
+ var PACKAGE_VERSION;
4168
+ var init_package_meta = __esm({
4169
+ "src/package-meta.ts"() {
4170
+ init_package();
4171
+ PACKAGE_VERSION = package_default.version;
4172
+ }
4173
+ });
4174
+
3954
4175
  // bin/multicorn-shield.ts
3955
4176
  var multicorn_shield_exports = {};
3956
4177
  __export(multicorn_shield_exports, {
@@ -4109,6 +4330,7 @@ function printHelp() {
4109
4330
  " Shield's permission layer.",
4110
4331
  "",
4111
4332
  "Options:",
4333
+ " --version, -v Print version and exit",
4112
4334
  " --verbose, --debug Print extra diagnostics during init (menu selection, agent counts)",
4113
4335
  " --api-key <key> Multicorn API key (overrides MULTICORN_API_KEY env var and config file)",
4114
4336
  " --log-level <level> Log level: debug | info | warn | error (default: info)",
@@ -4133,6 +4355,11 @@ async function runCli() {
4133
4355
  );
4134
4356
  return;
4135
4357
  }
4358
+ if (first === "--version" || first === "-v") {
4359
+ process.stdout.write(`${PACKAGE_VERSION}
4360
+ `);
4361
+ process.exit(0);
4362
+ }
4136
4363
  const cli = parseArgs(process.argv);
4137
4364
  const logger = createLogger(cli.logLevel);
4138
4365
  if (cli.subcommand === "help") {
@@ -4279,6 +4506,7 @@ var init_multicorn_shield = __esm({
4279
4506
  init_logger();
4280
4507
  init_consent();
4281
4508
  init_restore();
4509
+ init_package_meta();
4282
4510
  isDirectRun = process.argv[1] !== void 0 && (import.meta.url.endsWith(process.argv[1]) || import.meta.url === `file://${process.argv[1]}` || import.meta.url.endsWith("/multicorn-shield.js") || import.meta.url.endsWith("/multicorn-shield.ts"));
4283
4511
  if (isDirectRun && process.env["VITEST"] === void 0) {
4284
4512
  runCli().catch((error) => {
@@ -432,6 +432,18 @@ function stripAnsi(str) {
432
432
  function normalizeAgentName(raw) {
433
433
  return raw.toLowerCase().replace(/\s+/g, "-").replace(/[^a-z0-9-]/g, "").replace(/-{2,}/g, "-").replace(/^-+|-+$/g, "").slice(0, 50);
434
434
  }
435
+ var UPSTREAM_AUTH_KNOWN_SCHEME_WITH_PAYLOAD = /^(Bearer|Basic|Token|ApiKey)(\s+)(.+)$/is;
436
+ function formatUpstreamAuthorizationBearerHeader(raw) {
437
+ const t = raw.trim();
438
+ if (t.length === 0) return void 0;
439
+ if (UPSTREAM_AUTH_KNOWN_SCHEME_WITH_PAYLOAD.test(t)) {
440
+ return t;
441
+ }
442
+ if (/^(Bearer|Basic|Token|ApiKey)$/i.test(t)) {
443
+ return void 0;
444
+ }
445
+ return `Bearer ${t}`;
446
+ }
435
447
  function isErrnoException(e) {
436
448
  return typeof e === "object" && e !== null && "code" in e;
437
449
  }
@@ -1471,6 +1483,12 @@ async function promptWindsurfIntegrationMode(ask) {
1471
1483
  return choice === 1 ? "native" : "hosted";
1472
1484
  }
1473
1485
  async function arrowSelect(options, ask, fallbackLabel) {
1486
+ if (options.length === 1) {
1487
+ const only = options[0] ?? "";
1488
+ process.stderr.write(`${style.violet("\u276F")} ${style.cyan(only)}
1489
+ `);
1490
+ return 0;
1491
+ }
1474
1492
  const canRaw = process.stdin.isTTY && typeof process.stdin.setRawMode === "function";
1475
1493
  if (!canRaw) {
1476
1494
  for (let i = 0; i < options.length; i++) {
@@ -1523,7 +1541,7 @@ async function arrowSelect(options, ask, fallbackLabel) {
1523
1541
  cleanup();
1524
1542
  clearLines();
1525
1543
  const chosen = options.at(idx);
1526
- if (chosen !== void 0) {
1544
+ if (chosen !== void 0 && options.length > 1) {
1527
1545
  process.stderr.write(`${style.violet("\u276F")} ${style.cyan(chosen)}
1528
1546
  `);
1529
1547
  }
@@ -1605,12 +1623,12 @@ async function promptProxyConfig(ask, agentName) {
1605
1623
  let upstreamHeaders;
1606
1624
  if (wantsAuth) {
1607
1625
  process.stderr.write(
1608
- "\n" + style.bold("Enter the Authorization header value.") + "\n" + style.dim(" For Bearer tokens: Bearer ghp_xxxxxxxxxxxx") + "\n" + style.dim(" For API keys: Bearer sk-xxxxxxxxxxxx") + "\n"
1626
+ "\n" + style.bold("Enter your API token or full Authorization header value.") + "\n" + style.dim(" Bearer tokens: ghp_xxxxxxxxxxxx (Bearer is added automatically)") + "\n" + style.dim(" Other schemes: Basic dXNlcjpwYXNz (passed as-is)") + "\n"
1609
1627
  );
1610
1628
  const headerVal = await ask("Value: ");
1611
- const trimmed = headerVal.trim();
1612
- if (trimmed.length > 0) {
1613
- upstreamHeaders = { Authorization: trimmed };
1629
+ const authHeader = formatUpstreamAuthorizationBearerHeader(headerVal);
1630
+ if (authHeader !== void 0) {
1631
+ upstreamHeaders = { Authorization: authHeader };
1614
1632
  }
1615
1633
  }
1616
1634
  return {
@@ -2143,7 +2161,7 @@ function printPlatformSnippet(platform, routingToken, shortName, apiKey) {
2143
2161
  }
2144
2162
  }
2145
2163
  function agentDisplayNameDedupeKey(name) {
2146
- return name.trim().toLowerCase();
2164
+ return name.trim().normalize("NFKC").toLowerCase();
2147
2165
  }
2148
2166
  function normalizeAgentEntryForMerge(a) {
2149
2167
  const name = a.name.trim();
@@ -2371,6 +2389,9 @@ You have ${String(agentsForPlatform.length)} agent(s) connected for ${selectedLa
2371
2389
  const victim = agentsForPlatform[replaceIdx];
2372
2390
  if (victim !== void 0) {
2373
2391
  removeAgentNameBeforeSave = victim.name;
2392
+ process.stderr.write(
2393
+ "\n" + style.dim("Replacing agent ") + style.cyan(victim.name) + style.dim("...") + "\n"
2394
+ );
2374
2395
  }
2375
2396
  }
2376
2397
  }
@@ -2879,6 +2900,14 @@ You have ${String(agentsForPlatform.length)} agent(s) connected for ${selectedLa
2879
2900
  }
2880
2901
  rl.close();
2881
2902
  if (configuredAgents.length > 0) {
2903
+ let mcpPromptLabel2 = function(platformSlug) {
2904
+ const rows = configuredAgents.filter((a) => a.platform === platformSlug);
2905
+ const last = rows[rows.length - 1];
2906
+ if (last === void 0) return "shield-mcp";
2907
+ const s = typeof last.shortName === "string" ? last.shortName.trim() : "";
2908
+ if (s.length > 0) return s;
2909
+ return last.agentName.trim().length > 0 ? last.agentName.trim() : "shield-mcp";
2910
+ };
2882
2911
  process.stderr.write("\n" + style.bold(style.violet("Setup complete")) + "\n\n");
2883
2912
  for (const agent of configuredAgents) {
2884
2913
  const namePart = agent.agentName.length > 0 ? ` - ${style.cyan(agent.agentName)}` : "";
@@ -2902,13 +2931,15 @@ You have ${String(agentsForPlatform.length)} agent(s) connected for ${selectedLa
2902
2931
  );
2903
2932
  }
2904
2933
  if (configuredPlatforms.has("claude-desktop")) {
2934
+ const cdLabel = mcpPromptLabel2("claude-desktop");
2905
2935
  blocks.push(
2906
- "\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"
2936
+ "\n" + style.bold("Claude Desktop") + '\n \u2192 Restart Claude Desktop to load the updated configuration\n \u2192 Confirm connection: click your profile (bottom-left) \u2192 Settings \u2192 Developer\n Check that "' + cdLabel + '" shows a green "running" status\n \u2192 Try it: paste this into Claude Desktop:\n "Use the ' + cdLabel + ' MCP server to list my GitHub repositories"\n'
2907
2937
  );
2908
2938
  }
2909
2939
  if (configuredPlatforms.has("cursor")) {
2940
+ const cursorLabel = mcpPromptLabel2("cursor");
2910
2941
  blocks.push(
2911
- "\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"
2942
+ "\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 Confirm connection: open Settings \u2192 Tools & MCPs\n Check that "' + cursorLabel + '" shows a green status indicator\n \u2192 Try it: paste this into Cursor:\n "Use the ' + cursorLabel + ' MCP server to list my GitHub repositories"\n'
2912
2943
  );
2913
2944
  }
2914
2945
  if (configuredPlatforms.has("kilo-code")) {
@@ -3374,9 +3405,13 @@ function extractToolCallParams(request) {
3374
3405
  if (typeof args !== "object" || args === null) return null;
3375
3406
  return { name, arguments: args };
3376
3407
  }
3377
- function buildBlockedResponse(id, service, permissionLevel, dashboardUrl) {
3408
+ function buildBlockedResponse(id, service, _permissionLevel, dashboardUrl) {
3378
3409
  const displayService = capitalize(service);
3379
- const message = `Action blocked by Multicorn Shield: agent does not have ${permissionLevel} access to ${displayService}. Configure permissions at ${dashboardUrl}`;
3410
+ const message = `Action blocked by Shield
3411
+
3412
+ This agent cannot use ${displayService}.
3413
+
3414
+ Configure permissions: ${dashboardUrl}`;
3380
3415
  return {
3381
3416
  jsonrpc: "2.0",
3382
3417
  id,
@@ -3878,6 +3913,13 @@ async function restoreClaudeDesktopMcpFromBackup() {
3878
3913
  });
3879
3914
  }
3880
3915
 
3916
+ // package.json
3917
+ var package_default = {
3918
+ version: "1.6.0"};
3919
+
3920
+ // src/package-meta.ts
3921
+ var PACKAGE_VERSION = package_default.version;
3922
+
3881
3923
  // bin/multicorn-shield.ts
3882
3924
  function parseArgs(argv) {
3883
3925
  const args = argv.slice(2);
@@ -4030,6 +4072,7 @@ function printHelp() {
4030
4072
  " Shield's permission layer.",
4031
4073
  "",
4032
4074
  "Options:",
4075
+ " --version, -v Print version and exit",
4033
4076
  " --verbose, --debug Print extra diagnostics during init (menu selection, agent counts)",
4034
4077
  " --api-key <key> Multicorn API key (overrides MULTICORN_API_KEY env var and config file)",
4035
4078
  " --log-level <level> Log level: debug | info | warn | error (default: info)",
@@ -4054,6 +4097,11 @@ async function runCli() {
4054
4097
  );
4055
4098
  return;
4056
4099
  }
4100
+ if (first === "--version" || first === "-v") {
4101
+ process.stdout.write(`${PACKAGE_VERSION}
4102
+ `);
4103
+ process.exit(0);
4104
+ }
4057
4105
  const cli = parseArgs(process.argv);
4058
4106
  const logger = createLogger(cli.logLevel);
4059
4107
  if (cli.subcommand === "help") {
package/dist/proxy.cjs CHANGED
@@ -30,9 +30,13 @@ function extractToolCallParams(request) {
30
30
  if (typeof args !== "object" || args === null) return null;
31
31
  return { name, arguments: args };
32
32
  }
33
- function buildBlockedResponse(id, service, permissionLevel, dashboardUrl) {
33
+ function buildBlockedResponse(id, service, _permissionLevel, dashboardUrl) {
34
34
  const displayService = capitalize(service);
35
- const message = `Action blocked by Multicorn Shield: agent does not have ${permissionLevel} access to ${displayService}. Configure permissions at ${dashboardUrl}`;
35
+ const message = `Action blocked by Shield
36
+
37
+ This agent cannot use ${displayService}.
38
+
39
+ Configure permissions: ${dashboardUrl}`;
36
40
  return {
37
41
  jsonrpc: "2.0",
38
42
  id,
package/dist/proxy.d.cts CHANGED
@@ -31,7 +31,7 @@ interface ToolCallParams {
31
31
  }
32
32
  declare function parseJsonRpcLine(line: string): JsonRpcRequest | null;
33
33
  declare function extractToolCallParams(request: JsonRpcRequest): ToolCallParams | null;
34
- declare function buildBlockedResponse(id: string | number | null, service: string, permissionLevel: string, dashboardUrl: string): JsonRpcResponse;
34
+ declare function buildBlockedResponse(id: string | number | null, service: string, _permissionLevel: string, dashboardUrl: string): JsonRpcResponse;
35
35
  declare function buildSpendingBlockedResponse(id: string | number | null, reason: string, dashboardUrl: string): JsonRpcResponse;
36
36
  /**
37
37
  * Internal error: Shield could not verify permissions due to an exception.
package/dist/proxy.d.ts CHANGED
@@ -31,7 +31,7 @@ interface ToolCallParams {
31
31
  }
32
32
  declare function parseJsonRpcLine(line: string): JsonRpcRequest | null;
33
33
  declare function extractToolCallParams(request: JsonRpcRequest): ToolCallParams | null;
34
- declare function buildBlockedResponse(id: string | number | null, service: string, permissionLevel: string, dashboardUrl: string): JsonRpcResponse;
34
+ declare function buildBlockedResponse(id: string | number | null, service: string, _permissionLevel: string, dashboardUrl: string): JsonRpcResponse;
35
35
  declare function buildSpendingBlockedResponse(id: string | number | null, reason: string, dashboardUrl: string): JsonRpcResponse;
36
36
  /**
37
37
  * Internal error: Shield could not verify permissions due to an exception.
package/dist/proxy.js CHANGED
@@ -28,9 +28,13 @@ function extractToolCallParams(request) {
28
28
  if (typeof args !== "object" || args === null) return null;
29
29
  return { name, arguments: args };
30
30
  }
31
- function buildBlockedResponse(id, service, permissionLevel, dashboardUrl) {
31
+ function buildBlockedResponse(id, service, _permissionLevel, dashboardUrl) {
32
32
  const displayService = capitalize(service);
33
- const message = `Action blocked by Multicorn Shield: agent does not have ${permissionLevel} access to ${displayService}. Configure permissions at ${dashboardUrl}`;
33
+ const message = `Action blocked by Shield
34
+
35
+ This agent cannot use ${displayService}.
36
+
37
+ Configure permissions: ${dashboardUrl}`;
34
38
  return {
35
39
  jsonrpc: "2.0",
36
40
  id,
@@ -3090,11 +3090,14 @@ var require_data = __commonJS({
3090
3090
  }
3091
3091
  });
3092
3092
 
3093
- // node_modules/.pnpm/fast-uri@3.1.0/node_modules/fast-uri/lib/utils.js
3093
+ // node_modules/.pnpm/fast-uri@3.1.2/node_modules/fast-uri/lib/utils.js
3094
3094
  var require_utils = __commonJS({
3095
- "node_modules/.pnpm/fast-uri@3.1.0/node_modules/fast-uri/lib/utils.js"(exports$1, module) {
3095
+ "node_modules/.pnpm/fast-uri@3.1.2/node_modules/fast-uri/lib/utils.js"(exports$1, module) {
3096
3096
  var isUUID = RegExp.prototype.test.bind(/^[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}$/iu);
3097
3097
  var isIPv4 = RegExp.prototype.test.bind(/^(?:(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)$/u);
3098
+ var isHexPair = RegExp.prototype.test.bind(/^[\da-f]{2}$/iu);
3099
+ var isUnreserved = RegExp.prototype.test.bind(/^[\da-z\-._~]$/iu);
3100
+ var isPathCharacter = RegExp.prototype.test.bind(/^[\da-z\-._~!$&'()*+,;=:@/]$/iu);
3098
3101
  function stringArrayToHexStripped(input) {
3099
3102
  let acc = "";
3100
3103
  let code = 0;
@@ -3287,27 +3290,77 @@ var require_utils = __commonJS({
3287
3290
  }
3288
3291
  return output.join("");
3289
3292
  }
3290
- function normalizeComponentEncoding(component, esc2) {
3291
- const func = esc2 !== true ? escape : unescape;
3292
- if (component.scheme !== void 0) {
3293
- component.scheme = func(component.scheme);
3294
- }
3295
- if (component.userinfo !== void 0) {
3296
- component.userinfo = func(component.userinfo);
3297
- }
3298
- if (component.host !== void 0) {
3299
- component.host = func(component.host);
3293
+ var HOST_DELIMS = { "@": "%40", "/": "%2F", "?": "%3F", "#": "%23", ":": "%3A" };
3294
+ var HOST_DELIM_RE = /[@/?#:]/g;
3295
+ var HOST_DELIM_NO_COLON_RE = /[@/?#]/g;
3296
+ function reescapeHostDelimiters(host, isIP) {
3297
+ const re = isIP ? HOST_DELIM_NO_COLON_RE : HOST_DELIM_RE;
3298
+ re.lastIndex = 0;
3299
+ return host.replace(re, (ch) => HOST_DELIMS[ch]);
3300
+ }
3301
+ function normalizePercentEncoding(input, decodeUnreserved = false) {
3302
+ if (input.indexOf("%") === -1) {
3303
+ return input;
3300
3304
  }
3301
- if (component.path !== void 0) {
3302
- component.path = func(component.path);
3305
+ let output = "";
3306
+ for (let i = 0; i < input.length; i++) {
3307
+ if (input[i] === "%" && i + 2 < input.length) {
3308
+ const hex3 = input.slice(i + 1, i + 3);
3309
+ if (isHexPair(hex3)) {
3310
+ const normalizedHex = hex3.toUpperCase();
3311
+ const decoded = String.fromCharCode(parseInt(normalizedHex, 16));
3312
+ if (decodeUnreserved && isUnreserved(decoded)) {
3313
+ output += decoded;
3314
+ } else {
3315
+ output += "%" + normalizedHex;
3316
+ }
3317
+ i += 2;
3318
+ continue;
3319
+ }
3320
+ }
3321
+ output += input[i];
3303
3322
  }
3304
- if (component.query !== void 0) {
3305
- component.query = func(component.query);
3323
+ return output;
3324
+ }
3325
+ function normalizePathEncoding(input) {
3326
+ let output = "";
3327
+ for (let i = 0; i < input.length; i++) {
3328
+ if (input[i] === "%" && i + 2 < input.length) {
3329
+ const hex3 = input.slice(i + 1, i + 3);
3330
+ if (isHexPair(hex3)) {
3331
+ const normalizedHex = hex3.toUpperCase();
3332
+ const decoded = String.fromCharCode(parseInt(normalizedHex, 16));
3333
+ if (decoded !== "." && isUnreserved(decoded)) {
3334
+ output += decoded;
3335
+ } else {
3336
+ output += "%" + normalizedHex;
3337
+ }
3338
+ i += 2;
3339
+ continue;
3340
+ }
3341
+ }
3342
+ if (isPathCharacter(input[i])) {
3343
+ output += input[i];
3344
+ } else {
3345
+ output += escape(input[i]);
3346
+ }
3306
3347
  }
3307
- if (component.fragment !== void 0) {
3308
- component.fragment = func(component.fragment);
3348
+ return output;
3349
+ }
3350
+ function escapePreservingEscapes(input) {
3351
+ let output = "";
3352
+ for (let i = 0; i < input.length; i++) {
3353
+ if (input[i] === "%" && i + 2 < input.length) {
3354
+ const hex3 = input.slice(i + 1, i + 3);
3355
+ if (isHexPair(hex3)) {
3356
+ output += "%" + hex3.toUpperCase();
3357
+ i += 2;
3358
+ continue;
3359
+ }
3360
+ }
3361
+ output += escape(input[i]);
3309
3362
  }
3310
- return component;
3363
+ return output;
3311
3364
  }
3312
3365
  function recomposeAuthority(component) {
3313
3366
  const uriTokens = [];
@@ -3322,7 +3375,7 @@ var require_utils = __commonJS({
3322
3375
  if (ipV6res.isIPV6 === true) {
3323
3376
  host = `[${ipV6res.escapedHost}]`;
3324
3377
  } else {
3325
- host = component.host;
3378
+ host = reescapeHostDelimiters(host, false);
3326
3379
  }
3327
3380
  }
3328
3381
  uriTokens.push(host);
@@ -3336,7 +3389,10 @@ var require_utils = __commonJS({
3336
3389
  module.exports = {
3337
3390
  nonSimpleDomain,
3338
3391
  recomposeAuthority,
3339
- normalizeComponentEncoding,
3392
+ reescapeHostDelimiters,
3393
+ normalizePercentEncoding,
3394
+ normalizePathEncoding,
3395
+ escapePreservingEscapes,
3340
3396
  removeDotSegments,
3341
3397
  isIPv4,
3342
3398
  isUUID,
@@ -3346,9 +3402,9 @@ var require_utils = __commonJS({
3346
3402
  }
3347
3403
  });
3348
3404
 
3349
- // node_modules/.pnpm/fast-uri@3.1.0/node_modules/fast-uri/lib/schemes.js
3405
+ // node_modules/.pnpm/fast-uri@3.1.2/node_modules/fast-uri/lib/schemes.js
3350
3406
  var require_schemes = __commonJS({
3351
- "node_modules/.pnpm/fast-uri@3.1.0/node_modules/fast-uri/lib/schemes.js"(exports$1, module) {
3407
+ "node_modules/.pnpm/fast-uri@3.1.2/node_modules/fast-uri/lib/schemes.js"(exports$1, module) {
3352
3408
  var { isUUID } = require_utils();
3353
3409
  var URN_REG = /([\da-z][\d\-a-z]{0,31}):((?:[\w!$'()*+,\-.:;=@]|%[\da-f]{2})+)/iu;
3354
3410
  var supportedSchemeNames = (
@@ -3555,15 +3611,15 @@ var require_schemes = __commonJS({
3555
3611
  }
3556
3612
  });
3557
3613
 
3558
- // node_modules/.pnpm/fast-uri@3.1.0/node_modules/fast-uri/index.js
3614
+ // node_modules/.pnpm/fast-uri@3.1.2/node_modules/fast-uri/index.js
3559
3615
  var require_fast_uri = __commonJS({
3560
- "node_modules/.pnpm/fast-uri@3.1.0/node_modules/fast-uri/index.js"(exports$1, module) {
3561
- var { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizeComponentEncoding, isIPv4, nonSimpleDomain } = require_utils();
3616
+ "node_modules/.pnpm/fast-uri@3.1.2/node_modules/fast-uri/index.js"(exports$1, module) {
3617
+ var { normalizeIPv6, removeDotSegments, recomposeAuthority, normalizePercentEncoding, normalizePathEncoding, escapePreservingEscapes, reescapeHostDelimiters, isIPv4, nonSimpleDomain } = require_utils();
3562
3618
  var { SCHEMES, getSchemeHandler } = require_schemes();
3563
3619
  function normalize(uri, options) {
3564
3620
  if (typeof uri === "string") {
3565
3621
  uri = /** @type {T} */
3566
- serialize(parse3(uri, options), options);
3622
+ normalizeString(uri, options);
3567
3623
  } else if (typeof uri === "object") {
3568
3624
  uri = /** @type {T} */
3569
3625
  parse3(serialize(uri, options), options);
@@ -3630,19 +3686,9 @@ var require_fast_uri = __commonJS({
3630
3686
  return target;
3631
3687
  }
3632
3688
  function equal(uriA, uriB, options) {
3633
- if (typeof uriA === "string") {
3634
- uriA = unescape(uriA);
3635
- uriA = serialize(normalizeComponentEncoding(parse3(uriA, options), true), { ...options, skipEscape: true });
3636
- } else if (typeof uriA === "object") {
3637
- uriA = serialize(normalizeComponentEncoding(uriA, true), { ...options, skipEscape: true });
3638
- }
3639
- if (typeof uriB === "string") {
3640
- uriB = unescape(uriB);
3641
- uriB = serialize(normalizeComponentEncoding(parse3(uriB, options), true), { ...options, skipEscape: true });
3642
- } else if (typeof uriB === "object") {
3643
- uriB = serialize(normalizeComponentEncoding(uriB, true), { ...options, skipEscape: true });
3644
- }
3645
- return uriA.toLowerCase() === uriB.toLowerCase();
3689
+ const normalizedA = normalizeComparableURI(uriA, options);
3690
+ const normalizedB = normalizeComparableURI(uriB, options);
3691
+ return normalizedA !== void 0 && normalizedB !== void 0 && normalizedA.toLowerCase() === normalizedB.toLowerCase();
3646
3692
  }
3647
3693
  function serialize(cmpts, opts) {
3648
3694
  const component = {
@@ -3667,12 +3713,12 @@ var require_fast_uri = __commonJS({
3667
3713
  if (schemeHandler && schemeHandler.serialize) schemeHandler.serialize(component, options);
3668
3714
  if (component.path !== void 0) {
3669
3715
  if (!options.skipEscape) {
3670
- component.path = escape(component.path);
3716
+ component.path = escapePreservingEscapes(component.path);
3671
3717
  if (component.scheme !== void 0) {
3672
3718
  component.path = component.path.split("%3A").join(":");
3673
3719
  }
3674
3720
  } else {
3675
- component.path = unescape(component.path);
3721
+ component.path = normalizePercentEncoding(component.path);
3676
3722
  }
3677
3723
  }
3678
3724
  if (options.reference !== "suffix" && component.scheme) {
@@ -3707,7 +3753,16 @@ var require_fast_uri = __commonJS({
3707
3753
  return uriTokens.join("");
3708
3754
  }
3709
3755
  var URI_PARSE = /^(?:([^#/:?]+):)?(?:\/\/((?:([^#/?@]*)@)?(\[[^#/?\]]+\]|[^#/:?]*)(?::(\d*))?))?([^#?]*)(?:\?([^#]*))?(?:#((?:.|[\n\r])*))?/u;
3710
- function parse3(uri, opts) {
3756
+ function getParseError(parsed, matches) {
3757
+ if (matches[2] !== void 0 && parsed.path && parsed.path[0] !== "/") {
3758
+ return 'URI path must start with "/" when authority is present.';
3759
+ }
3760
+ if (typeof parsed.port === "number" && (parsed.port < 0 || parsed.port > 65535)) {
3761
+ return "URI port is malformed.";
3762
+ }
3763
+ return void 0;
3764
+ }
3765
+ function parseWithStatus(uri, opts) {
3711
3766
  const options = Object.assign({}, opts);
3712
3767
  const parsed = {
3713
3768
  scheme: void 0,
@@ -3718,6 +3773,7 @@ var require_fast_uri = __commonJS({
3718
3773
  query: void 0,
3719
3774
  fragment: void 0
3720
3775
  };
3776
+ let malformedAuthorityOrPort = false;
3721
3777
  let isIP = false;
3722
3778
  if (options.reference === "suffix") {
3723
3779
  if (options.scheme) {
@@ -3738,6 +3794,11 @@ var require_fast_uri = __commonJS({
3738
3794
  if (isNaN(parsed.port)) {
3739
3795
  parsed.port = matches[5];
3740
3796
  }
3797
+ const parseError = getParseError(parsed, matches);
3798
+ if (parseError !== void 0) {
3799
+ parsed.error = parsed.error || parseError;
3800
+ malformedAuthorityOrPort = true;
3801
+ }
3741
3802
  if (parsed.host) {
3742
3803
  const ipv4result = isIPv4(parsed.host);
3743
3804
  if (ipv4result === false) {
@@ -3776,14 +3837,18 @@ var require_fast_uri = __commonJS({
3776
3837
  parsed.scheme = unescape(parsed.scheme);
3777
3838
  }
3778
3839
  if (parsed.host !== void 0) {
3779
- parsed.host = unescape(parsed.host);
3840
+ parsed.host = reescapeHostDelimiters(unescape(parsed.host), isIP);
3780
3841
  }
3781
3842
  }
3782
3843
  if (parsed.path) {
3783
- parsed.path = escape(unescape(parsed.path));
3844
+ parsed.path = normalizePathEncoding(parsed.path);
3784
3845
  }
3785
3846
  if (parsed.fragment) {
3786
- parsed.fragment = encodeURI(decodeURIComponent(parsed.fragment));
3847
+ try {
3848
+ parsed.fragment = encodeURI(decodeURIComponent(parsed.fragment));
3849
+ } catch {
3850
+ parsed.error = parsed.error || "URI malformed";
3851
+ }
3787
3852
  }
3788
3853
  }
3789
3854
  if (schemeHandler && schemeHandler.parse) {
@@ -3792,7 +3857,29 @@ var require_fast_uri = __commonJS({
3792
3857
  } else {
3793
3858
  parsed.error = parsed.error || "URI can not be parsed.";
3794
3859
  }
3795
- return parsed;
3860
+ return { parsed, malformedAuthorityOrPort };
3861
+ }
3862
+ function parse3(uri, opts) {
3863
+ return parseWithStatus(uri, opts).parsed;
3864
+ }
3865
+ function normalizeString(uri, opts) {
3866
+ return normalizeStringWithStatus(uri, opts).normalized;
3867
+ }
3868
+ function normalizeStringWithStatus(uri, opts) {
3869
+ const { parsed, malformedAuthorityOrPort } = parseWithStatus(uri, opts);
3870
+ return {
3871
+ normalized: malformedAuthorityOrPort ? uri : serialize(parsed, opts),
3872
+ malformedAuthorityOrPort
3873
+ };
3874
+ }
3875
+ function normalizeComparableURI(uri, opts) {
3876
+ if (typeof uri === "string") {
3877
+ const { normalized, malformedAuthorityOrPort } = normalizeStringWithStatus(uri, opts);
3878
+ return malformedAuthorityOrPort ? void 0 : normalized;
3879
+ }
3880
+ if (typeof uri === "object") {
3881
+ return serialize(uri, opts);
3882
+ }
3796
3883
  }
3797
3884
  var fastUri = {
3798
3885
  SCHEMES,
@@ -22417,7 +22504,7 @@ async function writeExtensionBackup(claudeDesktopConfigPath, mcpServers) {
22417
22504
 
22418
22505
  // package.json
22419
22506
  var package_default = {
22420
- version: "1.4.0"};
22507
+ version: "1.6.0"};
22421
22508
 
22422
22509
  // src/package-meta.ts
22423
22510
  var PACKAGE_VERSION = package_default.version;
@@ -22980,7 +23067,7 @@ function resultSuggestsConsentNeeded(result) {
22980
23067
  return false;
22981
23068
  }
22982
23069
  const t = first.text;
22983
- return t.includes("Action blocked by Multicorn Shield") || t.includes("does not have") && t.includes("access to") || t.includes("Configure permissions at");
23070
+ return t.includes("Action blocked by Shield") || t.includes("Permission required") || t.includes("This agent cannot use") || t.includes("does not have") && t.includes("access to") || t.includes("Configure permissions:");
22984
23071
  }
22985
23072
 
22986
23073
  // src/types/index.ts
@@ -23203,9 +23290,13 @@ function sleep2(ms) {
23203
23290
  var BLOCKED_ERROR_CODE = -32e3;
23204
23291
  var INTERNAL_ERROR_CODE = -32002;
23205
23292
  var SERVICE_UNREACHABLE_ERROR_CODE = -32003;
23206
- function buildBlockedResponse(id, service, permissionLevel, dashboardUrl) {
23293
+ function buildBlockedResponse(id, service, _permissionLevel, dashboardUrl) {
23207
23294
  const displayService = capitalize(service);
23208
- const message = `Action blocked by Multicorn Shield: agent does not have ${permissionLevel} access to ${displayService}. Configure permissions at ${dashboardUrl}`;
23295
+ const message = `Action blocked by Shield
23296
+
23297
+ This agent cannot use ${displayService}.
23298
+
23299
+ Configure permissions: ${dashboardUrl}`;
23209
23300
  return {
23210
23301
  jsonrpc: "2.0",
23211
23302
  id,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "multicorn-shield",
3
- "version": "1.4.0",
3
+ "version": "1.6.0",
4
4
  "description": "The control layer for AI agents: permissions, consent, spending limits, and audit logging.",
5
5
  "license": "MIT",
6
6
  "author": "Multicorn AI Pty Ltd",