@introspection-ai/recipes 0.25.1 → 0.26.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 (98) hide show
  1. package/dist/mcp-chunks/{auth-command-4WFRNU2I.js → auth-command-JBYNHHMV.js} +23 -27
  2. package/dist/mcp-chunks/call-arguments-S4EGFKUQ.js +15 -0
  3. package/dist/mcp-chunks/{call-command-JBIKXOGC.js → call-command-467BVXTE.js} +32 -33
  4. package/dist/mcp-chunks/{chunk-IPNSPKQK.js → chunk-3Q2Q7SBU.js} +12 -14
  5. package/dist/mcp-chunks/chunk-66P5FXP3.js +31 -0
  6. package/dist/mcp-chunks/{chunk-TF2YTYE4.js → chunk-6DVS7RBO.js} +1 -1
  7. package/dist/mcp-chunks/{chunk-IME7DGLJ.js → chunk-AK5ZEDEF.js} +2 -2
  8. package/dist/mcp-chunks/{chunk-OP3IW2V6.js → chunk-AP5VHS73.js} +2 -2
  9. package/dist/mcp-chunks/{chunk-B2LNXGAP.js → chunk-AS27BTCS.js} +1 -1
  10. package/dist/mcp-chunks/{chunk-MOEZ43ZL.js → chunk-BC2HDCYV.js} +1 -1
  11. package/dist/mcp-chunks/{chunk-RSTKSBVF.js → chunk-BSCNF4NY.js} +2 -2
  12. package/dist/mcp-chunks/chunk-BTU34BUG.js +1182 -0
  13. package/dist/mcp-chunks/{chunk-HN7WPMCA.js → chunk-CN5YF3IQ.js} +21042 -3688
  14. package/dist/mcp-chunks/{chunk-G6OMDUNG.js → chunk-CZ43ZITK.js} +1 -1
  15. package/dist/mcp-chunks/{chunk-JG4TRUPF.js → chunk-D2P2IV4H.js} +1 -1
  16. package/dist/mcp-chunks/{chunk-3R2WK3NB.js → chunk-DMBE47LM.js} +6 -6
  17. package/dist/mcp-chunks/{chunk-WTMJMM3B.js → chunk-EP22XMWK.js} +3 -30
  18. package/dist/mcp-chunks/{chunk-ITCCROID.js → chunk-EUDC3ICZ.js} +5 -5
  19. package/dist/mcp-chunks/{chunk-FX5NYWBH.js → chunk-G4H535MI.js} +3 -21
  20. package/dist/mcp-chunks/{chunk-HCOKLSOB.js → chunk-GA4ZYSRX.js} +4 -4
  21. package/dist/mcp-chunks/{chunk-C2KNLFZR.js → chunk-GEVQ2GJW.js} +2 -2
  22. package/dist/mcp-chunks/{chunk-WYLHHXI6.js → chunk-GK4LA4E6.js} +26 -11
  23. package/dist/mcp-chunks/{chunk-QZUC2T72.js → chunk-GL4AA5QV.js} +2 -2
  24. package/dist/mcp-chunks/{chunk-KW3ANJ36.js → chunk-HBN3ESMH.js} +4 -4
  25. package/dist/mcp-chunks/{chunk-ELA77TDC.js → chunk-HKZZGSDV.js} +4 -4
  26. package/dist/mcp-chunks/{chunk-36VIJRYY.js → chunk-HTXQPQPB.js} +4 -4
  27. package/dist/mcp-chunks/{chunk-3JGS7LQB.js → chunk-I7JR2GIC.js} +2 -2
  28. package/dist/mcp-chunks/{chunk-AIKLVBYU.js → chunk-IO2IMWYS.js} +2 -2
  29. package/dist/mcp-chunks/{chunk-RD7NHCRK.js → chunk-J2WP6ERZ.js} +39 -42
  30. package/dist/mcp-chunks/{chunk-HLRCUHNO.js → chunk-KJNNO5Z6.js} +1 -1
  31. package/dist/mcp-chunks/{chunk-4ZNBWL65.js → chunk-L2LGMX5P.js} +2 -2
  32. package/dist/mcp-chunks/chunk-LG3GLOSA.js +513 -0
  33. package/dist/mcp-chunks/{chunk-CZKDJZER.js → chunk-LTR626QF.js} +1 -1
  34. package/dist/mcp-chunks/{chunk-FS5JIKT6.js → chunk-LYWEATXZ.js} +6 -6
  35. package/dist/mcp-chunks/{chunk-YIRGLKDA.js → chunk-M62ESEOY.js} +45 -14
  36. package/dist/mcp-chunks/{chunk-V5AYEKSL.js → chunk-MJHMXYMO.js} +52 -81
  37. package/dist/mcp-chunks/{chunk-7WOKCV6Q.js → chunk-N7ZWX3WW.js} +1 -1
  38. package/dist/mcp-chunks/chunk-NTABJCUL.js +123 -0
  39. package/dist/mcp-chunks/{chunk-EPT4MYOF.js → chunk-OABFKFSL.js} +11 -11
  40. package/dist/mcp-chunks/{chunk-SCOMDV54.js → chunk-OB256NMD.js} +1 -1
  41. package/dist/mcp-chunks/{chunk-IYWYVHHD.js → chunk-OZQTZWW4.js} +1 -1
  42. package/dist/mcp-chunks/{chunk-ITR7FQM3.js → chunk-QIBGY4IX.js} +2 -2
  43. package/dist/mcp-chunks/{chunk-ZOAQDFAO.js → chunk-REEFOL44.js} +1 -1
  44. package/dist/mcp-chunks/{chunk-ED2WN5BI.js → chunk-SUNOYTQJ.js} +3 -3
  45. package/dist/mcp-chunks/{chunk-Y3EDWN2P.js → chunk-TFU4NKFJ.js} +1 -1
  46. package/dist/mcp-chunks/{chunk-EMSNQHZZ.js → chunk-TGPIW6F6.js} +1 -1
  47. package/dist/mcp-chunks/{chunk-SNKXMWDB.js → chunk-UCJ7YDFN.js} +1 -1
  48. package/dist/mcp-chunks/{chunk-TPHPAEDH.js → chunk-WUEDIOR5.js} +1 -1
  49. package/dist/mcp-chunks/{chunk-FAJPJTOC.js → chunk-XCNWICLD.js} +1 -1
  50. package/dist/mcp-chunks/{chunk-6YZW3XAE.js → chunk-XFQSUC7T.js} +5 -5
  51. package/dist/mcp-chunks/{chunk-GQ6NSIDS.js → chunk-Y3L5LWBY.js} +3037 -747
  52. package/dist/mcp-chunks/{chunk-53NRFMB3.js → chunk-YI5SMRFH.js} +46 -25
  53. package/dist/mcp-chunks/{chunk-GUXMP7QB.js → chunk-YPTN46JQ.js} +2 -2
  54. package/dist/mcp-chunks/{chunk-I5GI2A2D.js → chunk-YVH36MGQ.js} +2 -2
  55. package/dist/mcp-chunks/{chunk-ASG4OY3M.js → chunk-Z6QEOUMK.js} +22 -23
  56. package/dist/mcp-chunks/{cli-XU26MUCN.js → cli-TN6JTLTS.js} +108 -77
  57. package/dist/mcp-chunks/client-G33HPQAC.js +29 -0
  58. package/dist/mcp-chunks/{config-command-UQMMIK2U.js → config-command-LICU56ZH.js} +27 -28
  59. package/dist/mcp-chunks/daemon-command-JLVHGWHB.js +29 -0
  60. package/dist/mcp-chunks/{dist-DM2RXZMU.js → dist-MFAWSKGH.js} +80 -46
  61. package/dist/mcp-chunks/{emit-ts-command-KAOL6DAN.js → emit-ts-command-FVX3JMSN.js} +18 -18
  62. package/dist/mcp-chunks/{generate-cli-runner-AK6XNRTK.js → generate-cli-runner-L2L7VMCA.js} +53 -51
  63. package/dist/mcp-chunks/generated-daemon-runtime-DC6IL7E7.js +29 -0
  64. package/dist/mcp-chunks/{inspect-cli-command-6FVJO7H2.js → inspect-cli-command-Y5D3GRE2.js} +9 -10
  65. package/dist/mcp-chunks/{launch-EIT73HX4.js → launch-ZFY6CM2A.js} +1 -1
  66. package/dist/mcp-chunks/{lifecycle-QH4TUI3K.js → lifecycle-H7DIW5DM.js} +1 -1
  67. package/dist/mcp-chunks/{list-command-UOB2XZK7.js → list-command-55LCLW4S.js} +34 -35
  68. package/dist/mcp-chunks/{output-utils-6YXH23T7.js → output-utils-YYHI637S.js} +3 -3
  69. package/dist/mcp-chunks/{prompt-CH6TK0bC-ZB6RFAXR.js → prompt-CH6TK0bC-DZLFAAPK.js} +1 -1
  70. package/dist/mcp-chunks/{record-command-FO5TTERC.js → record-command-PWIBYC5J.js} +5 -5
  71. package/dist/mcp-chunks/{replay-command-SCBPCGQ7.js → replay-command-QHZZZMXF.js} +6 -6
  72. package/dist/mcp-chunks/{resource-command-S2J7XEMV.js → resource-command-HMR2KXWK.js} +9 -10
  73. package/dist/mcp-chunks/{result-utils-OME6HGS6.js → result-utils-UGCQSRJ4.js} +3 -4
  74. package/dist/mcp-chunks/runtime-ZNFPZXKE.js +36 -0
  75. package/dist/mcp-chunks/runtime-wrapper-I4B3OROR.js +10 -0
  76. package/dist/mcp-chunks/{serve-command-DDBZZSG6.js → serve-command-NTDI3YPN.js} +29 -34
  77. package/dist/mcp-chunks/{timeouts-HNGNKDQN.js → timeouts-35UDWFA7.js} +3 -3
  78. package/dist/mcp-chunks/{vault-command-TJZYS3YI.js → vault-command-D5QZL4FI.js} +4 -6
  79. package/dist/mcp-daemon.js +26 -31
  80. package/dist/mcp-run-worker.js +26 -31
  81. package/docs/pi-extension.md +1 -1
  82. package/docs/recipe-format.md +7 -3
  83. package/docs/recipe-templates.md +46 -0
  84. package/package.json +14 -14
  85. package/dist/mcp-chunks/call-arguments-4DWPBLQP.js +0 -15
  86. package/dist/mcp-chunks/chunk-3Z7MFS6K.js +0 -86
  87. package/dist/mcp-chunks/chunk-AD3FQ73K.js +0 -39
  88. package/dist/mcp-chunks/chunk-BWW4XRUC.js +0 -1931
  89. package/dist/mcp-chunks/chunk-DTZHEVKC.js +0 -12
  90. package/dist/mcp-chunks/chunk-H3JCYHGS.js +0 -1018
  91. package/dist/mcp-chunks/chunk-IRTJXFWA.js +0 -28
  92. package/dist/mcp-chunks/chunk-NTHUNCXJ.js +0 -526
  93. package/dist/mcp-chunks/chunk-OD3MSMXY.js +0 -15
  94. package/dist/mcp-chunks/chunk-PZ323CXI.js +0 -17394
  95. package/dist/mcp-chunks/client-OT34CKRH.js +0 -21
  96. package/dist/mcp-chunks/daemon-command-YCIOZGPZ.js +0 -35
  97. package/dist/mcp-chunks/runtime-QIPMLIJI.js +0 -39
  98. package/dist/mcp-chunks/runtime-wrapper-X4YFKMJI.js +0 -16
@@ -0,0 +1,1182 @@
1
+ import { createRequire as __createRequire } from "node:module"; const require = __createRequire(import.meta.url);
2
+ import {
3
+ BrowserOwner,
4
+ authorizeBrokerDefinition,
5
+ connectionIdentity,
6
+ createRuntime,
7
+ daemonRunDir,
8
+ effectiveDefinition,
9
+ filterTools,
10
+ getChromeDevtoolsRelayDecision,
11
+ getDaemonMetadataPath,
12
+ getDaemonSocketPath,
13
+ inspectLegacyDaemonDirectory,
14
+ isChromeDefinition,
15
+ isToolAllowed,
16
+ resolveSystemPowerShellPath,
17
+ secureDaemonDirectory,
18
+ upgradeLegacyDaemonDirectory
19
+ } from "./chunk-Y3L5LWBY.js";
20
+ import {
21
+ NON_INTERACTIVE_ELICITATION_HINT,
22
+ createNonInteractiveElicitationResponder
23
+ } from "./chunk-REEFOL44.js";
24
+ import {
25
+ isOAuthFlowError,
26
+ resolveOAuthTimeoutFromEnv
27
+ } from "./chunk-M62ESEOY.js";
28
+ import {
29
+ withRuntimeEnvironment
30
+ } from "./chunk-YI5SMRFH.js";
31
+ import {
32
+ MCPORTER_VERSION
33
+ } from "./chunk-NTABJCUL.js";
34
+ import {
35
+ normalizeTimeout
36
+ } from "./chunk-YVH36MGQ.js";
37
+ import {
38
+ RawEntrySchema,
39
+ loadServerDefinitions
40
+ } from "./chunk-J2WP6ERZ.js";
41
+ import {
42
+ isProcessRunning,
43
+ withFileLock,
44
+ writeJsonFile
45
+ } from "./chunk-QIBGY4IX.js";
46
+ import {
47
+ mcporterDir
48
+ } from "./chunk-LYWEATXZ.js";
49
+ import {
50
+ isKeepAliveServer
51
+ } from "./chunk-D2P2IV4H.js";
52
+ import {
53
+ SdkErrorCode,
54
+ external_exports
55
+ } from "./chunk-CN5YF3IQ.js";
56
+
57
+ // node_modules/.pnpm/mcporter@0.13.10/node_modules/mcporter/dist/daemon/socket-rpc.js
58
+ import { createHmac, randomBytes, timingSafeEqual } from "node:crypto";
59
+ import fs from "node:fs/promises";
60
+ import net from "node:net";
61
+ import path from "node:path";
62
+
63
+ // node_modules/.pnpm/mcporter@0.13.10/node_modules/mcporter/dist/daemon/protocol.js
64
+ var DAEMON_PROTOCOL_VERSION = 3;
65
+ var MAX_DAEMON_PAYLOAD_BYTES = 4 * 1024 * 1024;
66
+ var DAEMON_PROGRESS_INTERVAL_MS = 250;
67
+ var MIN_DAEMON_PROGRESS_INTERVAL_MS = 25;
68
+ var DAEMON_PROGRESS_SCHEDULING_SLACK_MS = MIN_DAEMON_PROGRESS_INTERVAL_MS;
69
+ function resolveProgressInterval(requestedIntervalMs) {
70
+ if (requestedIntervalMs >= DAEMON_PROGRESS_INTERVAL_MS)
71
+ return DAEMON_PROGRESS_INTERVAL_MS;
72
+ if (requestedIntervalMs >= 100)
73
+ return 100;
74
+ if (requestedIntervalMs >= 50)
75
+ return 50;
76
+ return MIN_DAEMON_PROGRESS_INTERVAL_MS;
77
+ }
78
+ function resolveProgressTiming(requestedIdleTimeoutMs) {
79
+ const idleTimeoutMs = normalizeTimeout(requestedIdleTimeoutMs) ?? DAEMON_PROGRESS_INTERVAL_MS * 3 + DAEMON_PROGRESS_SCHEDULING_SLACK_MS;
80
+ const progressIntervalMs = resolveProgressInterval(Math.floor(idleTimeoutMs / 3));
81
+ return {
82
+ progressIntervalMs,
83
+ // Keep three frame opportunities plus scheduler slack inside the socket idle budget.
84
+ idleTimeoutMs: Math.max(idleTimeoutMs, progressIntervalMs * 3 + DAEMON_PROGRESS_SCHEDULING_SLACK_MS)
85
+ };
86
+ }
87
+
88
+ // node_modules/.pnpm/mcporter@0.13.10/node_modules/mcporter/dist/daemon/socket-rpc.js
89
+ async function daemonKey() {
90
+ await secureDaemonDirectory();
91
+ const file = path.join(daemonRunDir(), "user.key");
92
+ return withFileLock(file, async () => {
93
+ try {
94
+ await fs.writeFile(file, randomBytes(32), { flag: "wx", mode: 384 });
95
+ } catch (error) {
96
+ if (error.code !== "EEXIST")
97
+ throw error;
98
+ }
99
+ const info = await fs.lstat(file);
100
+ if (!info.isFile() || info.isSymbolicLink() || process.platform !== "win32" && (info.uid !== process.getuid?.() || (info.mode & 63) !== 0))
101
+ throw new Error("Unsafe daemon authentication key ownership.");
102
+ const key = await fs.readFile(file);
103
+ if (key.length !== 32)
104
+ throw new Error("Invalid daemon authentication key.");
105
+ return key;
106
+ });
107
+ }
108
+ var SocketFrames = class {
109
+ socket;
110
+ buffer = "";
111
+ queue = [];
112
+ pending;
113
+ failure;
114
+ bytes = 0;
115
+ constructor(socket) {
116
+ this.socket = socket;
117
+ socket.setEncoding("utf8");
118
+ socket.on("data", (chunk) => {
119
+ this.bytes += Buffer.byteLength(chunk);
120
+ if (this.bytes > MAX_DAEMON_PAYLOAD_BYTES * 2) {
121
+ this.fail(new Error("Daemon frame limit exceeded."));
122
+ return;
123
+ }
124
+ this.buffer += chunk;
125
+ let newline;
126
+ while ((newline = this.buffer.indexOf("\n")) !== -1) {
127
+ const line = this.buffer.slice(0, newline);
128
+ this.buffer = this.buffer.slice(newline + 1);
129
+ this.bytes = Buffer.byteLength(this.buffer);
130
+ try {
131
+ const value = JSON.parse(line);
132
+ if (this.pending) {
133
+ const pending2 = this.pending;
134
+ this.pending = void 0;
135
+ pending2.resolve(value);
136
+ } else if (this.queue.length < 8)
137
+ this.queue.push(value);
138
+ else {
139
+ this.fail(new Error("Too many daemon frames."));
140
+ return;
141
+ }
142
+ } catch {
143
+ this.fail(new Error("Malformed daemon frame."));
144
+ return;
145
+ }
146
+ }
147
+ });
148
+ socket.on("error", (error) => this.fail(error));
149
+ socket.on("end", () => this.fail(new Error("Daemon connection ended.")));
150
+ }
151
+ fail(error) {
152
+ this.failure ??= error;
153
+ this.pending?.reject(error);
154
+ this.pending = void 0;
155
+ this.socket.destroy();
156
+ }
157
+ read() {
158
+ if (this.queue.length)
159
+ return Promise.resolve(this.queue.shift());
160
+ if (this.failure)
161
+ return Promise.reject(this.failure);
162
+ return new Promise((resolve, reject) => {
163
+ this.pending = { resolve, reject };
164
+ });
165
+ }
166
+ write(value) {
167
+ this.socket.write(`${JSON.stringify(value)}
168
+ `);
169
+ }
170
+ };
171
+ function proof(key, role, client, server) {
172
+ return createHmac("sha256", key).update(`mcporter-v3\0${role}\0${client}\0${server}`).digest("hex");
173
+ }
174
+ function nonce(value) {
175
+ return typeof value === "string" && /^[a-f0-9]{64}$/.test(value);
176
+ }
177
+ function checkProof(actual, expected) {
178
+ if (!nonce(actual) || !timingSafeEqual(Buffer.from(actual, "hex"), Buffer.from(expected, "hex")))
179
+ throw new Error("Daemon authentication failed; no configuration sent.");
180
+ }
181
+ async function authenticateServer(frames, key) {
182
+ const hello = await frames.read();
183
+ if (!hello || !nonce(hello.hello))
184
+ throw new Error("Invalid daemon hello.");
185
+ const server = randomBytes(32).toString("hex");
186
+ frames.write({ nonce: server, proof: proof(key, "server", hello.hello, server) });
187
+ const auth = await frames.read();
188
+ checkProof(auth?.proof, proof(key, "client", hello.hello, server));
189
+ frames.write({ authenticated: true });
190
+ }
191
+ async function authenticateClient(frames, key) {
192
+ const client = randomBytes(32).toString("hex");
193
+ frames.write({ hello: client });
194
+ const hello = await frames.read();
195
+ if (!hello || !nonce(hello.nonce))
196
+ throw new Error("Invalid daemon authentication response.");
197
+ checkProof(hello.proof, proof(key, "server", client, hello.nonce));
198
+ frames.write({ proof: proof(key, "client", client, hello.nonce) });
199
+ const ack = await frames.read();
200
+ if (!ack?.authenticated)
201
+ throw new Error("Daemon authentication failed.");
202
+ }
203
+ async function requestDaemon(socketPath, request, idleTimeoutMs) {
204
+ const key = await daemonKey();
205
+ const socket = net.createConnection(socketPath);
206
+ const frames = new SocketFrames(socket);
207
+ socket.setTimeout(idleTimeoutMs, () => socket.destroy(Object.assign(new Error("Daemon request timed out; outcome unknown, not replayed."), { code: "ETIMEDOUT" })));
208
+ try {
209
+ await authenticateClient(frames, key);
210
+ frames.write(request);
211
+ for (; ; ) {
212
+ const response = await frames.read();
213
+ if (!response || response.id !== request.id)
214
+ throw new Error("Mismatched daemon response.");
215
+ if (response.type === "progress")
216
+ continue;
217
+ if (typeof response.ok !== "boolean")
218
+ throw new Error("Invalid daemon response.");
219
+ return response;
220
+ }
221
+ } finally {
222
+ key.fill(0);
223
+ socket.destroy();
224
+ }
225
+ }
226
+
227
+ // node_modules/.pnpm/mcporter@0.13.10/node_modules/mcporter/dist/daemon/client.js
228
+ import { randomUUID as randomUUID3 } from "node:crypto";
229
+ import fs3 from "node:fs/promises";
230
+
231
+ // node_modules/.pnpm/mcporter@0.13.10/node_modules/mcporter/dist/daemon/process-retirement.js
232
+ import { execFile } from "node:child_process";
233
+ import { promisify } from "node:util";
234
+ var exec = promisify(execFile);
235
+ var MAX_TARGETS = 256;
236
+ var MAX_TREE = 1024;
237
+ var pending = [];
238
+ var ProcessObservationError = class extends Error {
239
+ code = "process_observation_failed";
240
+ };
241
+ function observationFailure(detail) {
242
+ return new ProcessObservationError(`Windows process observation ${detail}; retirement remains blocked. Check Windows process query access and retry.`);
243
+ }
244
+ var sid = (candidate) => typeof candidate === "string" && /^S-\d+(?:-\d+)+$/.test(candidate);
245
+ function decodeWindowsInventory(stdout) {
246
+ let value;
247
+ try {
248
+ value = JSON.parse(stdout.replace(/^\uFEFF/, ""));
249
+ } catch {
250
+ throw observationFailure("returned invalid or empty JSON");
251
+ }
252
+ if (!value || value.version !== 1 || !sid(value.owner) || !Array.isArray(value.processes) || value.processes.length > MAX_TREE)
253
+ throw observationFailure("returned an invalid completion envelope");
254
+ const seen = /* @__PURE__ */ new Set();
255
+ for (const item of value.processes) {
256
+ if (!item || !Number.isSafeInteger(item.pid) || item.pid <= 0 || seen.has(item.pid) || !Number.isSafeInteger(item.parent) || item.parent < 0 || item.owner !== null && !sid(item.owner) || item.born !== null && (typeof item.born !== "string" || !/^\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d\.\d{7}Z$/.test(item.born) || !Number.isFinite(Date.parse(item.born))))
257
+ throw observationFailure("returned an invalid process identity");
258
+ seen.add(item.pid);
259
+ }
260
+ return value;
261
+ }
262
+ async function windowsInventory(requests) {
263
+ const roots = [...new Set(requests.filter((r) => r.tree).flatMap((r) => r.pids))];
264
+ const targets = [...new Set(requests.flatMap((r) => r.pids))];
265
+ const query = "SELECT Handle,ProcessId,ParentProcessId,CreationDate FROM Win32_Process" + (roots.length ? "" : ` WHERE ${targets.map((pid) => `ProcessId=${pid}`).join(" OR ")}`);
266
+ const script = String.raw`
267
+ $ErrorActionPreference='Stop'
268
+ [Console]::OutputEncoding = New-Object System.Text.UTF8Encoding($false)
269
+ try {
270
+ Add-Type -AssemblyName System.Management
271
+ $sid=[System.Security.Principal.WindowsIdentity]::GetCurrent().User.Value
272
+ $searcher=New-Object System.Management.ManagementObjectSearcher('${query}')
273
+ $rows=@($searcher.Get())
274
+ $selected=@{}
275
+ foreach ($target in @(${targets.join(",")})) { $selected[[int]$target]=$true }
276
+ $frontier=@(${roots.join(",")})
277
+ $descendants=@{}
278
+ foreach ($root in $frontier) { $descendants[[int]$root]=$true }
279
+ while ($frontier.Count -gt 0) {
280
+ $next=@()
281
+ foreach ($item in $rows) {
282
+ if ($frontier -contains [int]$item.ParentProcessId -and -not $descendants.ContainsKey([int]$item.ProcessId)) {
283
+ $descendants[[int]$item.ProcessId]=$true
284
+ $selected[[int]$item.ProcessId]=$true
285
+ $next+=([int]$item.ProcessId)
286
+ if ($selected.Count -gt ${MAX_TREE}) { throw 'tree limit' }
287
+ }
288
+ }
289
+ $frontier=$next
290
+ }
291
+ $items=@(foreach ($item in $rows) {
292
+ if (-not $selected.ContainsKey([int]$item.ProcessId)) { continue }
293
+ $born=$null
294
+ if ($null -ne $item.CreationDate) { $born=[System.Management.ManagementDateTimeConverter]::ToDateTime($item.CreationDate).ToUniversalTime().ToString('o') }
295
+ $owner=$null
296
+ try {
297
+ $ownerArgs=[object[]]@('')
298
+ if ($item.InvokeMethod('GetOwnerSid',$ownerArgs) -eq 0) { $owner=[string]$ownerArgs[0] }
299
+ } catch { $owner=$null }
300
+ @{pid=[int]$item.ProcessId;parent=[int]$item.ParentProcessId;owner=$owner;born=$born}
301
+ })
302
+ # Bind owner results to the same start identities; an exited process is definite absence.
303
+ $filter=($selected.Keys | ForEach-Object { 'ProcessId='+$_ }) -join ' OR '
304
+ $verify=New-Object System.Management.ManagementObjectSearcher("SELECT Handle,ProcessId,ParentProcessId,CreationDate FROM Win32_Process WHERE $filter")
305
+ $current=@{}
306
+ foreach ($item in $verify.Get()) { $current[[int]$item.ProcessId]=$item }
307
+ $checked=@(foreach ($item in $items) {
308
+ $now=$current[$item.pid]
309
+ if ($null -eq $now) { continue }
310
+ $born=$null
311
+ if ($null -ne $now.CreationDate) { $born=[System.Management.ManagementDateTimeConverter]::ToDateTime($now.CreationDate).ToUniversalTime().ToString('o') }
312
+ if ($born -ne $item.born) { $item.owner=$null; $item.born=$null }
313
+ $item
314
+ })
315
+ [Console]::Write((@{version=1;owner=$sid;processes=$checked}|ConvertTo-Json -Compress -Depth 4))
316
+ } catch { exit 1 }
317
+ `;
318
+ let stdout;
319
+ try {
320
+ ({ stdout } = await exec(resolveSystemPowerShellPath(), [
321
+ "-NoLogo",
322
+ "-NoProfile",
323
+ "-NonInteractive",
324
+ "-EncodedCommand",
325
+ Buffer.from(script, "utf16le").toString("base64")
326
+ ], { timeout: 5e3, maxBuffer: 4 * 1024 * 1024, windowsHide: true, encoding: "utf8" }));
327
+ } catch {
328
+ throw observationFailure("failed");
329
+ }
330
+ return decodeWindowsInventory(stdout);
331
+ }
332
+ async function processInventory(pids, tree = false) {
333
+ if (!pids.length || pids.length > MAX_TARGETS || pids.some((pid) => !Number.isSafeInteger(pid) || pid <= 0))
334
+ throw new Error("Invalid process observation targets.");
335
+ if (process.platform === "win32") {
336
+ return new Promise((resolve, reject) => {
337
+ pending.push({ pids: [...pids], tree, resolve, reject });
338
+ if (pending.length !== 1)
339
+ return;
340
+ queueMicrotask(() => {
341
+ const requests = pending;
342
+ pending = [];
343
+ let batch = [];
344
+ let count = 0;
345
+ const run = (group) => {
346
+ void windowsInventory(group).then((inventory) => {
347
+ for (const request of group)
348
+ request.resolve(inventory);
349
+ }, (error) => {
350
+ for (const request of group)
351
+ request.reject(error);
352
+ });
353
+ };
354
+ for (const request of requests) {
355
+ if (count + request.pids.length > MAX_TARGETS) {
356
+ run(batch);
357
+ batch = [];
358
+ count = 0;
359
+ }
360
+ batch.push(request);
361
+ count += request.pids.length;
362
+ }
363
+ run(batch);
364
+ });
365
+ });
366
+ }
367
+ const { stdout } = await exec("/bin/ps", ["-axo", "pid=,ppid=,uid=,lstart="], {
368
+ timeout: 5e3,
369
+ maxBuffer: 4 * 1024 * 1024
370
+ });
371
+ const processes = stdout.trim().split("\n").map((line) => {
372
+ const match = /^\s*(\d+)\s+(\d+)\s+(-?\d+)\s+(.+)$/.exec(line);
373
+ if (!match)
374
+ throw new Error("Invalid process observation; retirement remains blocked.");
375
+ return { pid: Number(match[1]), parent: Number(match[2]), owner: match[3], born: match[4].trim() };
376
+ });
377
+ return { owner: String(process.getuid?.()), processes };
378
+ }
379
+ async function ownedProcessTree(pid) {
380
+ const inventory = await processInventory([pid], true);
381
+ const root = inventory.processes.find((p) => p.pid === pid);
382
+ if (!root || !root.born || root.owner !== inventory.owner)
383
+ throw new Error("Legacy daemon process ownership could not be verified.");
384
+ const result = [root];
385
+ for (let i = 0; i < result.length; i++)
386
+ for (const p of inventory.processes)
387
+ if (p.parent === result[i].pid && !result.some((item) => item.pid === p.pid)) {
388
+ if (!p.born || p.owner !== inventory.owner)
389
+ throw new Error("Legacy child ownership could not be verified.");
390
+ result.push(p);
391
+ }
392
+ return result;
393
+ }
394
+ async function awaitRetirement(identities) {
395
+ if (!identities.length)
396
+ return;
397
+ const deadline = Date.now() + 5e3;
398
+ while (Date.now() < deadline) {
399
+ let alive = false;
400
+ for (let offset = 0; offset < identities.length; offset += MAX_TARGETS) {
401
+ const batch = identities.slice(offset, offset + MAX_TARGETS);
402
+ const { processes } = await processInventory(batch.map((item) => item.pid));
403
+ for (const old of batch) {
404
+ const current = processes.find((item) => item.pid === old.pid);
405
+ if (!current)
406
+ continue;
407
+ if (!current.born || !current.owner)
408
+ throw new Error("Process ownership could not be verified; retirement remains blocked.");
409
+ if (current.born === old.born.trim()) {
410
+ if (current.owner !== old.owner)
411
+ throw new Error("Process ownership could not be verified; retirement remains blocked.");
412
+ alive = true;
413
+ }
414
+ }
415
+ }
416
+ if (!alive)
417
+ return;
418
+ await new Promise((r) => setTimeout(r, 50));
419
+ }
420
+ throw new Error("Verified legacy processes have not retired; cutover remains blocked. No process was signalled.");
421
+ }
422
+
423
+ // node_modules/.pnpm/mcporter@0.13.10/node_modules/mcporter/dist/daemon/migration.js
424
+ import fs2 from "node:fs/promises";
425
+ import net2 from "node:net";
426
+ import path2 from "node:path";
427
+ import { randomUUID as randomUUID2 } from "node:crypto";
428
+
429
+ // node_modules/.pnpm/mcporter@0.13.10/node_modules/mcporter/dist/daemon/idle-timer.js
430
+ var MAX_NATIVE_TIMER_MS = 2147483647;
431
+ function idleTimerDelay(timeoutMs, lastActivity) {
432
+ const remaining = timeoutMs - (Date.now() - lastActivity);
433
+ return Math.min(MAX_NATIVE_TIMER_MS, Math.max(1, remaining > 0 ? remaining : timeoutMs));
434
+ }
435
+
436
+ // node_modules/.pnpm/mcporter@0.13.10/node_modules/mcporter/dist/daemon/broker.js
437
+ import { AsyncLocalStorage } from "node:async_hooks";
438
+ import { randomUUID } from "node:crypto";
439
+
440
+ // node_modules/.pnpm/mcporter@0.13.10/node_modules/mcporter/dist/daemon/view-codec.js
441
+ var command = external_exports.discriminatedUnion("kind", [
442
+ external_exports.object({
443
+ kind: external_exports.literal("stdio"),
444
+ command: external_exports.string().min(1),
445
+ args: external_exports.array(external_exports.string()).max(1024),
446
+ cwd: external_exports.string().min(1)
447
+ }).strict(),
448
+ external_exports.object({ kind: external_exports.literal("http"), url: external_exports.string().url(), headers: external_exports.record(external_exports.string(), external_exports.string()).optional() }).strict()
449
+ ]);
450
+ var definition = external_exports.object({
451
+ ...RawEntrySchema.shape,
452
+ name: external_exports.string().min(1).max(256),
453
+ configuredEnv: external_exports.record(external_exports.string(), external_exports.string()).optional(),
454
+ launchCommand: external_exports.string().min(1).optional(),
455
+ command,
456
+ lifecycle: external_exports.object({ mode: external_exports.enum(["keep-alive", "ephemeral"]), idleTimeoutMs: external_exports.number().positive().optional() }).optional(),
457
+ source: external_exports.unknown().optional(),
458
+ sources: external_exports.unknown().optional()
459
+ }).strip();
460
+ var registration = external_exports.object({
461
+ definitions: external_exports.array(definition).max(256),
462
+ clientInfo: external_exports.object({ name: external_exports.string().min(1).max(256), version: external_exports.string().min(1).max(256) }).optional()
463
+ }).strict();
464
+ function decodeView(value) {
465
+ const parsed = registration.parse(value);
466
+ const names = /* @__PURE__ */ new Set();
467
+ const definitions = parsed.definitions.map((entry) => {
468
+ if (names.has(entry.name))
469
+ throw new Error("Duplicate view alias.");
470
+ names.add(entry.name);
471
+ if (entry.allowedTools && entry.blockedTools)
472
+ throw new Error("Conflicting tool filters.");
473
+ const { source: _source, sources: _sources, ...rest } = entry;
474
+ const decodedCommand = entry.command.kind === "http" ? { kind: "http", url: new URL(entry.command.url), headers: entry.command.headers } : entry.command;
475
+ return Object.assign(rest, { command: decodedCommand });
476
+ });
477
+ return { definitions, clientInfo: parsed.clientInfo };
478
+ }
479
+
480
+ // node_modules/.pnpm/mcporter@0.13.10/node_modules/mcporter/dist/daemon/broker.js
481
+ var notices = new AsyncLocalStorage();
482
+ var BrokerError = class extends Error {
483
+ code;
484
+ constructor(code, message) {
485
+ super(message);
486
+ this.code = code;
487
+ }
488
+ };
489
+ var DaemonBroker = class {
490
+ generation = randomUUID();
491
+ views = /* @__PURE__ */ new Map();
492
+ entries = /* @__PURE__ */ new Map();
493
+ owner;
494
+ draining = false;
495
+ activeRequests = 0;
496
+ constructor(canonical = []) {
497
+ this.owner = new BrowserOwner(canonical);
498
+ }
499
+ register(params) {
500
+ this.expireViews();
501
+ if (this.draining)
502
+ throw new BrokerError("daemon_draining", "Daemon is draining.");
503
+ if (this.views.size >= 1024)
504
+ throw new BrokerError("view_limit", "Too many active config views; release abandoned clients.");
505
+ const { definitions, clientInfo = { name: "mcporter", version: MCPORTER_VERSION } } = decodeView(params);
506
+ const view = randomUUID();
507
+ this.views.set(view, {
508
+ definitions: new Map(definitions.map((def) => [def.name, def])),
509
+ lastUsed: Date.now(),
510
+ active: 0,
511
+ clientInfo
512
+ });
513
+ return { view, generation: this.generation };
514
+ }
515
+ release(request) {
516
+ this.getView(request);
517
+ this.views.delete(request.view);
518
+ }
519
+ getView(request) {
520
+ if (request.generation !== this.generation)
521
+ throw new BrokerError("daemon_generation_changed", "Daemon generation changed; register before a new operation. The request was not replayed.");
522
+ const view = this.views.get(request.view ?? "");
523
+ if (!view)
524
+ throw new BrokerError("view_expired", "Config view expired; register before a new operation.");
525
+ view.lastUsed = Date.now();
526
+ return view;
527
+ }
528
+ async invokeWithNotices(request) {
529
+ const messages = /* @__PURE__ */ new Set();
530
+ const result = await notices.run(messages, () => this.invoke(request));
531
+ return { result, notices: [...messages] };
532
+ }
533
+ makeRuntime(definition2, clientInfo) {
534
+ return withRuntimeEnvironment(definition2.env ?? {}, () => createRuntime({
535
+ servers: [definition2],
536
+ clientInfo,
537
+ logger: { info() {
538
+ }, warn() {
539
+ }, error() {
540
+ } },
541
+ oauthTimeoutMs: resolveOAuthTimeoutFromEnv(),
542
+ elicitationHandler: createNonInteractiveElicitationResponder({
543
+ onDecline: () => notices.getStore()?.add(NON_INTERACTIVE_ELICITATION_HINT)
544
+ }).handler
545
+ }));
546
+ }
547
+ async invoke(request) {
548
+ if (this.draining)
549
+ throw new BrokerError("daemon_draining", "Daemon is draining.");
550
+ const view = this.getView(request);
551
+ const params = request.params;
552
+ if (!params || typeof params.server !== "string")
553
+ throw new BrokerError("invalid_params", "A view-local alias is required.");
554
+ const viewDefinition = view.definitions.get(params.server);
555
+ if (!viewDefinition)
556
+ throw new BrokerError("server_not_in_view", "Server is not authorized in this config view.");
557
+ if (request.method === "closeServer")
558
+ return true;
559
+ if (request.method === "callTool" && (typeof params.tool !== "string" || !isToolAllowed(params.tool, viewDefinition)))
560
+ throw new BrokerError("tool_not_allowed", "Tool is not accessible in this config view (blocked by configuration).");
561
+ if (params.timeoutMs !== void 0 && (!Number.isFinite(params.timeoutMs) || params.timeoutMs <= 0))
562
+ throw new BrokerError("invalid_params", "Invalid timeout.");
563
+ const chrome = isChromeDefinition(viewDefinition);
564
+ if (chrome && JSON.stringify(view.clientInfo) !== JSON.stringify({ name: "mcporter", version: MCPORTER_VERSION }))
565
+ throw new BrokerError("browser_owner_conflict", "Existing Chrome requires the canonical MCP client identity.");
566
+ const definition2 = this.owner.reserve(viewDefinition);
567
+ const identity = connectionIdentity(definition2);
568
+ view.active++;
569
+ this.activeRequests++;
570
+ try {
571
+ const relay = chrome ? await this.owner.resolveIdentity(definition2) : "";
572
+ const policy = definition2.command.kind === "stdio" ? { allowCachedAuth: true, disableOAuth: false } : {
573
+ allowCachedAuth: params.allowCachedAuth ?? true,
574
+ disableOAuth: params.disableOAuth === true || (request.method === "listTools" || request.method === "getServerMetadata") && params.autoAuthorize === false
575
+ };
576
+ const key = `${identity}:${relay}:${JSON.stringify(policy)}:${JSON.stringify(view.clientInfo)}`;
577
+ let entry = this.entries.get(key);
578
+ if (!entry) {
579
+ if (this.entries.size >= 256)
580
+ throw new BrokerError("transport_limit", "Transport capacity reached; drain unused transports with daemon stop.");
581
+ const pooled = { ...definition2, allowedTools: void 0, blockedTools: void 0 };
582
+ authorizeBrokerDefinition(pooled, chrome ? () => this.owner.resolveIdentity(definition2) : void 0);
583
+ entry = {
584
+ id: randomUUID(),
585
+ definition: pooled,
586
+ runtime: this.makeRuntime(pooled, view.clientInfo),
587
+ active: 0,
588
+ lastUsed: Date.now(),
589
+ state: "pending",
590
+ chrome,
591
+ serial: Promise.resolve(),
592
+ generation: 1,
593
+ policy,
594
+ clientInfo: view.clientInfo
595
+ };
596
+ this.entries.set(key, entry);
597
+ }
598
+ const target = entry;
599
+ const run = () => withRuntimeEnvironment(target.definition.env ?? {}, async () => {
600
+ if (chrome)
601
+ await this.owner.resolveIdentity(definition2);
602
+ if (target.state === "retirement-failed")
603
+ throw new BrokerError("transport_retirement_failed", "Old transport retirement is unverified; no replacement was launched.");
604
+ if (target.state === "disconnected" || target.state === "idle") {
605
+ try {
606
+ if (target.state !== "idle")
607
+ await this.retire(target);
608
+ } catch (error) {
609
+ target.state = "retirement-failed";
610
+ throw error;
611
+ }
612
+ target.runtime = this.makeRuntime(target.definition, target.clientInfo);
613
+ target.connection = void 0;
614
+ target.processes = void 0;
615
+ target.uncertain = false;
616
+ target.generation++;
617
+ target.state = "pending";
618
+ }
619
+ const runtime = await target.runtime;
620
+ if (!target.connection) {
621
+ target.connection = runtime.connect(target.definition.name, policy).then(async (context2) => {
622
+ const pid = context2.transport.pid;
623
+ const generation = target.generation;
624
+ const previous = context2.client.onclose;
625
+ context2.client.onclose = () => {
626
+ if (target.generation === generation && target.state !== "retirement-failed") {
627
+ target.state = "disconnected";
628
+ }
629
+ previous?.();
630
+ };
631
+ target.state = "connected";
632
+ if (pid) {
633
+ try {
634
+ target.processes = await ownedProcessTree(pid);
635
+ } catch (error) {
636
+ throw new BrokerError("transport_retirement_failed", error instanceof ProcessObservationError ? error.message : "Transport ownership could not be verified; inspect it before recovery.");
637
+ }
638
+ }
639
+ return context2;
640
+ }).catch((error) => {
641
+ target.connection = void 0;
642
+ if (error && typeof error === "object" && "code" in error && error.code === "transport_retirement_failed")
643
+ target.state = "retirement-failed";
644
+ throw error;
645
+ });
646
+ }
647
+ const context = await target.connection;
648
+ const server = target.definition.name;
649
+ try {
650
+ switch (request.method) {
651
+ case "getServerMetadata": {
652
+ if (chrome)
653
+ await this.owner.resolveIdentity(definition2);
654
+ const info = context.client.getServerVersion();
655
+ return {
656
+ instructions: context.client.getInstructions(),
657
+ serverInfo: info ? { name: info.name, version: info.version, title: info.title } : void 0
658
+ };
659
+ }
660
+ case "callTool":
661
+ return await runtime.callTool(server, params.tool, {
662
+ args: params.args,
663
+ timeoutMs: params.timeoutMs,
664
+ disableOAuth: policy.disableOAuth
665
+ });
666
+ case "listTools":
667
+ return filterTools(await runtime.listTools(server, {
668
+ includeSchema: params.includeSchema,
669
+ ...policy,
670
+ timeoutMs: params.timeoutMs
671
+ }), viewDefinition);
672
+ case "listResources":
673
+ return await runtime.listResources(server, { ...params.params, ...policy });
674
+ case "readResource":
675
+ if (typeof params.uri !== "string")
676
+ throw new BrokerError("invalid_params", "Resource URI required.");
677
+ return await runtime.readResource(server, params.uri, policy);
678
+ default:
679
+ throw new BrokerError("unknown_method", "Unknown daemon operation.");
680
+ }
681
+ } catch (error) {
682
+ const code = error && typeof error === "object" && "code" in error ? error.code : void 0;
683
+ if (code === SdkErrorCode.ConnectionClosed || code === SdkErrorCode.NotConnected) {
684
+ target.state = "disconnected";
685
+ }
686
+ if (code === SdkErrorCode.RequestTimeout || error instanceof Error && error.message === "Timeout") {
687
+ target.uncertain = true;
688
+ throw new BrokerError("operation_timeout", "Operation timed out; outcome unknown. It was not replayed and the connection was retained.");
689
+ }
690
+ if (isOAuthFlowError(error))
691
+ throw new BrokerError("oauth_flow_error", "Authorization failed. Authenticate this server explicitly; the operation was not replayed.");
692
+ throw error;
693
+ }
694
+ });
695
+ target.active++;
696
+ clearTimeout(target.idleTimer);
697
+ const operation = target.serial.then(run, run);
698
+ target.serial = operation.catch(() => {
699
+ });
700
+ try {
701
+ return await operation;
702
+ } finally {
703
+ target.active--;
704
+ target.lastUsed = Date.now();
705
+ this.scheduleIdle(target);
706
+ }
707
+ } finally {
708
+ view.active--;
709
+ this.activeRequests--;
710
+ }
711
+ }
712
+ status() {
713
+ this.expireViews();
714
+ const entries = [...this.entries.values()];
715
+ const owner = entries.find((entry) => entry.chrome);
716
+ return {
717
+ generation: this.generation,
718
+ views: this.views.size,
719
+ servers: entries.map((entry) => ({
720
+ name: entry.id,
721
+ connectionId: entry.id,
722
+ connectionGeneration: entry.generation,
723
+ connected: entry.state === "connected",
724
+ activeCalls: entry.active,
725
+ lastUsedAt: entry.lastUsed,
726
+ idleTimeoutMs: entry.definition.lifecycle?.mode === "keep-alive" ? entry.definition.lifecycle.idleTimeoutMs : void 0,
727
+ idleBlocked: entry.chrome ? "browser-owner" : entry.uncertain ? "unknown-outcome" : void 0,
728
+ chromeDevtoolsRelay: getChromeDevtoolsRelayDecision(entry.definition.name)
729
+ })),
730
+ browserOwner: owner ? { connectionId: owner.id, state: owner.state } : void 0
731
+ };
732
+ }
733
+ async close() {
734
+ this.draining = true;
735
+ if (this.activeRequests > 0)
736
+ throw new BrokerError("active_calls", "Active calls are still running; wait for completion before stopping.");
737
+ for (const entry of this.entries.values()) {
738
+ clearTimeout(entry.idleTimer);
739
+ await entry.serial;
740
+ if (entry.state === "retirement-failed" && !entry.processes)
741
+ throw new BrokerError("transport_retirement_failed", "Retirement is unverified; inspect the previous transport before stopping this owner.");
742
+ if (entry.state !== "idle")
743
+ await this.retire(entry);
744
+ }
745
+ this.entries.clear();
746
+ this.views.clear();
747
+ }
748
+ canIdleShutdown() {
749
+ return !this.draining && this.activeRequests === 0 && !this.owner.reserved && [...this.entries.values()].every((entry) => !entry.active && !entry.uncertain && entry.state !== "retirement-failed");
750
+ }
751
+ async retire(entry) {
752
+ await withRuntimeEnvironment(entry.definition.env ?? {}, async () => {
753
+ await (await entry.runtime).close();
754
+ if (entry.processes)
755
+ await awaitRetirement(entry.processes);
756
+ });
757
+ }
758
+ scheduleIdle(entry) {
759
+ if (this.draining || entry.chrome || entry.active || entry.uncertain || entry.state === "retirement-failed")
760
+ return;
761
+ const timeout = entry.definition.lifecycle?.mode === "keep-alive" ? entry.definition.lifecycle.idleTimeoutMs : void 0;
762
+ if (!timeout)
763
+ return;
764
+ clearTimeout(entry.idleTimer);
765
+ entry.idleTimer = setTimeout(() => {
766
+ if (Date.now() - entry.lastUsed < timeout) {
767
+ this.scheduleIdle(entry);
768
+ return;
769
+ }
770
+ entry.serial = entry.serial.then(async () => {
771
+ if (entry.active || this.draining)
772
+ return;
773
+ entry.state = "disconnected";
774
+ try {
775
+ await this.retire(entry);
776
+ entry.state = "idle";
777
+ } catch {
778
+ entry.state = "retirement-failed";
779
+ }
780
+ });
781
+ }, idleTimerDelay(timeout, entry.lastUsed));
782
+ entry.idleTimer.unref();
783
+ }
784
+ expireViews() {
785
+ const cutoff = Date.now() - 15 * 6e4;
786
+ for (const [id, view] of this.views)
787
+ if (!view.active && view.lastUsed < cutoff)
788
+ this.views.delete(id);
789
+ }
790
+ };
791
+
792
+ // node_modules/.pnpm/mcporter@0.13.10/node_modules/mcporter/dist/daemon/migration.js
793
+ async function probeDaemon(socketPath, method = "status") {
794
+ return new Promise((resolve) => {
795
+ const socket = net2.createConnection(socketPath);
796
+ let buffer = "";
797
+ let done = false;
798
+ const finish = (value) => {
799
+ if (!done) {
800
+ done = true;
801
+ socket.destroy();
802
+ resolve(value);
803
+ }
804
+ };
805
+ socket.setTimeout(1e3, () => finish(null));
806
+ socket.on("error", () => finish(null));
807
+ socket.on("connect", () => socket.write(JSON.stringify({ id: randomUUID2(), method, params: {} })));
808
+ socket.on("data", (chunk) => {
809
+ buffer += chunk.toString();
810
+ if (buffer.length > 1024 * 1024) {
811
+ finish(null);
812
+ return;
813
+ }
814
+ try {
815
+ const response = JSON.parse(buffer.trim());
816
+ finish(response.ok ? response.result ?? null : null);
817
+ } catch {
818
+ }
819
+ });
820
+ socket.on("end", () => finish(null));
821
+ });
822
+ }
823
+ function legacyDirectories() {
824
+ const dirs = /* @__PURE__ */ new Set([daemonRunDir()]);
825
+ if (!process.env.MCPORTER_DAEMON_DIR)
826
+ dirs.add(path2.join(mcporterDir("state"), "daemon"));
827
+ return dirs;
828
+ }
829
+ async function legacyDaemons() {
830
+ const result = [];
831
+ for (const dir of legacyDirectories()) {
832
+ if (!await inspectLegacyDaemonDirectory(dir))
833
+ continue;
834
+ const files = await fs2.readdir(dir).catch((error) => {
835
+ if (error.code === "ENOENT")
836
+ return [];
837
+ throw error;
838
+ });
839
+ for (const name of files.filter((file) => /^daemon-[a-f0-9]+\.json$/.test(file))) {
840
+ const file = path2.join(dir, name);
841
+ const info = await fs2.lstat(file);
842
+ if (!info.isFile() || process.platform !== "win32" && info.uid !== process.getuid?.())
843
+ throw new BrokerError("legacy_daemon_unverified", "Legacy daemon metadata ownership cannot be verified. Resolve it manually before cutover.");
844
+ const data = JSON.parse(await fs2.readFile(file, "utf8"));
845
+ if (!Number.isSafeInteger(data.pid) || data.pid <= 0 || typeof data.socketPath !== "string")
846
+ throw new BrokerError("legacy_daemon_unverified", "Malformed legacy metadata requires manual inspection.");
847
+ if (!isProcessRunning(data.pid))
848
+ continue;
849
+ const expected = process.platform === "win32" ? `\\\\.\\pipe\\mcporter-${name.slice(0, -5)}` : path2.join(dir, name.replace(/\.json$/, ".sock"));
850
+ const live = data.socketPath === expected ? await probeDaemon(expected) : null;
851
+ const verified = !!live && typeof live === "object" && live.pid === data.pid && live.socketPath === expected && (live.protocolVersion ?? 1) < 3;
852
+ result.push({ pid: data.pid, socketPath: expected, verified });
853
+ }
854
+ }
855
+ return result;
856
+ }
857
+ async function assertLegacyDrained() {
858
+ if (await fs2.stat(path2.join(daemonRunDir(), "legacy-retirement.json")).catch(() => void 0))
859
+ throw new BrokerError("legacy_retirement_pending", "Legacy retirement is unverified; inspect daemon migrate before cutover.");
860
+ if ((await legacyDaemons()).length)
861
+ throw new BrokerError("legacy_daemon_conflict", "Live legacy per-config daemon ownership remains. Upgrade all invoking clients, drain old calls, then run daemon migrate --stop-legacy --confirmed-drained. No process was stopped.");
862
+ }
863
+ async function stopVerifiedLegacyDaemons() {
864
+ const directories = legacyDirectories();
865
+ for (const directory of directories)
866
+ await inspectLegacyDaemonDirectory(directory);
867
+ for (const directory of directories)
868
+ await upgradeLegacyDaemonDirectory(directory);
869
+ await secureDaemonDirectory();
870
+ const marker = path2.join(daemonRunDir(), "legacy-retirement.json");
871
+ const pending2 = await fs2.readFile(marker, "utf8").then((raw) => JSON.parse(raw)).catch((error) => {
872
+ if (error.code !== "ENOENT")
873
+ throw error;
874
+ return void 0;
875
+ });
876
+ if (pending2) {
877
+ if (!Array.isArray(pending2.processes) || pending2.processes.length === 0 || !pending2.processes.every((p) => Number.isSafeInteger(p.pid) && p.pid > 0 && typeof p.born === "string" && typeof p.owner === "string"))
878
+ throw new Error("Invalid legacy retirement marker; manual inspection required.");
879
+ await awaitRetirement(pending2.processes);
880
+ await fs2.unlink(marker);
881
+ }
882
+ const legacy = await legacyDaemons();
883
+ if (legacy.some((entry) => !entry.verified))
884
+ throw new BrokerError("legacy_daemon_unverified", "Legacy process ownership is unverified; no process was stopped.");
885
+ for (const entry of legacy) {
886
+ const live = await probeDaemon(entry.socketPath);
887
+ if (!live || typeof live !== "object" || live.pid !== entry.pid || live.socketPath !== entry.socketPath)
888
+ throw new BrokerError("legacy_daemon_unverified", "Legacy owner changed during cutover.");
889
+ const processes = await ownedProcessTree(entry.pid);
890
+ await writeJsonFile(marker, { processes });
891
+ if (!await probeDaemon(entry.socketPath, "stop"))
892
+ throw new BrokerError("legacy_stop_failed", "Verified legacy daemon did not accept stop; retirement remains blocked.");
893
+ await awaitRetirement(processes);
894
+ await fs2.unlink(marker);
895
+ }
896
+ }
897
+
898
+ // node_modules/.pnpm/mcporter@0.13.10/node_modules/mcporter/dist/daemon/startup-readiness.js
899
+ var DAEMON_STARTUP_TIMEOUT_MS = 45e3;
900
+ var DAEMON_STARTUP_SLOW_NOTICE_MS = 5e3;
901
+ var DAEMON_STARTUP_POLL_INTERVAL_MS = 100;
902
+ async function waitForDaemonReady(probe, timing = {}) {
903
+ const now = timing.now ?? Date.now;
904
+ const wait = timing.delay ?? delay;
905
+ const reportSlowStart = timing.reportSlowStart ?? defaultSlowStartReporter;
906
+ const startedAt = now();
907
+ const deadline = startedAt + DAEMON_STARTUP_TIMEOUT_MS;
908
+ let reportedSlowStart = false;
909
+ while (true) {
910
+ const remainingBeforeProbe = deadline - now();
911
+ if (remainingBeforeProbe <= 0) {
912
+ throw daemonStartupTimeoutError();
913
+ }
914
+ const result = await probe(Math.min(DAEMON_STARTUP_POLL_INTERVAL_MS, remainingBeforeProbe)).catch((error) => {
915
+ if (error && typeof error === "object" && "code" in error && error.code === "ETIMEDOUT")
916
+ return null;
917
+ throw error;
918
+ });
919
+ if (result !== null) {
920
+ return result;
921
+ }
922
+ const currentTime = now();
923
+ if (currentTime >= deadline) {
924
+ throw daemonStartupTimeoutError();
925
+ }
926
+ if (!reportedSlowStart && currentTime - startedAt >= DAEMON_STARTUP_SLOW_NOTICE_MS) {
927
+ reportedSlowStart = true;
928
+ reportSlowStart();
929
+ }
930
+ await wait(Math.min(DAEMON_STARTUP_POLL_INTERVAL_MS, deadline - currentTime));
931
+ }
932
+ }
933
+ function defaultSlowStartReporter() {
934
+ console.error("[mcporter] Daemon startup is taking longer than usual; Chrome relay discovery can take up to 30 seconds.");
935
+ }
936
+ function daemonStartupTimeoutError() {
937
+ return new Error("MCPorter daemon did not become ready within 45 seconds. Run 'mcporter daemon start --foreground --log' to diagnose startup.");
938
+ }
939
+ function delay(ms) {
940
+ return new Promise((resolve) => {
941
+ setTimeout(resolve, ms);
942
+ });
943
+ }
944
+
945
+ // node_modules/.pnpm/mcporter@0.13.10/node_modules/mcporter/dist/daemon/client.js
946
+ var DEFAULT_DAEMON_TIMEOUT_MS = 3e4;
947
+ function resolveDaemonPaths(configPath) {
948
+ const key = "user";
949
+ void configPath;
950
+ return {
951
+ key,
952
+ socketPath: getDaemonSocketPath(key),
953
+ metadataPath: getDaemonMetadataPath(key)
954
+ };
955
+ }
956
+ var DaemonClient = class {
957
+ options;
958
+ socketPath;
959
+ metadataPath;
960
+ startingPromise = null;
961
+ constructor(options) {
962
+ this.options = options;
963
+ const paths = resolveDaemonPaths(options.configPath);
964
+ this.socketPath = paths.socketPath;
965
+ this.metadataPath = paths.metadataPath;
966
+ }
967
+ async callTool(params) {
968
+ return this.invoke("callTool", params, params.timeoutMs);
969
+ }
970
+ async listTools(params) {
971
+ return this.invoke("listTools", params, params.timeoutMs);
972
+ }
973
+ async listResources(params) {
974
+ return this.invoke("listResources", params);
975
+ }
976
+ async readResource(params) {
977
+ return this.invoke("readResource", params);
978
+ }
979
+ async closeServer(params) {
980
+ await this.invoke("closeServer", params);
981
+ }
982
+ async status(timeoutMs) {
983
+ return await this.readVerifiedStatus(timeoutMs);
984
+ }
985
+ async stop() {
986
+ try {
987
+ await this.sendRequest("stop", {});
988
+ } catch (error) {
989
+ if (isTransportError(error)) {
990
+ return;
991
+ }
992
+ throw error;
993
+ }
994
+ }
995
+ epoch;
996
+ retiring = /* @__PURE__ */ new Set();
997
+ definitions;
998
+ clientInfo;
999
+ setDefinitions(definitions, clientInfo) {
1000
+ this.definitions = definitions.map(({ command: command2, ...definition2 }) => ({
1001
+ ...structuredClone(definition2),
1002
+ command: command2.kind === "http" ? { ...structuredClone({ ...command2, url: void 0 }), url: new URL(command2.url) } : structuredClone(command2)
1003
+ }));
1004
+ this.clientInfo = clientInfo ? { ...clientInfo } : void 0;
1005
+ if (this.epoch)
1006
+ void this.retire(this.epoch).catch(() => {
1007
+ });
1008
+ }
1009
+ retire(epoch) {
1010
+ if (this.epoch === epoch)
1011
+ this.epoch = void 0;
1012
+ if (!epoch.release) {
1013
+ epoch.release = (async () => {
1014
+ if (epoch.active)
1015
+ await new Promise((resolve) => {
1016
+ epoch.drained = resolve;
1017
+ });
1018
+ const handle = await epoch.registration?.catch(() => void 0);
1019
+ if (handle)
1020
+ await this.sendRequest("releaseView", {}, void 0, handle);
1021
+ })();
1022
+ this.retiring.add(epoch.release);
1023
+ void epoch.release.finally(() => this.retiring.delete(epoch.release)).catch(() => {
1024
+ });
1025
+ }
1026
+ return epoch.release;
1027
+ }
1028
+ async release() {
1029
+ if (this.epoch)
1030
+ void this.retire(this.epoch).catch(() => {
1031
+ });
1032
+ await Promise.all(this.retiring);
1033
+ }
1034
+ async getServerMetadata(params) {
1035
+ return this.invoke("getServerMetadata", params, params.timeoutMs);
1036
+ }
1037
+ async invoke(method, params, timeoutMs) {
1038
+ const epoch = this.epoch ??= { definitions: this.definitions, clientInfo: this.clientInfo, active: 0 };
1039
+ epoch.active++;
1040
+ try {
1041
+ epoch.registration ??= (async () => {
1042
+ await this.ensureDaemon(timeoutMs);
1043
+ const definitions = epoch.definitions ?? await loadServerDefinitions({
1044
+ configPath: this.options.configExplicit ? this.options.configPath : void 0,
1045
+ rootDir: this.options.rootDir
1046
+ });
1047
+ const effective = await Promise.all(definitions.filter(isKeepAliveServer).map((definition2) => effectiveDefinition(definition2, process.env, "view")));
1048
+ return this.sendRequest("registerView", {
1049
+ definitions: effective,
1050
+ clientInfo: epoch.clientInfo
1051
+ });
1052
+ })();
1053
+ let handle;
1054
+ try {
1055
+ handle = await epoch.registration;
1056
+ } catch (error) {
1057
+ void this.retire(epoch).catch(() => {
1058
+ });
1059
+ throw error;
1060
+ }
1061
+ return await this.sendRequest(method, params, timeoutMs, handle);
1062
+ } catch (error) {
1063
+ const code = error.code;
1064
+ if (code === "daemon_generation_changed" || code === "view_expired" || isTransportError(error))
1065
+ void this.retire(epoch).catch(() => {
1066
+ });
1067
+ throw error;
1068
+ } finally {
1069
+ epoch.active--;
1070
+ if (!epoch.active)
1071
+ epoch.drained?.();
1072
+ }
1073
+ }
1074
+ async ensureDaemon(timeoutMs) {
1075
+ await secureDaemonDirectory();
1076
+ await assertLegacyDrained();
1077
+ if (await this.readVerifiedStatus(timeoutMs))
1078
+ return;
1079
+ const previous = await readDaemonMetadata(this.metadataPath);
1080
+ if (previous && !isProcessRunning(previous.pid))
1081
+ throw new Error("Previous daemon exited unexpectedly; verify retirement of its transports before deliberate recovery. No replacement was launched.");
1082
+ this.startingPromise ??= (async () => {
1083
+ const { launchDaemonDetached } = await import("./launch-ZFY6CM2A.js");
1084
+ await launchDaemonDetached({
1085
+ configPath: this.options.configPath,
1086
+ metadataPath: this.metadataPath,
1087
+ socketPath: this.socketPath
1088
+ });
1089
+ await waitForDaemonReady((timeout) => this.readVerifiedStatus(timeout));
1090
+ })().finally(() => {
1091
+ this.startingPromise = null;
1092
+ });
1093
+ await this.startingPromise;
1094
+ }
1095
+ async readVerifiedStatus(timeoutMs) {
1096
+ const metadata = await readDaemonMetadata(this.metadataPath);
1097
+ if (metadata && metadata.protocolVersion !== DAEMON_PROTOCOL_VERSION && isProcessRunning(metadata.pid))
1098
+ throw new Error("Incompatible daemon: upgrade clients and use deliberate daemon cutover.");
1099
+ let result;
1100
+ try {
1101
+ result = await this.sendRequest("status", {}, timeoutMs);
1102
+ } catch (error) {
1103
+ if (isTransportError(error) && (!metadata || !isProcessRunning(metadata.pid)))
1104
+ return null;
1105
+ throw error;
1106
+ }
1107
+ if (result.socketPath !== this.socketPath || result.protocolVersion !== DAEMON_PROTOCOL_VERSION || !result.generation || !isProcessRunning(result.pid))
1108
+ throw new Error("Incompatible or unverified daemon; no restart attempted.");
1109
+ if (!metadata || metadata.pid !== result.pid)
1110
+ await writeJsonFile(this.metadataPath, result);
1111
+ return result;
1112
+ }
1113
+ async sendRequest(method, params, timeoutOverrideMs, handle) {
1114
+ const progressTiming = resolveProgressTiming(resolveDaemonTimeout(timeoutOverrideMs));
1115
+ const request = {
1116
+ id: randomUUID3(),
1117
+ ...handle,
1118
+ method,
1119
+ params,
1120
+ protocolVersion: DAEMON_PROTOCOL_VERSION,
1121
+ progressIntervalMs: progressTiming.progressIntervalMs
1122
+ };
1123
+ const parsed = await requestDaemon(this.socketPath, request, progressTiming.idleTimeoutMs);
1124
+ for (const notice of parsed.notices ?? []) {
1125
+ console.warn(`[mcporter] ${notice}`);
1126
+ }
1127
+ if (!parsed.ok) {
1128
+ const error = new Error(parsed.error?.message ?? "Daemon error");
1129
+ error.code = parsed.error?.code;
1130
+ throw error;
1131
+ }
1132
+ return parsed.result;
1133
+ }
1134
+ };
1135
+ function isTransportError(error) {
1136
+ if (!error || typeof error !== "object") {
1137
+ return false;
1138
+ }
1139
+ const code = error.code;
1140
+ return code === "ECONNREFUSED" || code === "ENOENT" || code === "ETIMEDOUT" || code === "ECONNRESET";
1141
+ }
1142
+ function resolveDaemonTimeout(override) {
1143
+ if (typeof override === "number" && Number.isFinite(override) && override > 0) {
1144
+ return override;
1145
+ }
1146
+ const raw = process.env.MCPORTER_DAEMON_TIMEOUT_MS;
1147
+ if (!raw) {
1148
+ return DEFAULT_DAEMON_TIMEOUT_MS;
1149
+ }
1150
+ const parsed = Number.parseInt(raw, 10);
1151
+ if (!Number.isFinite(parsed) || parsed <= 0) {
1152
+ return DEFAULT_DAEMON_TIMEOUT_MS;
1153
+ }
1154
+ return parsed;
1155
+ }
1156
+ async function readDaemonMetadata(metadataPath) {
1157
+ try {
1158
+ const raw = await fs3.readFile(metadataPath, "utf8");
1159
+ return JSON.parse(raw);
1160
+ } catch {
1161
+ return null;
1162
+ }
1163
+ }
1164
+
1165
+ export {
1166
+ DAEMON_PROTOCOL_VERSION,
1167
+ resolveProgressInterval,
1168
+ daemonKey,
1169
+ SocketFrames,
1170
+ authenticateServer,
1171
+ requestDaemon,
1172
+ ProcessObservationError,
1173
+ idleTimerDelay,
1174
+ BrokerError,
1175
+ DaemonBroker,
1176
+ legacyDaemons,
1177
+ assertLegacyDrained,
1178
+ stopVerifiedLegacyDaemons,
1179
+ waitForDaemonReady,
1180
+ resolveDaemonPaths,
1181
+ DaemonClient
1182
+ };