@introspection-ai/recipes 0.19.2 → 0.20.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.
Files changed (116) hide show
  1. package/dist/agents.d.ts +17 -1
  2. package/dist/agents.d.ts.map +1 -1
  3. package/dist/agents.js +15 -1
  4. package/dist/agents.js.map +1 -1
  5. package/dist/child-agent.d.ts +3 -1
  6. package/dist/child-agent.d.ts.map +1 -1
  7. package/dist/child-agent.js +1 -0
  8. package/dist/child-agent.js.map +1 -1
  9. package/dist/mcp-chunks/{auth-command-3K7V3VCW.js → auth-command-IQ4J332A.js} +26 -38
  10. package/dist/mcp-chunks/call-arguments-MCCBPJMY.js +15 -0
  11. package/dist/mcp-chunks/{call-command-OFPHPFM5.js → call-command-WPQ3MDOE.js} +74 -40
  12. package/dist/mcp-chunks/{chunk-LNSUME65.js → chunk-24FKKIXI.js} +29 -13
  13. package/dist/mcp-chunks/{chunk-HTZ2URXW.js → chunk-2CTVPSHF.js} +3 -3
  14. package/dist/mcp-chunks/{chunk-NCXEJ35U.js → chunk-3FB4ZJ4Z.js} +4 -4
  15. package/dist/mcp-chunks/{chunk-P3RN22HQ.js → chunk-3MIFROM7.js} +3 -2
  16. package/dist/mcp-chunks/{chunk-GFYTST6N.js → chunk-54UGGTOX.js} +1 -1
  17. package/dist/mcp-chunks/{chunk-L4VKBFYI.js → chunk-5HQYKAE7.js} +101 -16
  18. package/dist/mcp-chunks/{chunk-E6RVTWJY.js → chunk-5YBCGQA7.js} +1 -1
  19. package/dist/mcp-chunks/{chunk-6D6KPSXN.js → chunk-AJPFOQLF.js} +1 -1
  20. package/dist/mcp-chunks/{chunk-C2PQFLWS.js → chunk-B4XFULJ6.js} +15 -6
  21. package/dist/mcp-chunks/{chunk-HAO6PL7Z.js → chunk-DIIFWDZ7.js} +7 -7
  22. package/dist/mcp-chunks/{chunk-55JIHDU3.js → chunk-EEYUPDRX.js} +1 -1
  23. package/dist/mcp-chunks/{chunk-7A63PAGP.js → chunk-ETYYCEQF.js} +21 -5
  24. package/dist/mcp-chunks/{chunk-E6T37ED6.js → chunk-FNQV2ONG.js} +2 -2
  25. package/dist/mcp-chunks/{chunk-2JHHONW4.js → chunk-FW5QVG6V.js} +1 -1
  26. package/dist/mcp-chunks/{chunk-YCYSQA5V.js → chunk-FZ7K5EGL.js} +5 -5
  27. package/dist/mcp-chunks/{chunk-KSMY7PXI.js → chunk-G5C4WVDQ.js} +1 -1
  28. package/dist/mcp-chunks/{chunk-XRGLP3Z2.js → chunk-GPCLDF6U.js} +1 -1
  29. package/dist/mcp-chunks/{chunk-KSGYBW3F.js → chunk-GQHTGV5E.js} +72 -22
  30. package/dist/mcp-chunks/{chunk-64EP2BVO.js → chunk-HULRE4D2.js} +1 -1
  31. package/dist/mcp-chunks/{chunk-UENXT3NE.js → chunk-ILSK6AWI.js} +1 -1
  32. package/dist/mcp-chunks/{chunk-RBVYCKCD.js → chunk-ILULMM2E.js} +2 -2
  33. package/dist/mcp-chunks/{chunk-NZOIX6XW.js → chunk-ITJWLDF5.js} +2 -2
  34. package/dist/mcp-chunks/{chunk-XUF6KARU.js → chunk-IUFDFNNP.js} +1 -1
  35. package/dist/mcp-chunks/chunk-JJG2OEHI.js +12 -0
  36. package/dist/mcp-chunks/{chunk-YPJ5EHXR.js → chunk-K56RW4HB.js} +4 -4
  37. package/dist/mcp-chunks/{chunk-H7F5RZXS.js → chunk-KJ3CMHWS.js} +2 -1
  38. package/dist/mcp-chunks/{chunk-WXBPMFSN.js → chunk-LI4L4FOV.js} +91 -34
  39. package/dist/mcp-chunks/{chunk-ETWN4IIA.js → chunk-LYZRCACV.js} +6 -6
  40. package/dist/mcp-chunks/{chunk-ZBFZ5UFE.js → chunk-MDVNQ4HM.js} +3 -1
  41. package/dist/mcp-chunks/{chunk-3IZQW4H4.js → chunk-MNAVFYYV.js} +212 -18
  42. package/dist/mcp-chunks/{chunk-7DH57OKF.js → chunk-MWD5PZ4G.js} +2 -2
  43. package/dist/mcp-chunks/{chunk-YSPT6F7K.js → chunk-N2HVJU7X.js} +1 -1
  44. package/dist/mcp-chunks/{chunk-WWO5WGH5.js → chunk-NACLB5YH.js} +5 -5
  45. package/dist/mcp-chunks/{chunk-QJACOI2W.js → chunk-NMF5S5DC.js} +4 -2
  46. package/dist/mcp-chunks/{chunk-54EWGONA.js → chunk-NPU7EMGE.js} +10 -6
  47. package/dist/mcp-chunks/{chunk-SFREPU3D.js → chunk-NSZY5WLR.js} +1 -1
  48. package/dist/mcp-chunks/{chunk-7RDLPFIO.js → chunk-QK6LUI5Q.js} +2 -2
  49. package/dist/mcp-chunks/{chunk-XTL4MHFH.js → chunk-QONTHFPO.js} +11 -7
  50. package/dist/mcp-chunks/{chunk-YTKRAHO6.js → chunk-RDOD354S.js} +4 -4
  51. package/dist/mcp-chunks/{chunk-2MEHGB7D.js → chunk-RXSZ2W6Y.js} +1 -1
  52. package/dist/mcp-chunks/{chunk-UHOKCTZT.js → chunk-RYAUNXFA.js} +1 -1
  53. package/dist/mcp-chunks/{chunk-GIF7LOYU.js → chunk-SCD2NAX5.js} +2 -2
  54. package/dist/mcp-chunks/{chunk-F3LL4EBL.js → chunk-SHZVDY6Z.js} +1 -1
  55. package/dist/mcp-chunks/{chunk-CNDY7WB4.js → chunk-TAVMVGD5.js} +2 -2
  56. package/dist/mcp-chunks/{chunk-JAKI24KR.js → chunk-U23EY5DN.js} +1 -1
  57. package/dist/mcp-chunks/{chunk-SB2UUURE.js → chunk-UAIJZBGL.js} +10 -10
  58. package/dist/mcp-chunks/{chunk-PKOJCYNA.js → chunk-UDG3RHKX.js} +2 -2
  59. package/dist/mcp-chunks/{chunk-CA5WFJZA.js → chunk-VC6SKXTI.js} +1 -1
  60. package/dist/mcp-chunks/chunk-VJ2TSA5R.js +818 -0
  61. package/dist/mcp-chunks/{chunk-FWP4RACK.js → chunk-VREKED5H.js} +2 -2
  62. package/dist/mcp-chunks/{chunk-2FSDGCHW.js → chunk-WKUCIR2F.js} +374 -527
  63. package/dist/mcp-chunks/chunk-XRRT3SZM.js +1931 -0
  64. package/dist/mcp-chunks/{chunk-GSZOK5TS.js → chunk-YDJ7E2PH.js} +3 -3
  65. package/dist/mcp-chunks/{chunk-LICH4Q7A.js → chunk-ZI44YPFF.js} +4 -4
  66. package/dist/mcp-chunks/{chunk-DEUU7WSN.js → chunk-ZNKNF2BV.js} +2 -2
  67. package/dist/mcp-chunks/{chunk-DXPHJFSA.js → chunk-ZSKQI4TS.js} +4 -4
  68. package/dist/mcp-chunks/{cli-E4P6SZLQ.js → cli-Z7KV4PCE.js} +70 -69
  69. package/dist/mcp-chunks/client-B3FMQNGF.js +21 -0
  70. package/dist/mcp-chunks/{config-command-MWF3RHPQ.js → config-command-XXCDOB3M.js} +27 -27
  71. package/dist/mcp-chunks/daemon-command-BAREANTC.js +35 -0
  72. package/dist/mcp-chunks/{dist-ZIPUENTM.js → dist-V4UB7RTR.js} +547 -402
  73. package/dist/mcp-chunks/{emit-ts-command-GOVJJ64A.js → emit-ts-command-FEHTMXXB.js} +16 -16
  74. package/dist/mcp-chunks/{generate-cli-runner-L5OQIMEY.js → generate-cli-runner-OA6XL77R.js} +49 -42
  75. package/dist/mcp-chunks/{inspect-cli-command-7OMMREPE.js → inspect-cli-command-UQKKE5VO.js} +9 -9
  76. package/dist/mcp-chunks/{launch-BWXPLPB7.js → launch-KMPDJOUH.js} +1 -1
  77. package/dist/mcp-chunks/{lifecycle-B5UC65PT.js → lifecycle-R3IP22MJ.js} +1 -1
  78. package/dist/mcp-chunks/{list-command-ZO4HVFQK.js → list-command-7ENYKBF6.js} +31 -31
  79. package/dist/mcp-chunks/{output-utils-M3TJ2N4M.js → output-utils-N75TOWBX.js} +3 -3
  80. package/dist/mcp-chunks/{prompt-CH6TK0bC-C7OTKGRD.js → prompt-CH6TK0bC-NSBYYJZH.js} +1 -1
  81. package/dist/mcp-chunks/{record-command-VD3HUQIC.js → record-command-XHPCL7IG.js} +5 -5
  82. package/dist/mcp-chunks/{replay-command-AX6IN7YD.js → replay-command-CB56L3ZA.js} +6 -6
  83. package/dist/mcp-chunks/{resource-command-JEZ2DW2G.js → resource-command-STEBHVT7.js} +9 -9
  84. package/dist/mcp-chunks/{result-utils-3YHYGS45.js → result-utils-UONY2KNY.js} +3 -3
  85. package/dist/mcp-chunks/runtime-Z45IVD24.js +39 -0
  86. package/dist/mcp-chunks/{runtime-wrapper-UREU7GC3.js → runtime-wrapper-SYYAQVO6.js} +6 -6
  87. package/dist/mcp-chunks/{serve-command-M47YZ6JN.js → serve-command-VYSFRZFE.js} +35 -27
  88. package/dist/mcp-chunks/{timeouts-THZRYP4B.js → timeouts-T3JP3MUF.js} +5 -3
  89. package/dist/mcp-chunks/{vault-command-53P7MLCB.js → vault-command-AJ3X7GDI.js} +58 -12
  90. package/dist/mcp-chunks/{webapi-PHEQZQKH.js → webapi-BLTNWSB2.js} +68 -60
  91. package/dist/mcp-daemon.js +30 -28
  92. package/dist/mcp-run-worker.js +30 -28
  93. package/dist/mcp.d.ts.map +1 -1
  94. package/dist/mcp.js +2 -1
  95. package/dist/mcp.js.map +1 -1
  96. package/dist/pi-extension.d.ts +3 -0
  97. package/dist/pi-extension.d.ts.map +1 -1
  98. package/dist/pi-extension.js +27 -0
  99. package/dist/pi-extension.js.map +1 -1
  100. package/dist/run-controller.d.ts +3 -1
  101. package/dist/run-controller.d.ts.map +1 -1
  102. package/dist/run-controller.js +10 -0
  103. package/dist/run-controller.js.map +1 -1
  104. package/dist/session.d.ts +3 -1
  105. package/dist/session.d.ts.map +1 -1
  106. package/dist/session.js +4 -1
  107. package/dist/session.js.map +1 -1
  108. package/docs/host-api.md +12 -0
  109. package/docs/pi-extension.md +10 -0
  110. package/package.json +11 -11
  111. package/vendor/introspection-recipe-check/win32-x64/introspection-recipe-check.exe +0 -0
  112. package/dist/mcp-chunks/call-arguments-TX3F2TEE.js +0 -15
  113. package/dist/mcp-chunks/chunk-SRZZQ6TL.js +0 -266
  114. package/dist/mcp-chunks/client-2EJC4PLL.js +0 -18
  115. package/dist/mcp-chunks/daemon-command-6CJ26MKI.js +0 -33
  116. package/dist/mcp-chunks/runtime-HSYVOME7.js +0 -37
@@ -3,48 +3,41 @@ import {
3
3
  NON_INTERACTIVE_ELICITATION_HINT,
4
4
  createNonInteractiveElicitationResponder,
5
5
  registerElicitationHandler
6
- } from "./chunk-CA5WFJZA.js";
6
+ } from "./chunk-VC6SKXTI.js";
7
7
  import {
8
8
  RecordTransport,
9
9
  resolveRecordingPath
10
- } from "./chunk-E6T37ED6.js";
10
+ } from "./chunk-FNQV2ONG.js";
11
11
  import {
12
12
  OAuthTimeoutError,
13
13
  connectWithAuth,
14
+ createOAuthSession,
14
15
  isOAuthFlowError,
15
16
  isPostAuthConnectError,
16
17
  resolveOAuthTimeoutFromEnv
17
- } from "./chunk-SRZZQ6TL.js";
18
+ } from "./chunk-VJ2TSA5R.js";
18
19
  import {
19
- buildOAuthPersistence,
20
- buildStaticClientInformation,
21
20
  readCachedAccessToken
22
- } from "./chunk-3IZQW4H4.js";
21
+ } from "./chunk-MNAVFYYV.js";
23
22
  import {
24
23
  isUnauthorizedError,
25
24
  maybeEnableOAuth
26
- } from "./chunk-7DH57OKF.js";
25
+ } from "./chunk-MWD5PZ4G.js";
27
26
  import {
28
27
  STDIO_TRACE_ENABLED,
29
28
  flushStdioLogs,
30
29
  ignoreStdioEmitterError
31
- } from "./chunk-2MEHGB7D.js";
30
+ } from "./chunk-RXSZ2W6Y.js";
32
31
  import {
33
32
  MCPORTER_VERSION
34
- } from "./chunk-SFREPU3D.js";
33
+ } from "./chunk-NSZY5WLR.js";
35
34
  import {
36
35
  createPrefixedConsoleLogger,
37
36
  resolveLogLevelFromEnv
38
- } from "./chunk-GFYTST6N.js";
39
- import {
40
- normalizeTimeout,
41
- raceWithTimeout,
42
- resolveCommandArgument,
43
- resolveCommandArguments
44
- } from "./chunk-ETWN4IIA.js";
37
+ } from "./chunk-54UGGTOX.js";
45
38
  import {
46
39
  analyzeConnectionError
47
- } from "./chunk-DEUU7WSN.js";
40
+ } from "./chunk-ZNKNF2BV.js";
48
41
  import {
49
42
  Client,
50
43
  DEFAULT_REQUEST_TIMEOUT_MSEC,
@@ -56,17 +49,29 @@ import {
56
49
  SdkHttpError,
57
50
  StreamableHTTPClientTransport,
58
51
  serializeMessage,
59
- specTypeSchemas,
60
- validateClientMetadataUrl
61
- } from "./chunk-YPJ5EHXR.js";
52
+ specTypeSchemas
53
+ } from "./chunk-K56RW4HB.js";
54
+ import {
55
+ ChromeDevtoolsRelayRequiredError,
56
+ formatChromeDevtoolsRelayDecision,
57
+ recordChromeDevtoolsRelayDecision,
58
+ resolveChromeDevtoolsAutoConnectCommand,
59
+ resolveChromeDevtoolsRelayEnvironment,
60
+ rewriteChromeDevtoolsArgsForRelay
61
+ } from "./chunk-XRRT3SZM.js";
62
+ import {
63
+ normalizeTimeout,
64
+ raceWithTimeout,
65
+ resolveCommandArgument,
66
+ resolveCommandArguments
67
+ } from "./chunk-LYZRCACV.js";
62
68
  import {
63
69
  loadServerDefinitions
64
- } from "./chunk-L4VKBFYI.js";
70
+ } from "./chunk-5HQYKAE7.js";
65
71
  import {
66
72
  resolveEnvPlaceholders,
67
- resolveEnvValue,
68
73
  withEnvOverrides
69
- } from "./chunk-HAO6PL7Z.js";
74
+ } from "./chunk-DIIFWDZ7.js";
70
75
  import {
71
76
  __commonJS,
72
77
  __require,
@@ -550,27 +555,27 @@ var require_cross_spawn = __commonJS({
550
555
  var cp = __require("child_process");
551
556
  var parse = require_parse();
552
557
  var enoent = require_enoent();
553
- function spawn3(command, args, options) {
558
+ function spawn2(command, args, options) {
554
559
  const parsed = parse(command, args, options);
555
560
  const spawned = cp.spawn(parsed.command, parsed.args, parsed.options);
556
561
  enoent.hookChildProcess(spawned, parsed);
557
562
  return spawned;
558
563
  }
559
- function spawnSync(command, args, options) {
564
+ function spawnSync2(command, args, options) {
560
565
  const parsed = parse(command, args, options);
561
566
  const result = cp.spawnSync(parsed.command, parsed.args, parsed.options);
562
567
  result.error = result.error || enoent.verifyENOENTSync(result.status, parsed);
563
568
  return result;
564
569
  }
565
- module.exports = spawn3;
566
- module.exports.spawn = spawn3;
567
- module.exports.sync = spawnSync;
570
+ module.exports = spawn2;
571
+ module.exports.spawn = spawn2;
572
+ module.exports.sync = spawnSync2;
568
573
  module.exports._parse = parse;
569
574
  module.exports._enoent = enoent;
570
575
  }
571
576
  });
572
577
 
573
- // node_modules/.pnpm/mcporter@0.13.0/node_modules/mcporter/dist/runtime-process-utils.js
578
+ // node_modules/.pnpm/mcporter@0.13.6/node_modules/mcporter/dist/runtime-process-utils.js
574
579
  import { execFile } from "node:child_process";
575
580
  async function closeTransportAndWait(logger, transport, options = {}) {
576
581
  const pidBeforeClose = getTransportPid(transport);
@@ -777,7 +782,7 @@ function delay(ms) {
777
782
  return new Promise((resolve) => setTimeout(resolve, ms));
778
783
  }
779
784
 
780
- // node_modules/.pnpm/mcporter@0.13.0/node_modules/mcporter/dist/runtime/errors.js
785
+ // node_modules/.pnpm/mcporter@0.13.6/node_modules/mcporter/dist/runtime/errors.js
781
786
  var NON_FATAL_MCP_ERROR_CODES = /* @__PURE__ */ new Set([
782
787
  ProtocolErrorCode.InvalidRequest,
783
788
  ProtocolErrorCode.MethodNotFound,
@@ -799,7 +804,7 @@ function protocolErrorCode(error) {
799
804
  return typeof error.code === "number" ? error.code : void 0;
800
805
  }
801
806
 
802
- // node_modules/.pnpm/mcporter@0.13.0/node_modules/mcporter/dist/runtime/replay-transport.js
807
+ // node_modules/.pnpm/mcporter@0.13.6/node_modules/mcporter/dist/runtime/replay-transport.js
803
808
  import fs from "node:fs";
804
809
  import { isDeepStrictEqual } from "node:util";
805
810
  var CLIENT_IDENTITY_META_KEYS = [
@@ -1021,13 +1026,13 @@ function formatReplayRemainder(server, expectedSends) {
1021
1026
  return `Replay ended for server '${server}' with ${count} recorded ${requestText} still unused; next expected recv ${expectedText}.`;
1022
1027
  }
1023
1028
 
1024
- // node_modules/.pnpm/mcporter@0.13.0/node_modules/mcporter/dist/chrome-devtools-compat.js
1029
+ // node_modules/.pnpm/mcporter@0.13.6/node_modules/mcporter/dist/chrome-devtools-compat.js
1025
1030
  import fs3 from "node:fs";
1026
1031
  import os from "node:os";
1027
1032
  import path2 from "node:path";
1028
1033
  import { fileURLToPath, pathToFileURL } from "node:url";
1029
1034
 
1030
- // node_modules/.pnpm/mcporter@0.13.0/node_modules/mcporter/dist/chrome-devtools-auto-connect-patch.js
1035
+ // node_modules/.pnpm/mcporter@0.13.6/node_modules/mcporter/dist/chrome-devtools-auto-connect-patch.js
1031
1036
  import fs2 from "node:fs";
1032
1037
  import path from "node:path";
1033
1038
  var MARKER = "MCPORTER_DEVTOOLS_TIMEOUT_PATCH";
@@ -1114,8 +1119,7 @@ ${helper}`);
1114
1119
  }
1115
1120
  }
1116
1121
 
1117
- // node_modules/.pnpm/mcporter@0.13.0/node_modules/mcporter/dist/chrome-devtools-compat.js
1118
- var AUTO_CONNECT_FLAGS = /* @__PURE__ */ new Set(["--autoConnect", "--auto-connect"]);
1122
+ // node_modules/.pnpm/mcporter@0.13.6/node_modules/mcporter/dist/chrome-devtools-compat.js
1119
1123
  var FALLBACK_PATCH_FILENAME = "mcporter-chrome-devtools-auto-connect-patch.js";
1120
1124
  function applyChromeDevtoolsCompat(env, command, args) {
1121
1125
  if (!shouldApplyChromeDevtoolsCompat(command, args, env)) {
@@ -1143,11 +1147,7 @@ function shouldApplyChromeDevtoolsCompat(command, args, env = process.env) {
1143
1147
  if (env.MCPORTER_DISABLE_CHROME_DEVTOOLS_COMPAT === "1") {
1144
1148
  return false;
1145
1149
  }
1146
- const tokens = [command, ...args];
1147
- return tokens.some(isChromeDevtoolsToken) && args.some((arg) => AUTO_CONNECT_FLAGS.has(arg));
1148
- }
1149
- function isChromeDevtoolsToken(token) {
1150
- return token === "chrome-devtools-mcp" || token.startsWith("chrome-devtools-mcp@") || token.includes("/chrome-devtools-mcp");
1150
+ return resolveChromeDevtoolsAutoConnectCommand(command, args).enabled;
1151
1151
  }
1152
1152
  function resolveChromeDevtoolsCompatPatchPath(candidates = defaultChromeDevtoolsPatchCandidates(), fallbackDir = os.tmpdir()) {
1153
1153
  const existing = candidates.find((candidate) => fs3.existsSync(candidate));
@@ -1173,88 +1173,232 @@ function writeFallbackPatch(fallbackDir) {
1173
1173
  }
1174
1174
  }
1175
1175
 
1176
- // node_modules/.pnpm/mcporter@0.13.0/node_modules/mcporter/dist/chrome-devtools-relay.js
1176
+ // node_modules/.pnpm/mcporter@0.13.6/node_modules/mcporter/dist/chrome-devtools-relay-handoff.js
1177
+ import { spawnSync } from "node:child_process";
1178
+ import { randomBytes } from "node:crypto";
1177
1179
  import fs4 from "node:fs";
1178
1180
  import os2 from "node:os";
1179
1181
  import path3 from "node:path";
1180
- var AUTO_CONNECT_FLAGS2 = /* @__PURE__ */ new Set(["--autoConnect", "--auto-connect"]);
1181
- var RELAY_PROBE_TIMEOUT_MS = 750;
1182
- var DEFAULT_RELAY_URL = "http://127.0.0.1:18799";
1183
- function isChromeDevtoolsToken2(token) {
1184
- return token === "chrome-devtools-mcp" || token.startsWith("chrome-devtools-mcp@") || token.includes("/chrome-devtools-mcp");
1185
- }
1186
- function relayBaseUrl(env) {
1187
- const raw = env.MCPORTER_CHROME_DEVTOOLS_RELAY_URL?.trim() || DEFAULT_RELAY_URL;
1188
- let url;
1182
+ import { pathToFileURL as pathToFileURL2 } from "node:url";
1183
+ var CHROME_RELAY_HANDOFF_ENV = "MCPORTER_CHROME_RELAY_HANDOFF_PATH";
1184
+ var HANDOFF_DIR_PREFIX = "mcporter-chrome-relay-";
1185
+ var HANDOFF_FILENAME = "headers.json";
1186
+ var PRELOAD_FILENAME = "preload.mjs";
1187
+ var WINDOWS_ACL_PATH_ENV = "MCPORTER_CHROME_RELAY_ACL_PATH";
1188
+ function createChromeDevtoolsRelayHandoff(env, clientAuthorization) {
1189
+ let directory;
1189
1190
  try {
1190
- url = new URL(raw);
1191
- } catch {
1192
- return void 0;
1193
- }
1194
- if (url.protocol !== "http:" || !["127.0.0.1", "localhost", "[::1]", "::1"].includes(url.hostname)) {
1195
- return void 0;
1196
- }
1197
- return url;
1191
+ if (process.platform === "win32")
1192
+ directory = createWindowsHandoffDirectory();
1193
+ else {
1194
+ directory = fs4.mkdtempSync(path3.join(os2.tmpdir(), HANDOFF_DIR_PREFIX));
1195
+ fs4.chmodSync(directory, 448);
1196
+ }
1197
+ assertSecurePath(directory, "directory");
1198
+ const handoffPath = path3.join(directory, HANDOFF_FILENAME);
1199
+ const preloadPath = path3.join(directory, PRELOAD_FILENAME);
1200
+ writeExclusiveFile(preloadPath, renderChromeDevtoolsRelayPreloadSource());
1201
+ writeExclusiveFile(handoffPath, JSON.stringify({ Authorization: clientAuthorization }));
1202
+ const importFlag = `--import=${pathToFileURL2(preloadPath).href}`;
1203
+ const existingOptions = env.NODE_OPTIONS?.trim();
1204
+ let closed = false;
1205
+ return {
1206
+ env: {
1207
+ ...env,
1208
+ NODE_OPTIONS: existingOptions ? `${existingOptions} ${importFlag}` : importFlag,
1209
+ [CHROME_RELAY_HANDOFF_ENV]: handoffPath
1210
+ },
1211
+ handoffPath,
1212
+ preloadPath,
1213
+ async close() {
1214
+ if (closed)
1215
+ return;
1216
+ closed = true;
1217
+ cleanupHandoff(directory, handoffPath, preloadPath);
1218
+ }
1219
+ };
1220
+ } catch (error) {
1221
+ if (directory)
1222
+ cleanupHandoff(directory, path3.join(directory, HANDOFF_FILENAME), path3.join(directory, PRELOAD_FILENAME));
1223
+ const diagnostic = error instanceof Error && error.message.startsWith("Windows ACL setup failed:") ? ` ${error.message}` : "";
1224
+ throw new Error(`Unable to install secure Chrome relay authorization handoff.${diagnostic}`, { cause: error });
1225
+ }
1226
+ }
1227
+ function createWindowsHandoffDirectory() {
1228
+ const directory = path3.join(os2.tmpdir(), `${HANDOFF_DIR_PREFIX}${randomBytes(16).toString("hex")}`);
1229
+ const script = String.raw`
1230
+ $ErrorActionPreference = 'Stop'
1231
+ $stage = 'identity'
1232
+ try {
1233
+ $target = $env:${WINDOWS_ACL_PATH_ENV}
1234
+ if ([System.IO.Directory]::Exists($target)) { throw 'handoff path already exists' }
1235
+ $sid = [System.Security.Principal.WindowsIdentity]::GetCurrent().User
1236
+ $stage = 'descriptor'
1237
+ $security = New-Object System.Security.AccessControl.DirectorySecurity
1238
+ $sidValue = $sid.Value
1239
+ $security.SetSecurityDescriptorSddlForm("O:$($sidValue)G:$($sidValue)D:P(A;OICI;FA;;;$($sidValue))")
1240
+ $directory = New-Object System.IO.DirectoryInfo -ArgumentList @($target)
1241
+ $stage = 'create'
1242
+ $directory.Create($security)
1243
+ $stage = 'acl-read'
1244
+ $check = $directory.GetAccessControl([System.Security.AccessControl.AccessControlSections]::All)
1245
+ $rules = @($check.GetAccessRules($true, $true, [System.Security.Principal.SecurityIdentifier]))
1246
+ $ownerSid = $check.GetOwner([System.Security.Principal.SecurityIdentifier]).Value
1247
+ $stage = 'acl-verify'
1248
+ if (-not $check.AreAccessRulesProtected -or $ownerSid -ne $sid.Value -or $rules.Count -ne 1) { throw 'unsafe ACL' }
1249
+ $ruleSid = $rules[0].IdentityReference.Value
1250
+ $hasFullControl = ($rules[0].FileSystemRights -band [System.Security.AccessControl.FileSystemRights]::FullControl) -eq [System.Security.AccessControl.FileSystemRights]::FullControl
1251
+ if ($ruleSid -ne $sid.Value -or $rules[0].IsInherited -or -not $hasFullControl -or $rules[0].AccessControlType -ne [System.Security.AccessControl.AccessControlType]::Allow) { throw 'unsafe ACL' }
1252
+ } catch {
1253
+ $type = $_.Exception.GetType().FullName
1254
+ $hresult = ('0x{0:X8}' -f ($_.Exception.HResult -band 0xffffffffL))
1255
+ [Console]::Error.WriteLine("stage=$stage type=$type hresult=$hresult")
1256
+ exit 1
1198
1257
  }
1199
- function defaultReadToken(env) {
1200
- const stateDir = env.OPENCLAW_STATE_DIR?.trim() || path3.join(os2.homedir(), ".openclaw");
1201
- const secretPath = path3.join(stateDir, "credentials", "browser-extension-relay.secret");
1202
- let raw;
1203
- try {
1204
- raw = fs4.readFileSync(secretPath, "utf8");
1205
- } catch {
1206
- return void 0;
1258
+ `;
1259
+ const result = spawnSync(resolveSystemPowerShellPath(), ["-NoLogo", "-NoProfile", "-NonInteractive", "-Command", script], {
1260
+ encoding: "utf8",
1261
+ env: { ...process.env, [WINDOWS_ACL_PATH_ENV]: directory },
1262
+ stdio: ["ignore", "ignore", "pipe"],
1263
+ windowsHide: true
1264
+ });
1265
+ if (result.status !== 0) {
1266
+ try {
1267
+ fs4.rmdirSync(directory);
1268
+ } catch {
1269
+ }
1270
+ const stderr = typeof result.stderr === "string" ? result.stderr.trim() : "";
1271
+ const safeDetail = /^[A-Za-z0-9_.:=\- ]{1,240}$/u.test(stderr) ? stderr : `stage=spawn type=${result.error?.code ?? "unknown"} hresult=unknown`;
1272
+ throw new Error(`Windows ACL setup failed: ${safeDetail}`);
1207
1273
  }
1208
- const token = raw.trim();
1209
- return /^[0-9a-f]{64}$/.test(token) ? token : void 0;
1274
+ return directory;
1275
+ }
1276
+ function resolveSystemPowerShellPath() {
1277
+ const systemRoot = process.env.SystemRoot?.trim() || process.env.WINDIR?.trim();
1278
+ if (!systemRoot || !path3.win32.isAbsolute(systemRoot))
1279
+ throw new Error("unsafe Windows system root");
1280
+ const executable = path3.win32.join(systemRoot, "System32", "WindowsPowerShell", "v1.0", "powershell.exe");
1281
+ const stat = fs4.lstatSync(executable);
1282
+ if (!stat.isFile() || stat.isSymbolicLink())
1283
+ throw new Error("unsafe Windows PowerShell path");
1284
+ return executable;
1210
1285
  }
1211
- async function defaultProbe(versionUrl, token) {
1212
- const controller = new AbortController();
1213
- const timer = setTimeout(() => controller.abort(), RELAY_PROBE_TIMEOUT_MS);
1214
- timer.unref?.();
1286
+ function writeExclusiveFile(filePath, contents) {
1287
+ const descriptor = fs4.openSync(filePath, fs4.constants.O_WRONLY | fs4.constants.O_CREAT | fs4.constants.O_EXCL | (fs4.constants.O_NOFOLLOW ?? 0), 384);
1215
1288
  try {
1216
- const response = await fetch(versionUrl, {
1217
- headers: { Authorization: `Bearer ${token}` },
1218
- signal: controller.signal
1219
- });
1220
- return response.status === 200;
1221
- } catch {
1222
- return false;
1289
+ if (process.platform !== "win32")
1290
+ fs4.fchmodSync(descriptor, 384);
1291
+ fs4.writeFileSync(descriptor, contents, "utf8");
1223
1292
  } finally {
1224
- clearTimeout(timer);
1293
+ fs4.closeSync(descriptor);
1225
1294
  }
1295
+ assertSecurePath(filePath, "file");
1226
1296
  }
1227
- function shouldAttemptChromeDevtoolsRelay(command, args, env = process.env) {
1228
- if (env.MCPORTER_DISABLE_CHROME_DEVTOOLS_RELAY === "1") {
1229
- return false;
1230
- }
1231
- const tokens = [command, ...args];
1232
- return tokens.some(isChromeDevtoolsToken2) && args.some((arg) => AUTO_CONNECT_FLAGS2.has(arg));
1297
+ function assertSecurePath(filePath, kind) {
1298
+ const stat = fs4.lstatSync(filePath);
1299
+ if ((kind === "directory" ? !stat.isDirectory() : !stat.isFile()) || stat.isSymbolicLink())
1300
+ throw new Error("unsafe");
1301
+ if (process.platform === "win32")
1302
+ return;
1303
+ if ((stat.mode & 63) !== 0)
1304
+ throw new Error("unsafe");
1305
+ if (typeof process.getuid === "function" && stat.uid !== process.getuid())
1306
+ throw new Error("unsafe");
1233
1307
  }
1234
- async function rewriteChromeDevtoolsArgsForRelay(command, args, env = process.env, options = {}) {
1235
- if (!shouldAttemptChromeDevtoolsRelay(command, args, env)) {
1236
- return { args, applied: false };
1308
+ function cleanupHandoff(directory, handoffPath, preloadPath) {
1309
+ for (const filePath of [handoffPath, preloadPath]) {
1310
+ try {
1311
+ fs4.unlinkSync(filePath);
1312
+ } catch {
1313
+ }
1314
+ }
1315
+ try {
1316
+ fs4.rmdirSync(directory);
1317
+ } catch {
1237
1318
  }
1238
- const base = relayBaseUrl(env);
1239
- if (!base) {
1240
- return { args, applied: false };
1319
+ }
1320
+ function renderChromeDevtoolsRelayPreloadSource() {
1321
+ return `import fs from 'node:fs';
1322
+ import path from 'node:path';
1323
+
1324
+ const targetPath = process.argv[1]?.replaceAll('\\\\', '/').toLowerCase();
1325
+ if (targetPath?.includes('chrome-devtools-mcp')) {
1326
+ const failureMessage = 'MCPorter Chrome relay authorization handoff unavailable.';
1327
+ const fail = () => {
1328
+ throw new Error(failureMessage);
1329
+ };
1330
+ const envName = ${JSON.stringify(CHROME_RELAY_HANDOFF_ENV)};
1331
+ const handoffPath = process.env[envName];
1332
+ delete process.env[envName];
1333
+ if (!handoffPath || !path.isAbsolute(handoffPath)) fail();
1334
+
1335
+ const directoryStat = (() => {
1336
+ try {
1337
+ return fs.lstatSync(path.dirname(handoffPath));
1338
+ } catch {
1339
+ return fail();
1340
+ }
1341
+ })();
1342
+ if (!directoryStat.isDirectory() || directoryStat.isSymbolicLink()) fail();
1343
+ if (process.platform !== 'win32') {
1344
+ if ((directoryStat.mode & 0o077) !== 0) fail();
1345
+ if (typeof process.getuid === 'function' && directoryStat.uid !== process.getuid()) fail();
1241
1346
  }
1242
- const token = (options.readToken ?? (() => defaultReadToken(env)))();
1243
- if (!token) {
1244
- return { args, applied: false };
1347
+
1348
+ const descriptor = (() => {
1349
+ try {
1350
+ return fs.openSync(handoffPath, fs.constants.O_RDONLY | (fs.constants.O_NOFOLLOW ?? 0));
1351
+ } catch {
1352
+ return fail();
1353
+ }
1354
+ })();
1355
+
1356
+ let raw = '';
1357
+ let consumed = false;
1358
+ try {
1359
+ const stat = fs.fstatSync(descriptor);
1360
+ if (!stat.isFile() || stat.size <= 0 || stat.size > 4_096) fail();
1361
+ if (process.platform !== 'win32') {
1362
+ if ((stat.mode & 0o077) !== 0) fail();
1363
+ if (typeof process.getuid === 'function' && stat.uid !== process.getuid()) fail();
1364
+ }
1365
+ raw = fs.readFileSync(descriptor, 'utf8');
1366
+ try {
1367
+ fs.unlinkSync(handoffPath);
1368
+ consumed = true;
1369
+ } catch {
1370
+ try {
1371
+ fs.ftruncateSync(descriptor, 0);
1372
+ consumed = true;
1373
+ } catch {
1374
+ fail();
1375
+ }
1376
+ }
1377
+ } finally {
1378
+ fs.closeSync(descriptor);
1245
1379
  }
1246
- const versionUrl = new URL("/json/version", base).toString();
1247
- const alive = await (options.probe ?? defaultProbe)(versionUrl, token);
1248
- if (!alive) {
1249
- return { args, applied: false };
1380
+ if (!consumed) fail();
1381
+
1382
+ let parsed;
1383
+ try {
1384
+ parsed = JSON.parse(raw);
1385
+ } catch {
1386
+ fail();
1250
1387
  }
1251
- const wsEndpoint = `ws://${base.host}/cdp`;
1252
- const rewritten = args.filter((arg) => !AUTO_CONNECT_FLAGS2.has(arg));
1253
- rewritten.push("--wsEndpoint", wsEndpoint, "--wsHeaders", JSON.stringify({ Authorization: `Bearer ${token}` }));
1254
- return { args: rewritten, applied: true, endpoint: wsEndpoint };
1388
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) fail();
1389
+ const entries = Object.entries(parsed);
1390
+ if (entries.length !== 1 || entries[0]?.[0] !== 'Authorization') fail();
1391
+ const authorization = entries[0]?.[1];
1392
+ if (typeof authorization !== 'string' || !/^Bearer [A-Za-z0-9_-]{43}$/u.test(authorization)) fail();
1393
+
1394
+ const terminatorIndex = process.argv.indexOf('--', 2);
1395
+ const insertionIndex = terminatorIndex >= 0 ? terminatorIndex : process.argv.length;
1396
+ process.argv.splice(insertionIndex, 0, '--wsHeaders', JSON.stringify({ Authorization: authorization }));
1397
+ }
1398
+ `;
1255
1399
  }
1256
1400
 
1257
- // node_modules/.pnpm/mcporter@0.13.0/node_modules/mcporter/dist/runtime/cached-auth.js
1401
+ // node_modules/.pnpm/mcporter@0.13.6/node_modules/mcporter/dist/runtime/cached-auth.js
1258
1402
  function hasAuthorizationHeader(headers) {
1259
1403
  return Boolean(headers && Object.keys(headers).some((key) => key.toLowerCase() === "authorization"));
1260
1404
  }
@@ -1317,392 +1461,7 @@ async function applyCachedAuthIfAvailable(definition, logger, allowCachedAuth) {
1317
1461
  }
1318
1462
  }
1319
1463
 
1320
- // node_modules/.pnpm/mcporter@0.13.0/node_modules/mcporter/dist/oauth.js
1321
- import { spawn } from "node:child_process";
1322
- import { createHash, randomUUID } from "node:crypto";
1323
- import http from "node:http";
1324
- import { URL as URL2 } from "node:url";
1325
- var CALLBACK_HOST = "127.0.0.1";
1326
- var CALLBACK_PATH = "/callback";
1327
- var INTERACTIVE_AUTHORIZATION_TTL_MS = 3e5;
1328
- function createDeferred() {
1329
- let resolve;
1330
- let reject;
1331
- const promise = new Promise((res, rej) => {
1332
- resolve = res;
1333
- reject = rej;
1334
- });
1335
- return { promise, resolve, reject };
1336
- }
1337
- function openExternal(url, platform = process.platform, launch = spawn) {
1338
- const stdio = "ignore";
1339
- try {
1340
- if (platform === "darwin") {
1341
- const child = launch("open", [url], { stdio, detached: true });
1342
- child.unref();
1343
- } else if (platform === "win32") {
1344
- const child = launch("rundll32", ["url.dll,FileProtocolHandler", url], {
1345
- stdio,
1346
- detached: true,
1347
- windowsHide: true
1348
- });
1349
- child.unref();
1350
- } else {
1351
- try {
1352
- const child = launch("xdg-open", [url], { stdio, detached: true });
1353
- child.on("error", () => {
1354
- });
1355
- child.unref();
1356
- } catch {
1357
- }
1358
- }
1359
- } catch {
1360
- }
1361
- }
1362
- var PersistentOAuthClientProvider = class _PersistentOAuthClientProvider {
1363
- definition;
1364
- options;
1365
- metadata;
1366
- logger;
1367
- persistence;
1368
- redirectUrlValue;
1369
- authorizationDeferred = null;
1370
- authorizationRedirectStarted = false;
1371
- // One interactive authorization transaction per provider: concurrent SDK auth() flows
1372
- // (background GET reconnect + bridged POST both hitting 401) must not each open a
1373
- // prompt, because only one persisted PKCE verifier can complete (issue #247).
1374
- interactiveAuthorization = null;
1375
- pendingVerifiersByChallenge = /* @__PURE__ */ new Map();
1376
- server;
1377
- constructor(definition, persistence, redirectUrl, logger, options = {}) {
1378
- this.definition = definition;
1379
- this.options = options;
1380
- this.redirectUrlValue = redirectUrl;
1381
- this.logger = logger;
1382
- this.persistence = persistence;
1383
- this.metadata = {
1384
- client_name: definition.clientName ?? `mcporter (${definition.name})`,
1385
- redirect_uris: [this.redirectUrlValue.toString()],
1386
- grant_types: ["authorization_code", "refresh_token"],
1387
- response_types: ["code"],
1388
- token_endpoint_auth_method: "none",
1389
- // Omit scope so the MCP SDK can derive it from the server's metadata
1390
- // (resource metadata scopes_supported or auth server scopes_supported).
1391
- // Hardcoding 'mcp:tools' breaks providers like Granola whose auth server
1392
- // does not recognise that scope value.
1393
- // If oauthScope is explicitly configured, prefer that exact value.
1394
- ...definition.oauthScope !== void 0 ? { scope: definition.oauthScope || void 0 } : {}
1395
- };
1396
- }
1397
- static async create(definition, logger, options = {}) {
1398
- validateClientMetadataUrl(definition.oauthClientMetadataUrl);
1399
- const persistence = await buildOAuthPersistence(definition, logger);
1400
- const server = http.createServer();
1401
- const overrideRedirect = definition.oauthRedirectUrl ? new URL2(definition.oauthRedirectUrl) : null;
1402
- const listenHost = overrideRedirect?.hostname ?? CALLBACK_HOST;
1403
- const overridePort = overrideRedirect?.port ?? "";
1404
- const usesDynamicPort = !overrideRedirect || overridePort === "" || overridePort === "0";
1405
- const desiredPort = usesDynamicPort ? void 0 : Number.parseInt(overridePort, 10);
1406
- const callbackPath = overrideRedirect?.pathname && overrideRedirect.pathname !== "/" ? overrideRedirect.pathname : CALLBACK_PATH;
1407
- const port = await new Promise((resolve, reject) => {
1408
- server.listen(desiredPort ?? 0, listenHost, () => {
1409
- const address = server.address();
1410
- if (typeof address === "object" && address && "port" in address) {
1411
- resolve(address.port);
1412
- } else {
1413
- reject(new Error("Failed to determine callback port"));
1414
- }
1415
- });
1416
- server.once("error", (error) => reject(error));
1417
- });
1418
- const redirectUrl = overrideRedirect ? new URL2(overrideRedirect.toString()) : new URL2(`http://${listenHost}:${port}${callbackPath}`);
1419
- if (usesDynamicPort) {
1420
- redirectUrl.port = String(port);
1421
- }
1422
- if (!overrideRedirect || overrideRedirect.pathname === "/" || overrideRedirect.pathname === "") {
1423
- redirectUrl.pathname = callbackPath;
1424
- }
1425
- if (usesDynamicPort) {
1426
- try {
1427
- const cachedClient = await persistence.readClientInfo();
1428
- const cachedRedirect = firstRedirectUri(cachedClient);
1429
- if (cachedRedirect && cachedRedirect !== redirectUrl.toString()) {
1430
- logger.info(`Redirect URI changed (${cachedRedirect} \u2192 ${redirectUrl.toString()}); clearing stale client registration.`);
1431
- await persistence.clear("client");
1432
- }
1433
- } catch (error) {
1434
- await new Promise((resolve) => {
1435
- server.close(() => resolve());
1436
- });
1437
- throw error;
1438
- }
1439
- }
1440
- const provider = new _PersistentOAuthClientProvider(definition, persistence, redirectUrl, logger, options);
1441
- provider.attachServer(server);
1442
- return {
1443
- provider,
1444
- close: async () => {
1445
- await provider.close();
1446
- }
1447
- };
1448
- }
1449
- // attachServer listens for the OAuth redirect and resolves/rejects the deferred code promise.
1450
- attachServer(server) {
1451
- this.server = server;
1452
- server.on("request", async (req, res) => {
1453
- try {
1454
- const url = req.url ?? "";
1455
- const parsed = new URL2(url, this.redirectUrlValue);
1456
- const expectedPath = this.redirectUrlValue.pathname || "/callback";
1457
- if (parsed.pathname !== expectedPath) {
1458
- res.statusCode = 404;
1459
- res.end("Not found");
1460
- return;
1461
- }
1462
- const code = parsed.searchParams.get("code");
1463
- const error = parsed.searchParams.get("error");
1464
- const receivedState = parsed.searchParams.get("state");
1465
- const iss = parsed.searchParams.get("iss") ?? void 0;
1466
- const expectedState = await this.persistence.readState();
1467
- if (expectedState && receivedState !== expectedState) {
1468
- res.statusCode = 400;
1469
- res.setHeader("Content-Type", "text/html");
1470
- res.end("<html><body><h1>Authorization failed</h1><p>Invalid OAuth state</p></body></html>");
1471
- this.authorizationDeferred?.reject(new Error("Invalid OAuth state"));
1472
- this.authorizationDeferred = null;
1473
- this.clearInteractiveAuthorization();
1474
- return;
1475
- }
1476
- if (code) {
1477
- this.logger.info(`Received OAuth authorization code for ${this.definition.name}`);
1478
- res.statusCode = 200;
1479
- res.setHeader("Content-Type", "text/html");
1480
- res.end("<html><body><h1>Authorization successful</h1><p>You can return to the CLI.</p></body></html>");
1481
- this.authorizationDeferred?.resolve({ code, iss });
1482
- this.authorizationDeferred = null;
1483
- this.clearInteractiveAuthorization();
1484
- } else if (error) {
1485
- res.statusCode = 400;
1486
- res.setHeader("Content-Type", "text/html");
1487
- res.end("<html><body><h1>Authorization failed</h1><p>Return to the CLI for details.</p></body></html>");
1488
- this.authorizationDeferred?.reject(new Error("OAuth authorization failed."));
1489
- this.authorizationDeferred = null;
1490
- this.clearInteractiveAuthorization();
1491
- } else {
1492
- res.statusCode = 400;
1493
- res.end("Missing authorization code");
1494
- this.authorizationDeferred?.reject(new Error("Missing authorization code"));
1495
- this.authorizationDeferred = null;
1496
- this.clearInteractiveAuthorization();
1497
- }
1498
- } catch (error) {
1499
- this.authorizationDeferred?.reject(error);
1500
- this.authorizationDeferred = null;
1501
- this.clearInteractiveAuthorization();
1502
- }
1503
- });
1504
- }
1505
- get redirectUrl() {
1506
- return this.redirectUrlValue;
1507
- }
1508
- get clientMetadata() {
1509
- return this.metadata;
1510
- }
1511
- get clientMetadataUrl() {
1512
- return this.definition.oauthClientMetadataUrl;
1513
- }
1514
- async state() {
1515
- const existing = await this.persistence.readState();
1516
- if (existing) {
1517
- return existing;
1518
- }
1519
- const state = randomUUID();
1520
- await this.persistence.saveState(state);
1521
- return state;
1522
- }
1523
- async clientInformation(ctx) {
1524
- const staticClient = buildStaticClientInformation(this.definition, { redirectUrl: this.redirectUrlValue });
1525
- if (staticClient) {
1526
- return { ...staticClient, ...ctx ? { issuer: ctx.issuer } : {} };
1527
- }
1528
- const stored = await this.persistence.readClientInfo();
1529
- if (ctx && stored?.issuer && !issuersMatch(stored.issuer, ctx.issuer)) {
1530
- await this.persistence.clear("client");
1531
- this.logger.info(`Discarded OAuth client registration for ${this.definition.name} after issuer changed.`);
1532
- return void 0;
1533
- }
1534
- return stored;
1535
- }
1536
- async saveClientInformation(clientInformation) {
1537
- await this.persistence.saveClientInfo(clientInformation);
1538
- }
1539
- async tokens(ctx) {
1540
- const stored = await this.persistence.readTokens();
1541
- if (ctx && stored?.issuer && !issuersMatch(stored.issuer, ctx.issuer)) {
1542
- await this.persistence.clear("tokens");
1543
- this.logger.info(`Discarded OAuth tokens for ${this.definition.name} after issuer changed.`);
1544
- return void 0;
1545
- }
1546
- return stored;
1547
- }
1548
- async saveTokens(tokens) {
1549
- await this.persistence.saveTokens(tokens);
1550
- this.logger.info(`Saved OAuth tokens for ${this.definition.name} (${this.persistence.describe()})`);
1551
- }
1552
- async redirectToAuthorization(authorizationUrl) {
1553
- this.authorizationRedirectStarted = true;
1554
- this.ensureAuthorizationDeferred();
1555
- const challenge = authorizationUrl.searchParams.get("code_challenge");
1556
- if (this.hasActiveInteractiveAuthorization()) {
1557
- if (challenge) {
1558
- this.pendingVerifiersByChallenge.delete(challenge);
1559
- }
1560
- this.logger.info(`Authorization already pending for ${this.definition.name}; suppressing duplicate prompt.`);
1561
- return;
1562
- }
1563
- this.interactiveAuthorization = { challenge, claimedAt: Date.now() };
1564
- const claimedVerifier = challenge ? this.pendingVerifiersByChallenge.get(challenge) : void 0;
1565
- if (challenge) {
1566
- this.pendingVerifiersByChallenge.delete(challenge);
1567
- }
1568
- if (claimedVerifier) {
1569
- await this.persistence.saveCodeVerifier(claimedVerifier);
1570
- }
1571
- const request = {
1572
- authorizationUrl: authorizationUrl.toString(),
1573
- redirectUrl: this.redirectUrlValue.toString()
1574
- };
1575
- if (this.options.suppressBrowserLaunch) {
1576
- await this.options.onAuthorizationUrl?.(request);
1577
- return;
1578
- }
1579
- this.logger.info(`Authorization required for ${this.definition.name}. Opening browser...`);
1580
- __oauthInternals.openExternal(request.authorizationUrl);
1581
- this.logger.warn(`If the browser did not open, visit ${request.authorizationUrl} manually.`);
1582
- }
1583
- hasAuthorizationRedirectStarted() {
1584
- return this.authorizationRedirectStarted;
1585
- }
1586
- async saveCodeVerifier(codeVerifier) {
1587
- this.pendingVerifiersByChallenge.set(challengeForVerifier(codeVerifier), codeVerifier);
1588
- if (this.hasActiveInteractiveAuthorization()) {
1589
- return;
1590
- }
1591
- await this.persistence.saveCodeVerifier(codeVerifier);
1592
- }
1593
- async codeVerifier() {
1594
- const value = await this.persistence.readCodeVerifier();
1595
- if (!value) {
1596
- throw new Error(`Missing PKCE code verifier for ${this.definition.name}`);
1597
- }
1598
- return value.trim();
1599
- }
1600
- // invalidateCredentials removes cached files to force the next OAuth flow.
1601
- async invalidateCredentials(scope) {
1602
- if (scope === "all" || scope === "verifier") {
1603
- this.clearInteractiveAuthorization();
1604
- }
1605
- await this.persistence.clear(scope);
1606
- }
1607
- async saveDiscoveryState(state) {
1608
- await this.persistence.saveDiscoveryState(state);
1609
- }
1610
- async discoveryState() {
1611
- return this.persistence.readDiscoveryState();
1612
- }
1613
- async saveAuthorizationServerUrl(url) {
1614
- await this.persistence.saveAuthorizationServerUrl(url);
1615
- }
1616
- async authorizationServerUrl() {
1617
- return this.persistence.readAuthorizationServerUrl();
1618
- }
1619
- async saveResourceUrl(url) {
1620
- await this.persistence.saveResourceUrl(url);
1621
- }
1622
- async resourceUrl() {
1623
- return this.persistence.readResourceUrl();
1624
- }
1625
- // waitForAuthorizationCode resolves once the local callback server captures a redirect.
1626
- // The same deferred is shared with redirectToAuthorization so callback resolution is stable.
1627
- async waitForAuthorizationCode() {
1628
- return (await this.waitForAuthorizationResponse()).code;
1629
- }
1630
- async waitForAuthorizationResponse() {
1631
- return this.ensureAuthorizationDeferred().promise;
1632
- }
1633
- // close stops the temporary callback server created for the OAuth session.
1634
- async close() {
1635
- if (this.authorizationDeferred) {
1636
- this.authorizationDeferred.reject(new Error("OAuth session closed before receiving authorization code."));
1637
- this.authorizationDeferred = null;
1638
- this.clearInteractiveAuthorization();
1639
- }
1640
- if (!this.server) {
1641
- return;
1642
- }
1643
- this.server.closeAllConnections?.();
1644
- const server = this.server;
1645
- this.server = void 0;
1646
- await new Promise((resolve) => {
1647
- server.close(() => resolve());
1648
- });
1649
- }
1650
- ensureAuthorizationDeferred() {
1651
- if (!this.authorizationDeferred) {
1652
- this.authorizationDeferred = createDeferred();
1653
- }
1654
- return this.authorizationDeferred;
1655
- }
1656
- hasActiveInteractiveAuthorization() {
1657
- if (!this.interactiveAuthorization) {
1658
- return false;
1659
- }
1660
- if (Date.now() - this.interactiveAuthorization.claimedAt > INTERACTIVE_AUTHORIZATION_TTL_MS) {
1661
- this.interactiveAuthorization = null;
1662
- return false;
1663
- }
1664
- return true;
1665
- }
1666
- clearInteractiveAuthorization() {
1667
- this.interactiveAuthorization = null;
1668
- this.pendingVerifiersByChallenge.clear();
1669
- }
1670
- };
1671
- async function createOAuthSession(definition, logger, options = {}) {
1672
- const { provider, close } = await PersistentOAuthClientProvider.create(definition, logger, options);
1673
- const waitForAuthorizationCode = () => provider.waitForAuthorizationCode();
1674
- const waitForAuthorizationResponse = () => provider.waitForAuthorizationResponse();
1675
- const hasAuthorizationRedirectStarted = () => provider.hasAuthorizationRedirectStarted();
1676
- return {
1677
- provider,
1678
- waitForAuthorizationCode,
1679
- waitForAuthorizationResponse,
1680
- hasAuthorizationRedirectStarted,
1681
- close
1682
- };
1683
- }
1684
- function challengeForVerifier(verifier) {
1685
- return createHash("sha256").update(verifier).digest("base64url");
1686
- }
1687
- function firstRedirectUri(client) {
1688
- if (!client || typeof client !== "object") {
1689
- return void 0;
1690
- }
1691
- const redirectUris = client.redirect_uris;
1692
- if (!Array.isArray(redirectUris)) {
1693
- return void 0;
1694
- }
1695
- const [first] = redirectUris;
1696
- return typeof first === "string" ? first : void 0;
1697
- }
1698
- function issuersMatch(first, second) {
1699
- return first === second || first.endsWith("/") && first.slice(0, -1) === second || second.endsWith("/") && second.slice(0, -1) === first;
1700
- }
1701
- var __oauthInternals = {
1702
- openExternal
1703
- };
1704
-
1705
- // node_modules/.pnpm/mcporter@0.13.0/node_modules/mcporter/dist/runtime-header-utils.js
1464
+ // node_modules/.pnpm/mcporter@0.13.6/node_modules/mcporter/dist/runtime-header-utils.js
1706
1465
  function materializeHeaders(headers, serverName) {
1707
1466
  if (!headers) {
1708
1467
  return void 0;
@@ -1719,8 +1478,8 @@ function materializeHeaders(headers, serverName) {
1719
1478
  return resolved;
1720
1479
  }
1721
1480
 
1722
- // node_modules/.pnpm/mcporter@0.13.0/node_modules/mcporter/dist/runtime/node-http-fetch.js
1723
- import http2 from "node:http";
1481
+ // node_modules/.pnpm/mcporter@0.13.6/node_modules/mcporter/dist/runtime/node-http-fetch.js
1482
+ import http from "node:http";
1724
1483
  import https from "node:https";
1725
1484
  import { Buffer as Buffer2 } from "node:buffer";
1726
1485
  import { Readable } from "node:stream";
@@ -1755,7 +1514,7 @@ async function nodeHttp1FetchWithRedirects(input, init, redirectCount) {
1755
1514
  headers["content-length"] = String(Buffer2.byteLength(body));
1756
1515
  }
1757
1516
  return new Promise((resolve, reject) => {
1758
- const client = url.protocol === "https:" ? https : http2;
1517
+ const client = url.protocol === "https:" ? https : http;
1759
1518
  const request = client.request(url, {
1760
1519
  method: init.method ?? "GET",
1761
1520
  headers
@@ -1875,7 +1634,7 @@ async function materializeRequestBody(body) {
1875
1634
  throw new TypeError("node-http1 fetch does not support streaming request bodies.");
1876
1635
  }
1877
1636
 
1878
- // node_modules/.pnpm/mcporter@0.13.0/node_modules/mcporter/dist/runtime/http-transport.js
1637
+ // node_modules/.pnpm/mcporter@0.13.6/node_modules/mcporter/dist/runtime/http-transport.js
1879
1638
  function extractTransportStatusCode(error) {
1880
1639
  if (!error || typeof error !== "object")
1881
1640
  return void 0;
@@ -1910,6 +1669,7 @@ function removeAuthorizationHeader(headers) {
1910
1669
  return Object.keys(headers).length > 0 ? headers : void 0;
1911
1670
  }
1912
1671
  var NODE_HTTP1_FETCH_HOSTS = /* @__PURE__ */ new Set(["api.sunsama.com"]);
1672
+ var STANDALONE_SSE_START_GRACE_MS = 250;
1913
1673
  function resolveHttpFetchOverride(definition) {
1914
1674
  if (definition.command.kind !== "http" || definition.httpFetch === "default")
1915
1675
  return void 0;
@@ -1954,6 +1714,26 @@ function trackStandaloneSseFetch(fetchOverride) {
1954
1714
  }
1955
1715
  };
1956
1716
  }
1717
+ function waitForStandaloneSseStart(started, signal) {
1718
+ if (signal?.aborted)
1719
+ return Promise.resolve();
1720
+ return new Promise((resolve) => {
1721
+ let settled = false;
1722
+ const finish = () => {
1723
+ if (settled)
1724
+ return;
1725
+ settled = true;
1726
+ clearTimeout(timer);
1727
+ signal?.removeEventListener("abort", finish);
1728
+ resolve();
1729
+ };
1730
+ const timer = setTimeout(finish, STANDALONE_SSE_START_GRACE_MS);
1731
+ signal?.addEventListener("abort", finish, { once: true });
1732
+ if (signal?.aborted)
1733
+ finish();
1734
+ void started.then(finish);
1735
+ });
1736
+ }
1957
1737
  async function closeOAuthSession(oauthSession) {
1958
1738
  await oauthSession?.close().catch(() => {
1959
1739
  });
@@ -1961,7 +1741,11 @@ async function closeOAuthSession(oauthSession) {
1961
1741
  function shouldAbortSseFallback(error) {
1962
1742
  if (isPostAuthConnectError(error))
1963
1743
  return !isLegacySseTransportMismatch(error);
1964
- return isOAuthFlowError(error) || error instanceof OAuthTimeoutError;
1744
+ if (isOAuthFlowError(error) || error instanceof OAuthTimeoutError)
1745
+ return true;
1746
+ if (isUnauthorizedError(error))
1747
+ return false;
1748
+ return !isLegacySseTransportMismatch(error);
1965
1749
  }
1966
1750
  function isEraNegotiationFailure(error) {
1967
1751
  return !!error && typeof error === "object" && "code" in error && error.code === SdkErrorCode.EraNegotiationFailed;
@@ -2042,18 +1826,20 @@ async function connectPrimaryHttpTransport(client, definition, command, transpor
2042
1826
  recreateTransport: async () => createStreamableTransport()
2043
1827
  });
2044
1828
  if (typeof client.getProtocolEra === "function" && client.getProtocolEra() === "legacy") {
2045
- await transportOptions.standaloneSseStarted;
1829
+ await waitForStandaloneSseStart(transportOptions.standaloneSseStarted, options.signal);
2046
1830
  }
2047
1831
  return { client, transport, definition, oauthSession };
2048
1832
  }
2049
1833
  async function connectSseFallbackTransport(client, definition, command, transportOptions, oauthSession, logger, options, wrapRecordTransport2, clientFactory) {
1834
+ const createSseTransport = () => wrapRecordTransport2(new SSEClientTransport(command.url, transportOptions), definition, options);
2050
1835
  try {
2051
- const transport = await connectHttpTransport(client, wrapRecordTransport2(new SSEClientTransport(command.url, transportOptions), definition, options), oauthSession, logger, {
1836
+ const transport = await connectHttpTransport(client, createSseTransport(), oauthSession, logger, {
2052
1837
  serverName: definition.name,
2053
1838
  serverUrl: command.url,
2054
1839
  maxAttempts: options.maxOAuthAttempts,
2055
1840
  oauthTimeoutMs: options.oauthTimeoutMs,
2056
- signal: options.signal
1841
+ signal: options.signal,
1842
+ recreateTransport: async () => createSseTransport()
2057
1843
  });
2058
1844
  return { client, transport, definition, oauthSession };
2059
1845
  } catch (sseError) {
@@ -2066,8 +1852,7 @@ async function connectSseFallbackTransport(client, definition, command, transpor
2066
1852
  options.onDefinitionPromoted?.(promoted);
2067
1853
  return createHttpClientContext(promoted, logger, options, wrapRecordTransport2, clientFactory);
2068
1854
  }
2069
- if (definition.auth)
2070
- throw sseError;
1855
+ throw sseError;
2071
1856
  }
2072
1857
  throw sseError;
2073
1858
  }
@@ -2279,8 +2064,9 @@ var StdioClientTransport = class {
2279
2064
  }
2280
2065
  };
2281
2066
 
2282
- // node_modules/.pnpm/mcporter@0.13.0/node_modules/mcporter/dist/runtime/stdio-transport.js
2067
+ // node_modules/.pnpm/mcporter@0.13.6/node_modules/mcporter/dist/runtime/stdio-transport.js
2283
2068
  var McporterStdioTransport = class extends StdioClientTransport {
2069
+ parameters;
2284
2070
  meta;
2285
2071
  closing = false;
2286
2072
  closeDelegate;
@@ -2288,6 +2074,7 @@ var McporterStdioTransport = class extends StdioClientTransport {
2288
2074
  closeInterceptor = () => {
2289
2075
  this.meta.code = this.closing ? 0 : 1;
2290
2076
  flushStdioLogs(this.meta);
2077
+ void this.cleanup();
2291
2078
  this.closeDelegate?.();
2292
2079
  };
2293
2080
  messageInterceptor = (message) => {
@@ -2295,8 +2082,10 @@ var McporterStdioTransport = class extends StdioClientTransport {
2295
2082
  this.meta.stdoutChunks?.push(JSON.stringify(message));
2296
2083
  this.messageDelegate?.(message);
2297
2084
  };
2085
+ cleanupPromise;
2298
2086
  constructor(parameters) {
2299
2087
  super({ ...parameters, stderr: "pipe" });
2088
+ this.parameters = parameters;
2300
2089
  this.meta = {
2301
2090
  stderrChunks: [],
2302
2091
  stdoutChunks: STDIO_TRACE_ENABLED ? [] : void 0,
@@ -2339,8 +2128,14 @@ var McporterStdioTransport = class extends StdioClientTransport {
2339
2128
  } finally {
2340
2129
  this.meta.code ??= 0;
2341
2130
  flushStdioLogs(this.meta);
2131
+ await this.cleanup();
2342
2132
  }
2343
2133
  }
2134
+ cleanup() {
2135
+ this.cleanupPromise ??= Promise.resolve(this.parameters.cleanup?.()).catch(() => {
2136
+ });
2137
+ return this.cleanupPromise;
2138
+ }
2344
2139
  installInterceptors() {
2345
2140
  if (this.onclose !== this.closeInterceptor) {
2346
2141
  this.closeDelegate = this.onclose;
@@ -2353,7 +2148,7 @@ var McporterStdioTransport = class extends StdioClientTransport {
2353
2148
  }
2354
2149
  };
2355
2150
 
2356
- // node_modules/.pnpm/mcporter@0.13.0/node_modules/mcporter/dist/runtime/transport.js
2151
+ // node_modules/.pnpm/mcporter@0.13.6/node_modules/mcporter/dist/runtime/transport.js
2357
2152
  function shouldUseModeForServer(definition, serverFilter) {
2358
2153
  return !serverFilter || serverFilter === definition.name;
2359
2154
  }
@@ -2414,33 +2209,85 @@ async function createReplayClientContext(definition, replayPath, clientInfo, opt
2414
2209
  return { client, transport, definition, oauthSession: void 0 };
2415
2210
  }
2416
2211
  async function createStdioClientContext(client, definition, logger, options) {
2417
- const resolvedEnvOverrides = definition.env && Object.keys(definition.env).length > 0 ? Object.fromEntries(Object.entries(definition.env).map(([key, raw]) => [key, resolveEnvValue(raw)]).filter(([, value]) => value !== "")) : void 0;
2418
- const mergedEnv = resolvedEnvOverrides && Object.keys(resolvedEnvOverrides).length > 0 ? { ...process.env, ...resolvedEnvOverrides } : { ...process.env };
2212
+ const mergedEnv = resolveChromeDevtoolsRelayEnvironment(definition.env);
2419
2213
  const command = resolveCommandArgument(definition.command.command);
2420
2214
  const resolvedArgs = resolveCommandArguments(definition.command.args);
2421
- const relay = await rewriteChromeDevtoolsArgsForRelay(command, resolvedArgs, mergedEnv);
2422
- if (relay.applied) {
2423
- logger.info(`Routing chrome-devtools-mcp through the OpenClaw extension relay at ${relay.endpoint} (no dialog).`);
2424
- }
2425
- const commandArgs = [...relay.args];
2426
- const compat = applyChromeDevtoolsCompat(mergedEnv, command, commandArgs);
2427
- if (compat.applied) {
2428
- logger.info(`Injecting chrome-devtools-mcp --autoConnect compatibility patch from ${compat.patchPath}.`);
2429
- }
2430
- const rawTransport = new McporterStdioTransport({
2431
- command,
2432
- args: commandArgs,
2433
- cwd: definition.command.cwd,
2434
- env: compat.env
2435
- });
2436
- const transport = wrapRecordTransport(rawTransport, definition, options);
2215
+ const publishRelayDecision = (decision) => {
2216
+ if (decision.reason === "not-eligible")
2217
+ return;
2218
+ recordChromeDevtoolsRelayDecision(definition.name, decision);
2219
+ logger.info(`Chrome DevTools relay decision ${formatChromeDevtoolsRelayDecision(decision)}`);
2220
+ };
2221
+ let relayDecision;
2222
+ let relay;
2223
+ try {
2224
+ relay = await rewriteChromeDevtoolsArgsForRelay(command, resolvedArgs, mergedEnv, { onDecision: (decision) => relayDecision = decision }, definition.chromeDevtoolsRelay);
2225
+ } catch (error) {
2226
+ if (relayDecision)
2227
+ publishRelayDecision(relayDecision);
2228
+ throw error;
2229
+ }
2230
+ let commandArgs = [...relay.args];
2231
+ let activeProxy = relay.proxy;
2232
+ let handoff;
2233
+ let rawTransport;
2234
+ try {
2235
+ if (activeProxy) {
2236
+ try {
2237
+ handoff = createChromeDevtoolsRelayHandoff(mergedEnv, activeProxy.consumeClientAuthorization());
2238
+ } catch {
2239
+ await activeProxy.close().catch(() => {
2240
+ });
2241
+ activeProxy = void 0;
2242
+ relayDecision = {
2243
+ ...relay.decision,
2244
+ route: relay.decision.policy === "require" ? "unavailable" : "legacy",
2245
+ reason: "handoff-error"
2246
+ };
2247
+ if (relay.decision.policy === "require") {
2248
+ publishRelayDecision(relayDecision);
2249
+ throw new ChromeDevtoolsRelayRequiredError(relayDecision);
2250
+ }
2251
+ commandArgs = [...resolvedArgs];
2252
+ }
2253
+ }
2254
+ const transportEnv = handoff?.env ?? mergedEnv;
2255
+ const compat = applyChromeDevtoolsCompat(transportEnv, command, commandArgs);
2256
+ if (compat.applied) {
2257
+ logger.info(`Injecting chrome-devtools-mcp --autoConnect compatibility patch from ${compat.patchPath}.`);
2258
+ }
2259
+ if (relayDecision)
2260
+ publishRelayDecision(relayDecision);
2261
+ rawTransport = new McporterStdioTransport({
2262
+ command,
2263
+ args: commandArgs,
2264
+ cwd: definition.command.cwd,
2265
+ env: compat.env,
2266
+ cleanup: activeProxy ? async () => {
2267
+ await handoff?.close();
2268
+ await activeProxy?.close();
2269
+ } : void 0
2270
+ });
2271
+ } catch (error) {
2272
+ await handoff?.close().catch(() => {
2273
+ });
2274
+ await activeProxy?.close().catch(() => {
2275
+ });
2276
+ throw error;
2277
+ }
2278
+ let transport;
2279
+ try {
2280
+ transport = wrapRecordTransport(rawTransport, definition, options);
2281
+ } catch (error) {
2282
+ await closeTransportAndWait(logger, rawTransport).catch(() => {
2283
+ });
2284
+ throw error;
2285
+ }
2437
2286
  try {
2438
2287
  await client.connect(transport, { signal: options.signal });
2439
2288
  } catch (error) {
2440
- if (!options.signal?.aborted) {
2441
- await closeTransportAndWait(logger, transport).catch(() => {
2442
- });
2443
- }
2289
+ await closeTransportAndWait(logger, transport).catch(() => {
2290
+ });
2444
2291
  throw error;
2445
2292
  }
2446
2293
  return { client, transport, definition, oauthSession: void 0 };
@@ -2477,7 +2324,7 @@ async function createClientContext(definition, logger, clientInfo, options = {})
2477
2324
  });
2478
2325
  }
2479
2326
 
2480
- // node_modules/.pnpm/mcporter@0.13.0/node_modules/mcporter/dist/runtime/connection-cache.js
2327
+ // node_modules/.pnpm/mcporter@0.13.6/node_modules/mcporter/dist/runtime/connection-cache.js
2481
2328
  var RuntimeConnectionCache = class {
2482
2329
  definitions;
2483
2330
  options;
@@ -3030,7 +2877,7 @@ function connectionInfoFromClient(client) {
3030
2877
  };
3031
2878
  }
3032
2879
 
3033
- // node_modules/.pnpm/mcporter@0.13.0/node_modules/mcporter/dist/tool-filters.js
2880
+ // node_modules/.pnpm/mcporter@0.13.6/node_modules/mcporter/dist/tool-filters.js
3034
2881
  function validateToolFilters(name, filter) {
3035
2882
  if (filter.allowedTools !== void 0 && filter.blockedTools !== void 0) {
3036
2883
  throw new Error(`Server '${name}' cannot specify both allowedTools and blockedTools.`);
@@ -3052,7 +2899,7 @@ function filterTools(tools, filter) {
3052
2899
  return tools.filter((tool) => isToolAllowed(tool.name, filter));
3053
2900
  }
3054
2901
 
3055
- // node_modules/.pnpm/mcporter@0.13.0/node_modules/mcporter/dist/runtime.js
2902
+ // node_modules/.pnpm/mcporter@0.13.6/node_modules/mcporter/dist/runtime.js
3056
2903
  var PACKAGE_NAME = "mcporter";
3057
2904
  var OAUTH_CODE_TIMEOUT_MS = resolveOAuthTimeoutFromEnv();
3058
2905
  var MAX_RESOURCE_LIST_PAGES = 100;