multicorn-shield 1.4.0 → 1.4.1

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,16 @@ 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.4.1] - 2026-05-09
13
+
14
+ ### Changed
15
+
16
+ - 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)
17
+
18
+ ### Fixed
19
+
20
+ - CLI replace flow no longer shows duplicate agent entries
21
+
12
22
  ## [1.4.0] - 2026-05-08
13
23
 
14
24
  ### 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
  }
@@ -1534,12 +1545,12 @@ async function promptProxyConfig(ask, agentName) {
1534
1545
  let upstreamHeaders;
1535
1546
  if (wantsAuth) {
1536
1547
  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"
1548
+ "\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
1549
  );
1539
1550
  const headerVal = await ask("Value: ");
1540
- const trimmed = headerVal.trim();
1541
- if (trimmed.length > 0) {
1542
- upstreamHeaders = { Authorization: trimmed };
1551
+ const authHeader = formatUpstreamAuthorizationBearerHeader(headerVal);
1552
+ if (authHeader !== void 0) {
1553
+ upstreamHeaders = { Authorization: authHeader };
1543
1554
  }
1544
1555
  }
1545
1556
  return {
@@ -2064,7 +2075,7 @@ function printPlatformSnippet(platform, routingToken, shortName, apiKey) {
2064
2075
  }
2065
2076
  }
2066
2077
  function agentDisplayNameDedupeKey(name) {
2067
- return name.trim().toLowerCase();
2078
+ return name.trim().normalize("NFKC").toLowerCase();
2068
2079
  }
2069
2080
  function normalizeAgentEntryForMerge(a) {
2070
2081
  const name = a.name.trim();
@@ -2291,6 +2302,9 @@ You have ${String(agentsForPlatform.length)} agent(s) connected for ${selectedLa
2291
2302
  const victim = agentsForPlatform[replaceIdx];
2292
2303
  if (victim !== void 0) {
2293
2304
  removeAgentNameBeforeSave = victim.name;
2305
+ process.stderr.write(
2306
+ "\n" + style.dim("Replacing agent ") + style.cyan(victim.name) + style.dim("...") + "\n"
2307
+ );
2294
2308
  }
2295
2309
  }
2296
2310
  }
@@ -2810,6 +2824,14 @@ You have ${String(agentsForPlatform.length)} agent(s) connected for ${selectedLa
2810
2824
  }
2811
2825
  process.stderr.write("\n");
2812
2826
  const configuredPlatforms = new Set(configuredAgents.map((a) => a.platform));
2827
+ const cursorMcpPromptLabel = (() => {
2828
+ const rows = configuredAgents.filter((a) => a.platform === "cursor");
2829
+ const last = rows[rows.length - 1];
2830
+ if (last === void 0) return "shield-mcp";
2831
+ const s = typeof last.shortName === "string" ? last.shortName.trim() : "";
2832
+ if (s.length > 0) return s;
2833
+ return last.agentName.trim().length > 0 ? last.agentName.trim() : "shield-mcp";
2834
+ })();
2813
2835
  const blocks = [];
2814
2836
  if (configuredPlatforms.has("openclaw")) {
2815
2837
  blocks.push(
@@ -2828,7 +2850,7 @@ You have ${String(agentsForPlatform.length)} agent(s) connected for ${selectedLa
2828
2850
  }
2829
2851
  if (configuredPlatforms.has("cursor")) {
2830
2852
  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"
2853
+ "\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 \u2192 Example: "Use the ' + cursorMcpPromptLabel + ' MCP server to list my GitHub repositories"\n'
2832
2854
  );
2833
2855
  }
2834
2856
  if (configuredPlatforms.has("kilo-code")) {
@@ -2918,7 +2940,7 @@ You have ${String(agentsForPlatform.length)} agent(s) connected for ${selectedLa
2918
2940
  }
2919
2941
  return lastConfig;
2920
2942
  }
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;
2943
+ 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
2944
  var init_config = __esm({
2923
2945
  "src/proxy/config.ts"() {
2924
2946
  init_consent();
@@ -2950,6 +2972,7 @@ var init_config = __esm({
2950
2972
  CONFIG_PATH = join(CONFIG_DIR, "config.json");
2951
2973
  OPENCLAW_CONFIG_PATH = join(homedir(), ".openclaw", "openclaw.json");
2952
2974
  ANSI_PATTERN = new RegExp(String.fromCharCode(27) + "\\[[0-9;]*[a-zA-Z]", "g");
2975
+ UPSTREAM_AUTH_KNOWN_SCHEME_WITH_PAYLOAD = /^(Bearer|Basic|Token|ApiKey)(\s+)(.+)$/is;
2953
2976
  OPENCLAW_MIN_VERSION = "2026.2.26";
2954
2977
  INIT_WIZARD_PLATFORM_REGISTRY = [
2955
2978
  { slug: "openclaw", displayName: "OpenClaw", section: "native" },
@@ -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
  }
@@ -1605,12 +1617,12 @@ async function promptProxyConfig(ask, agentName) {
1605
1617
  let upstreamHeaders;
1606
1618
  if (wantsAuth) {
1607
1619
  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"
1620
+ "\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
1621
  );
1610
1622
  const headerVal = await ask("Value: ");
1611
- const trimmed = headerVal.trim();
1612
- if (trimmed.length > 0) {
1613
- upstreamHeaders = { Authorization: trimmed };
1623
+ const authHeader = formatUpstreamAuthorizationBearerHeader(headerVal);
1624
+ if (authHeader !== void 0) {
1625
+ upstreamHeaders = { Authorization: authHeader };
1614
1626
  }
1615
1627
  }
1616
1628
  return {
@@ -2143,7 +2155,7 @@ function printPlatformSnippet(platform, routingToken, shortName, apiKey) {
2143
2155
  }
2144
2156
  }
2145
2157
  function agentDisplayNameDedupeKey(name) {
2146
- return name.trim().toLowerCase();
2158
+ return name.trim().normalize("NFKC").toLowerCase();
2147
2159
  }
2148
2160
  function normalizeAgentEntryForMerge(a) {
2149
2161
  const name = a.name.trim();
@@ -2371,6 +2383,9 @@ You have ${String(agentsForPlatform.length)} agent(s) connected for ${selectedLa
2371
2383
  const victim = agentsForPlatform[replaceIdx];
2372
2384
  if (victim !== void 0) {
2373
2385
  removeAgentNameBeforeSave = victim.name;
2386
+ process.stderr.write(
2387
+ "\n" + style.dim("Replacing agent ") + style.cyan(victim.name) + style.dim("...") + "\n"
2388
+ );
2374
2389
  }
2375
2390
  }
2376
2391
  }
@@ -2890,6 +2905,14 @@ You have ${String(agentsForPlatform.length)} agent(s) connected for ${selectedLa
2890
2905
  }
2891
2906
  process.stderr.write("\n");
2892
2907
  const configuredPlatforms = new Set(configuredAgents.map((a) => a.platform));
2908
+ const cursorMcpPromptLabel = (() => {
2909
+ const rows = configuredAgents.filter((a) => a.platform === "cursor");
2910
+ const last = rows[rows.length - 1];
2911
+ if (last === void 0) return "shield-mcp";
2912
+ const s = typeof last.shortName === "string" ? last.shortName.trim() : "";
2913
+ if (s.length > 0) return s;
2914
+ return last.agentName.trim().length > 0 ? last.agentName.trim() : "shield-mcp";
2915
+ })();
2893
2916
  const blocks = [];
2894
2917
  if (configuredPlatforms.has("openclaw")) {
2895
2918
  blocks.push(
@@ -2908,7 +2931,7 @@ You have ${String(agentsForPlatform.length)} agent(s) connected for ${selectedLa
2908
2931
  }
2909
2932
  if (configuredPlatforms.has("cursor")) {
2910
2933
  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"
2934
+ "\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 \u2192 Example: "Use the ' + cursorMcpPromptLabel + ' MCP server to list my GitHub repositories"\n'
2912
2935
  );
2913
2936
  }
2914
2937
  if (configuredPlatforms.has("kilo-code")) {
@@ -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.4.1"};
22421
22508
 
22422
22509
  // src/package-meta.ts
22423
22510
  var PACKAGE_VERSION = package_default.version;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "multicorn-shield",
3
- "version": "1.4.0",
3
+ "version": "1.4.1",
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",