@ai-ecoverse/mcpcat 0.14.1 → 0.14.3

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.
@@ -167,6 +167,101 @@ var init_node_stub = __esm({
167
167
  }
168
168
  });
169
169
 
170
+ // src/config/lock.ts
171
+ var lock_exports = {};
172
+ __export(lock_exports, {
173
+ acquireLock: () => acquireLock
174
+ });
175
+ function isEexist(err) {
176
+ if (err instanceof Error && "code" in err)
177
+ return err.code === "EEXIST";
178
+ if (err instanceof Error) return err.message.includes("EEXIST");
179
+ return false;
180
+ }
181
+ async function removeStaleLockDir(fs, lockPath) {
182
+ try {
183
+ const s = await fs.stat(lockPath);
184
+ if (Date.now() - s.mtimeMs > LOCK_STALE_MS) {
185
+ try {
186
+ await fs.rmdir(lockPath);
187
+ } catch {
188
+ }
189
+ return true;
190
+ }
191
+ } catch {
192
+ }
193
+ return false;
194
+ }
195
+ async function removeStaleLockFile(fs, lockPath) {
196
+ try {
197
+ const s = await fs.stat(lockPath);
198
+ if (Date.now() - s.mtimeMs > LOCK_STALE_MS) {
199
+ try {
200
+ await fs.unlink(lockPath);
201
+ } catch {
202
+ }
203
+ return true;
204
+ }
205
+ } catch {
206
+ }
207
+ return false;
208
+ }
209
+ async function acquireLock(fs, configPath) {
210
+ const useFile = typeof fs.createExclusive === "function";
211
+ const lockPath = `${configPath}.lock`;
212
+ const start = Date.now();
213
+ const parentDir = lockPath.slice(0, lockPath.lastIndexOf("/"));
214
+ if (parentDir) {
215
+ try {
216
+ await fs.mkdir(parentDir);
217
+ } catch {
218
+ }
219
+ }
220
+ while (true) {
221
+ try {
222
+ if (useFile) {
223
+ await fs.createExclusive(lockPath);
224
+ } else {
225
+ await fs.mkdirExclusive(lockPath);
226
+ }
227
+ break;
228
+ } catch (err) {
229
+ if (!isEexist(err)) throw err;
230
+ if (useFile) {
231
+ await removeStaleLockFile(fs, lockPath);
232
+ } else {
233
+ await removeStaleLockDir(fs, lockPath);
234
+ }
235
+ }
236
+ if (Date.now() - start > LOCK_MAX_WAIT_MS) {
237
+ throw new Error(`mcpcat: could not acquire lock ${lockPath} within ${LOCK_MAX_WAIT_MS}ms`);
238
+ }
239
+ await new Promise((r) => setTimeout(r, LOCK_POLL_MS));
240
+ }
241
+ let released = false;
242
+ return async () => {
243
+ if (released) return;
244
+ released = true;
245
+ try {
246
+ if (useFile && fs.unlink) {
247
+ await fs.unlink(lockPath);
248
+ } else {
249
+ await fs.rmdir(lockPath);
250
+ }
251
+ } catch {
252
+ }
253
+ };
254
+ }
255
+ var LOCK_STALE_MS, LOCK_POLL_MS, LOCK_MAX_WAIT_MS;
256
+ var init_lock = __esm({
257
+ "src/config/lock.ts"() {
258
+ "use strict";
259
+ LOCK_STALE_MS = 1e4;
260
+ LOCK_POLL_MS = 50;
261
+ LOCK_MAX_WAIT_MS = 5e3;
262
+ }
263
+ });
264
+
170
265
  // node_modules/@earendil-works/pi-codemode/dist/identifier.js
171
266
  function toCodemodeIdentifier(name) {
172
267
  let identifier = "";
@@ -5966,7 +6061,7 @@ var McpOAuthProvider = class {
5966
6061
  };
5967
6062
 
5968
6063
  // src/auth/jerk-token-source.ts
5969
- var MIN_VERSION = [0, 13, 0];
6064
+ var MIN_VERSION = [0, 14, 1];
5970
6065
  var VERSION_TIMEOUT_MS = 2e3;
5971
6066
  var cachedAvailable;
5972
6067
  function parseVersion(raw) {
@@ -6092,6 +6187,192 @@ var JerkTokenSource = class {
6092
6187
  }
6093
6188
  };
6094
6189
 
6190
+ // src/auth/pi-store.ts
6191
+ init_lock();
6192
+
6193
+ // src/config/paths.ts
6194
+ function userConfigDir(platform2) {
6195
+ const piDir = platform2.env.PI_CODING_AGENT_DIR;
6196
+ if (piDir) return piDir;
6197
+ const home = platform2.env.HOME ?? platform2.env.USERPROFILE ?? "/";
6198
+ return `${home}/.pi/agent`;
6199
+ }
6200
+ function userConfigPath(platform2) {
6201
+ return `${userConfigDir(platform2)}/mcp.json`;
6202
+ }
6203
+ function projectConfigPath(platform2) {
6204
+ return `${platform2.cwd}/.pi/mcp.json`;
6205
+ }
6206
+ function stateDir(platform2) {
6207
+ if (platform2.env.XDG_STATE_HOME) return `${platform2.env.XDG_STATE_HOME}/mcpcat`;
6208
+ const home = platform2.env.HOME ?? platform2.env.USERPROFILE ?? "/";
6209
+ if (platform2.env.LOCALAPPDATA) return `${platform2.env.LOCALAPPDATA}\\mcpcat\\state`;
6210
+ if (platform2.env.SLICC_KERNEL) return `${home}/.local/state/mcpcat`;
6211
+ return `${home}/Library/Application Support/mcpcat`;
6212
+ }
6213
+
6214
+ // src/auth/token-source.ts
6215
+ function mcpNamespace(server) {
6216
+ return `mcp__${server.replace(/-/g, "_")}`;
6217
+ }
6218
+ function storeKey(name, serverUrl) {
6219
+ const ns = mcpNamespace(name);
6220
+ const url = String(new URL(serverUrl));
6221
+ return `${ns}|${url}`;
6222
+ }
6223
+ function isKernel(platform2) {
6224
+ return platform2.kind === "kernel";
6225
+ }
6226
+
6227
+ // src/auth/pi-store.ts
6228
+ var AUTH_FILE = "mcp-auth.json";
6229
+ var FILE_MODE = 384;
6230
+ var DIR_MODE = 448;
6231
+ function parseStates(raw) {
6232
+ if (!raw?.trim()) return {};
6233
+ const parsed = JSON.parse(raw);
6234
+ return typeof parsed === "object" && parsed !== null && !Array.isArray(parsed) ? parsed : {};
6235
+ }
6236
+ function serializeStates(states) {
6237
+ return `${JSON.stringify(states, null, 2)}
6238
+ `;
6239
+ }
6240
+ function legacyKey(serverUrl) {
6241
+ return String(new URL(serverUrl));
6242
+ }
6243
+ var PiFileTokenSource = class {
6244
+ platform;
6245
+ authPath;
6246
+ dirPath;
6247
+ constructor(platform2) {
6248
+ this.platform = platform2;
6249
+ this.dirPath = userConfigDir(platform2);
6250
+ this.authPath = `${this.dirPath}/${AUTH_FILE}`;
6251
+ }
6252
+ get path() {
6253
+ return this.authPath;
6254
+ }
6255
+ async loadWithoutLock(name, serverUrl) {
6256
+ const key = storeKey(name, serverUrl);
6257
+ const legacy = legacyKey(serverUrl);
6258
+ try {
6259
+ const raw = await this.readRaw();
6260
+ const states = parseStates(raw);
6261
+ return states[key] ?? states[legacy];
6262
+ } catch {
6263
+ return void 0;
6264
+ }
6265
+ }
6266
+ async getToken(name, serverUrl) {
6267
+ const state = await this.load(name, serverUrl);
6268
+ if (!state?.tokens?.access_token) return void 0;
6269
+ return {
6270
+ accessToken: state.tokens.access_token,
6271
+ expiresAt: state.tokensExpireAt
6272
+ };
6273
+ }
6274
+ async load(name, serverUrl) {
6275
+ const key = storeKey(name, serverUrl);
6276
+ const legacy = legacyKey(serverUrl);
6277
+ const release = await this.acquireLock();
6278
+ try {
6279
+ const raw = await this.readRaw();
6280
+ const states = parseStates(raw);
6281
+ if (states[key]) return states[key];
6282
+ if (states[legacy]) {
6283
+ states[key] = states[legacy];
6284
+ delete states[legacy];
6285
+ await this.writeStates(states);
6286
+ return states[key];
6287
+ }
6288
+ return void 0;
6289
+ } finally {
6290
+ await release();
6291
+ }
6292
+ }
6293
+ async save(name, serverUrl, state) {
6294
+ const key = storeKey(name, serverUrl);
6295
+ const release = await this.acquireLock();
6296
+ try {
6297
+ const raw = await this.readRaw();
6298
+ const states = parseStates(raw);
6299
+ states[key] = state;
6300
+ await this.writeStates(states);
6301
+ } finally {
6302
+ await release();
6303
+ }
6304
+ }
6305
+ async remove(name, serverUrl) {
6306
+ const key = storeKey(name, serverUrl);
6307
+ const legacy = legacyKey(serverUrl);
6308
+ const release = await this.acquireLock();
6309
+ try {
6310
+ const raw = await this.readRaw();
6311
+ const states = parseStates(raw);
6312
+ const stored = key in states ? key : legacy in states ? legacy : void 0;
6313
+ if (!stored) return false;
6314
+ delete states[stored];
6315
+ await this.writeStates(states);
6316
+ return true;
6317
+ } finally {
6318
+ await release();
6319
+ }
6320
+ }
6321
+ async acquireLock() {
6322
+ await this.ensureDir();
6323
+ return acquireLock(this.platform.fs, this.authPath);
6324
+ }
6325
+ async ensureDir() {
6326
+ const fs = this.platform.fs;
6327
+ try {
6328
+ await fs.mkdir(this.dirPath, { mode: DIR_MODE });
6329
+ } catch {
6330
+ }
6331
+ if (fs.chmod) {
6332
+ try {
6333
+ await fs.chmod(this.dirPath, DIR_MODE);
6334
+ } catch {
6335
+ }
6336
+ const piDir = this.dirPath.slice(0, this.dirPath.lastIndexOf("/"));
6337
+ if (piDir) {
6338
+ try {
6339
+ await fs.chmod(piDir, DIR_MODE);
6340
+ } catch {
6341
+ }
6342
+ }
6343
+ }
6344
+ }
6345
+ async readRaw() {
6346
+ try {
6347
+ const data = await this.platform.fs.readFile(this.authPath);
6348
+ return new TextDecoder().decode(data);
6349
+ } catch {
6350
+ return void 0;
6351
+ }
6352
+ }
6353
+ async writeStates(states) {
6354
+ const fs = this.platform.fs;
6355
+ const content = serializeStates(states);
6356
+ const tmpPath = `${this.authPath}.tmp.${Date.now()}`;
6357
+ try {
6358
+ await fs.writeFile(tmpPath, content, { mode: FILE_MODE });
6359
+ await fs.rename(tmpPath, this.authPath);
6360
+ } catch (renameErr) {
6361
+ try {
6362
+ if (fs.unlink) await fs.unlink(tmpPath);
6363
+ } catch {
6364
+ }
6365
+ throw renameErr;
6366
+ }
6367
+ if (fs.chmod) {
6368
+ try {
6369
+ await fs.chmod(this.authPath, FILE_MODE);
6370
+ } catch {
6371
+ }
6372
+ }
6373
+ }
6374
+ };
6375
+
6095
6376
  // src/auth/auth-provider.ts
6096
6377
  var CIMD_URL = "https://mcpcat.sliccy.ai/oauth/client.json";
6097
6378
  var CLIENT_NAME = "mcpcat";
@@ -6113,10 +6394,12 @@ var SourceBackedStore = class {
6113
6394
  source;
6114
6395
  name;
6115
6396
  serverUrl;
6116
- constructor(source, name, serverUrl) {
6397
+ platform;
6398
+ constructor(source, name, serverUrl, platform2) {
6117
6399
  this.source = source;
6118
6400
  this.name = name;
6119
6401
  this.serverUrl = serverUrl;
6402
+ this.platform = platform2;
6120
6403
  }
6121
6404
  async load() {
6122
6405
  return this.source.load(this.name, this.serverUrl);
@@ -6124,6 +6407,17 @@ var SourceBackedStore = class {
6124
6407
  async save(state) {
6125
6408
  await this.source.save(this.name, this.serverUrl, state);
6126
6409
  }
6410
+ async withRefreshLock(fn) {
6411
+ if (!(this.source instanceof PiFileTokenSource)) return fn();
6412
+ const refreshPath = `${this.source.path}.refresh`;
6413
+ const { acquireLock: acquireLock2 } = await Promise.resolve().then(() => (init_lock(), lock_exports));
6414
+ const release = await acquireLock2(this.platform.fs, refreshPath);
6415
+ try {
6416
+ return await fn();
6417
+ } finally {
6418
+ await release();
6419
+ }
6420
+ }
6127
6421
  };
6128
6422
  function cimdFn(redirectUrl) {
6129
6423
  return (metadata) => {
@@ -6152,10 +6446,9 @@ function createMcpAuthProvider(options) {
6152
6446
  function createJerkAuthProvider(options) {
6153
6447
  const { name, serverUrl, source } = options;
6154
6448
  let currentToken;
6449
+ const _fetched = false;
6155
6450
  return {
6156
6451
  async token() {
6157
- const result = await source.getToken(name, serverUrl);
6158
- currentToken = result?.accessToken;
6159
6452
  return currentToken;
6160
6453
  },
6161
6454
  async onUnauthorized(context) {
@@ -6186,10 +6479,10 @@ function createJerkAuthProvider(options) {
6186
6479
  }
6187
6480
  function createPiAuthProvider(options) {
6188
6481
  const { name, serverUrl, source, oauth, platform: platform2 } = options;
6189
- const store = new SourceBackedStore(source, name, serverUrl);
6482
+ const store = new SourceBackedStore(source, name, serverUrl, platform2);
6190
6483
  let refreshing;
6191
6484
  const refresh = async (staleToken) => {
6192
- refreshing ??= (async () => {
6485
+ refreshing ??= store.withRefreshLock(async () => {
6193
6486
  const state = await store.load();
6194
6487
  if (state?.tokens?.access_token !== staleToken) return;
6195
6488
  if (!state?.tokens?.refresh_token) throw new McpOAuthAuthorizationRequiredError();
@@ -6212,7 +6505,7 @@ function createPiAuthProvider(options) {
6212
6505
  fetch: timedFetch(platform2.fetch)
6213
6506
  });
6214
6507
  if (result === "REDIRECT") throw new McpOAuthAuthorizationRequiredError();
6215
- })().finally(() => {
6508
+ }).finally(() => {
6216
6509
  refreshing = void 0;
6217
6510
  });
6218
6511
  return refreshing;
@@ -7339,11 +7632,45 @@ var StreamableHttpTransport = class extends TransportEvents {
7339
7632
  }
7340
7633
  };
7341
7634
 
7342
- // src/client/platform-stdio-transport.ts
7343
- var DEFAULT_MAX_MESSAGE_BYTES2 = 4 * 1024 * 1024;
7344
- var DEFAULT_MAX_STDERR_BYTES2 = 64 * 1024;
7345
- var DEFAULT_CLOSE_TIMEOUT_MS2 = 2e3;
7346
- var STDIN_CLOSE_GRACE_MS2 = 500;
7635
+ // src/client/stdio-registry.ts
7636
+ var GRACE_MS = 2e3;
7637
+ var registry = /* @__PURE__ */ new Set();
7638
+ function trackStdio(proc) {
7639
+ registry.add(proc);
7640
+ void proc.wait().then(
7641
+ () => registry.delete(proc),
7642
+ () => registry.delete(proc)
7643
+ );
7644
+ }
7645
+ async function killAllStdio() {
7646
+ const procs = [...registry];
7647
+ if (procs.length === 0) return;
7648
+ await Promise.all(
7649
+ procs.map(async (proc) => {
7650
+ try {
7651
+ await proc.kill("SIGTERM");
7652
+ } catch {
7653
+ }
7654
+ const exited = await Promise.race([
7655
+ proc.wait().then(() => true),
7656
+ new Promise((r) => setTimeout(() => r(false), GRACE_MS))
7657
+ ]);
7658
+ if (!exited) {
7659
+ try {
7660
+ await proc.kill("SIGKILL");
7661
+ } catch {
7662
+ }
7663
+ }
7664
+ })
7665
+ );
7666
+ registry.clear();
7667
+ }
7668
+
7669
+ // src/client/platform-stdio-transport.ts
7670
+ var DEFAULT_MAX_MESSAGE_BYTES2 = 4 * 1024 * 1024;
7671
+ var DEFAULT_MAX_STDERR_BYTES2 = 64 * 1024;
7672
+ var DEFAULT_CLOSE_TIMEOUT_MS2 = 2e3;
7673
+ var STDIN_CLOSE_GRACE_MS2 = 500;
7347
7674
  var PlatformStdioTransport = class {
7348
7675
  options;
7349
7676
  process;
@@ -7395,16 +7722,21 @@ var PlatformStdioTransport = class {
7395
7722
  if (this.started) throw new Error("MCP stdio transport already started");
7396
7723
  if (this.closed) throw new Error("MCP connection closed");
7397
7724
  this.started = true;
7398
- const env2 = this.options.inheritEnv === false ? { ...this.options.env ?? {} } : {
7399
- ...this.options.platform.env,
7400
- ...this.options.env
7401
- };
7402
- this.process = await this.options.platform.spawn({
7403
- argv: [this.options.command, ...this.options.args ?? []],
7404
- env: env2,
7405
- cwd: this.options.cwd
7406
- });
7407
- void this.readStdout();
7725
+ if (this.options.existingProcess) {
7726
+ this.process = this.options.existingProcess;
7727
+ } else {
7728
+ const env2 = this.options.inheritEnv === false ? { ...this.options.env ?? {} } : {
7729
+ ...this.options.platform.env,
7730
+ ...this.options.env
7731
+ };
7732
+ this.process = await this.options.platform.spawn({
7733
+ argv: [this.options.command, ...this.options.args ?? []],
7734
+ env: env2,
7735
+ cwd: this.options.cwd
7736
+ });
7737
+ trackStdio(this.process);
7738
+ }
7739
+ void this.readStdout(this.options.pendingStdout);
7408
7740
  void this.readStderr();
7409
7741
  void this.waitForExit();
7410
7742
  }
@@ -7437,22 +7769,22 @@ var PlatformStdioTransport = class {
7437
7769
  }
7438
7770
  const exited = await Promise.race([done, delay(grace)]);
7439
7771
  if (!exited) {
7440
- proc.kill("SIGTERM");
7772
+ await proc.kill("SIGTERM");
7441
7773
  const exitedAfterTerm = await Promise.race([done, delay(closeTimeoutMs)]);
7442
7774
  if (!exitedAfterTerm) {
7443
- proc.kill("SIGKILL");
7775
+ await proc.kill("SIGKILL");
7444
7776
  await done;
7445
7777
  }
7446
7778
  }
7447
- proc.kill("SIGTERM");
7779
+ await proc.kill("SIGTERM");
7448
7780
  this.emitClose();
7449
7781
  }
7450
- async readStdout() {
7782
+ async readStdout(pending) {
7451
7783
  const proc = this.process;
7452
7784
  if (!proc) return;
7453
7785
  const reader = proc.stdout.getReader();
7454
7786
  const maxBytes = this.options.maxMessageBytes ?? DEFAULT_MAX_MESSAGE_BYTES2;
7455
- let buffer = "";
7787
+ let buffer = pending ?? "";
7456
7788
  try {
7457
7789
  for (; ; ) {
7458
7790
  const { done, value } = await reader.read();
@@ -7512,6 +7844,10 @@ var PlatformStdioTransport = class {
7512
7844
  await proc.wait();
7513
7845
  } catch {
7514
7846
  }
7847
+ try {
7848
+ await proc.kill("SIGTERM");
7849
+ } catch {
7850
+ }
7515
7851
  if (!this.closed) {
7516
7852
  this.emitClose();
7517
7853
  }
@@ -7853,7 +8189,9 @@ function buildTransport(options) {
7853
8189
  cwd: options.cwd,
7854
8190
  inheritEnv: true,
7855
8191
  platform: options.platform,
7856
- onStderr: buildStderrHandler(options)
8192
+ onStderr: buildStderrHandler(options),
8193
+ existingProcess: options.existingProcess?.proc,
8194
+ pendingStdout: options.existingProcess?.pendingStdout
7857
8195
  });
7858
8196
  }
7859
8197
  return new StdioTransport({
@@ -8040,6 +8378,9 @@ function createStdioJsonRpc(proc, platform2, options) {
8040
8378
  reader.releaseLock();
8041
8379
  } catch {
8042
8380
  }
8381
+ },
8382
+ pendingBuffer() {
8383
+ return readBuffer;
8043
8384
  }
8044
8385
  };
8045
8386
  }
@@ -8092,13 +8433,13 @@ function buildConnectionMethods(rpc, discoverResult2, proc) {
8092
8433
  async close() {
8093
8434
  rpc.close();
8094
8435
  try {
8095
- proc.kill("SIGTERM");
8436
+ await proc.kill("SIGTERM");
8096
8437
  } catch {
8097
8438
  }
8098
8439
  }
8099
8440
  };
8100
8441
  }
8101
- async function createStdioStatelessConnection(options) {
8442
+ async function probeStdioStateless(options) {
8102
8443
  const inheritedEnv = {
8103
8444
  ...options.platform.env,
8104
8445
  ...options.env
@@ -8108,22 +8449,30 @@ async function createStdioStatelessConnection(options) {
8108
8449
  env: inheritedEnv,
8109
8450
  cwd: options.cwd
8110
8451
  });
8111
- void readStderr(proc, options.verbose);
8452
+ trackStdio(proc);
8112
8453
  const rpc = createStdioJsonRpc(proc, options.platform, {
8113
8454
  version: options.version,
8114
8455
  timeoutMs: options.timeoutMs,
8115
8456
  signal: options.signal,
8116
8457
  verbose: options.verbose
8117
8458
  });
8118
- const discoverRaw = await rpc.request("server/discover", {
8119
- protocolVersion: PROTOCOL_VERSION
8120
- });
8459
+ let discoverRaw;
8460
+ try {
8461
+ discoverRaw = await rpc.request("server/discover", {
8462
+ protocolVersion: PROTOCOL_VERSION
8463
+ });
8464
+ } catch (err) {
8465
+ const pending = rpc.pendingBuffer();
8466
+ rpc.close();
8467
+ return { proc, pendingStdout: pending, error: err };
8468
+ }
8469
+ void readStderr(proc, options.verbose);
8121
8470
  const discoverResult2 = discoverRaw;
8122
8471
  const supported = (discoverResult2?.supportedVersions ?? []).filter(
8123
8472
  (v) => typeof v === "string"
8124
8473
  );
8125
8474
  if (!supported.includes(PROTOCOL_VERSION)) {
8126
- proc.kill("SIGTERM");
8475
+ await proc.kill("SIGTERM");
8127
8476
  throw new Error(
8128
8477
  `Server does not support ${PROTOCOL_VERSION} (advertised: ${supported.join(", ") || "none"})`
8129
8478
  );
@@ -8157,25 +8506,37 @@ async function connect(platform2, options) {
8157
8506
  platform: platform2
8158
8507
  };
8159
8508
  if (options.command) {
8509
+ let fallbackProcess;
8160
8510
  if (!options.protocolVersion || options.protocolVersion.startsWith("2026")) {
8161
- try {
8162
- return await createStdioStatelessConnection({
8163
- command: options.command,
8164
- args: options.args,
8165
- env: options.env,
8166
- cwd: options.cwd,
8167
- platform: platform2,
8168
- version: options.version,
8169
- timeoutMs: options.timeoutMs,
8170
- signal: options.signal,
8171
- verbose: options.verbose
8172
- });
8173
- } catch (err) {
8174
- const isMethodNotFound = err instanceof StatelessRpcError && err.code === -32601;
8175
- const isUnsupported = err instanceof Error && err.message.includes("does not support");
8176
- if (options.protocolVersion?.startsWith("2026")) throw err;
8177
- if (!isMethodNotFound && !isUnsupported) throw err;
8511
+ const result = await probeStdioStateless({
8512
+ command: options.command,
8513
+ args: options.args,
8514
+ env: options.env,
8515
+ cwd: options.cwd,
8516
+ platform: platform2,
8517
+ version: options.version,
8518
+ timeoutMs: options.timeoutMs,
8519
+ signal: options.signal,
8520
+ verbose: options.verbose
8521
+ });
8522
+ if (!("proc" in result)) return result;
8523
+ const isMethodNotFound = result.error instanceof StatelessRpcError && result.error.code === -32601;
8524
+ const isUnsupported = result.error.message.includes("does not support");
8525
+ if (options.protocolVersion?.startsWith("2026")) {
8526
+ try {
8527
+ await result.proc.kill("SIGTERM");
8528
+ } catch {
8529
+ }
8530
+ throw result.error;
8531
+ }
8532
+ if (!isMethodNotFound && !isUnsupported) {
8533
+ try {
8534
+ await result.proc.kill("SIGTERM");
8535
+ } catch {
8536
+ }
8537
+ throw result.error;
8178
8538
  }
8539
+ fallbackProcess = { proc: result.proc, pendingStdout: result.pendingStdout };
8179
8540
  }
8180
8541
  return createPiConnection({
8181
8542
  command: options.command,
@@ -8183,6 +8544,7 @@ async function connect(platform2, options) {
8183
8544
  env: options.env,
8184
8545
  cwd: options.cwd,
8185
8546
  roots: options.roots,
8547
+ existingProcess: fallbackProcess,
8186
8548
  ...shared
8187
8549
  });
8188
8550
  }
@@ -9192,27 +9554,6 @@ async function loadConfig(input) {
9192
9554
  };
9193
9555
  }
9194
9556
 
9195
- // src/config/paths.ts
9196
- function userConfigDir(platform2) {
9197
- const piDir = platform2.env.PI_CODING_AGENT_DIR;
9198
- if (piDir) return piDir;
9199
- const home = platform2.env.HOME ?? platform2.env.USERPROFILE ?? "/";
9200
- return `${home}/.pi/agent`;
9201
- }
9202
- function userConfigPath(platform2) {
9203
- return `${userConfigDir(platform2)}/mcp.json`;
9204
- }
9205
- function projectConfigPath(platform2) {
9206
- return `${platform2.cwd}/.pi/mcp.json`;
9207
- }
9208
- function stateDir(platform2) {
9209
- if (platform2.env.XDG_STATE_HOME) return `${platform2.env.XDG_STATE_HOME}/mcpcat`;
9210
- const home = platform2.env.HOME ?? platform2.env.USERPROFILE ?? "/";
9211
- if (platform2.env.LOCALAPPDATA) return `${platform2.env.LOCALAPPDATA}\\mcpcat\\state`;
9212
- if (platform2.env.SLICC_KERNEL) return `${home}/.local/state/mcpcat`;
9213
- return `${home}/Library/Application Support/mcpcat`;
9214
- }
9215
-
9216
9557
  // src/config/index.ts
9217
9558
  var MergedConfigSource = class _MergedConfigSource {
9218
9559
  entries;
@@ -9252,65 +9593,8 @@ var MergedConfigSource = class _MergedConfigSource {
9252
9593
  }
9253
9594
  };
9254
9595
 
9255
- // src/config/lock.ts
9256
- var LOCK_STALE_MS = 1e4;
9257
- var LOCK_POLL_MS = 50;
9258
- var LOCK_MAX_WAIT_MS = 5e3;
9259
- function isEexist(err) {
9260
- if (err instanceof Error && "code" in err)
9261
- return err.code === "EEXIST";
9262
- if (err instanceof Error) return err.message.includes("EEXIST");
9263
- return false;
9264
- }
9265
- async function removeStaleLock(fs, lockPath) {
9266
- try {
9267
- const s = await fs.stat(lockPath);
9268
- if (Date.now() - s.mtimeMs > LOCK_STALE_MS) {
9269
- try {
9270
- await fs.rmdir(lockPath);
9271
- } catch {
9272
- }
9273
- return true;
9274
- }
9275
- } catch {
9276
- }
9277
- return false;
9278
- }
9279
- async function acquireLock(fs, configPath) {
9280
- const lockPath = `${configPath}.lock`;
9281
- const start = Date.now();
9282
- const parentDir = lockPath.slice(0, lockPath.lastIndexOf("/"));
9283
- if (parentDir) {
9284
- try {
9285
- await fs.mkdir(parentDir);
9286
- } catch {
9287
- }
9288
- }
9289
- while (true) {
9290
- try {
9291
- await fs.mkdirExclusive(lockPath);
9292
- break;
9293
- } catch (err) {
9294
- if (!isEexist(err)) throw err;
9295
- await removeStaleLock(fs, lockPath);
9296
- }
9297
- if (Date.now() - start > LOCK_MAX_WAIT_MS) {
9298
- throw new Error(`mcpcat: could not acquire lock ${lockPath} within ${LOCK_MAX_WAIT_MS}ms`);
9299
- }
9300
- await new Promise((r) => setTimeout(r, LOCK_POLL_MS));
9301
- }
9302
- let released = false;
9303
- return async () => {
9304
- if (released) return;
9305
- released = true;
9306
- try {
9307
- await fs.rmdir(lockPath);
9308
- } catch {
9309
- }
9310
- };
9311
- }
9312
-
9313
9596
  // src/config/edit.ts
9597
+ init_lock();
9314
9598
  function isRecord2(value) {
9315
9599
  return typeof value === "object" && value !== null && !Array.isArray(value);
9316
9600
  }
@@ -11535,7 +11819,7 @@ function capOutput(value, limit) {
11535
11819
  ${value.slice(value.length - half)}`;
11536
11820
  }
11537
11821
  var inflightProcs = /* @__PURE__ */ new Set();
11538
- async function runCommand(platform2, cmdPath, argv, childEnv, stdin, timeoutMs, maxOutput, cwd) {
11822
+ async function runCommand(platform2, cmdPath, argv, childEnv, stdin, timeoutMs, maxOutput, cwd, signal) {
11539
11823
  let proc;
11540
11824
  try {
11541
11825
  proc = await platform2.spawn({
@@ -11574,23 +11858,41 @@ async function runCommand(platform2, cmdPath, argv, childEnv, stdin, timeoutMs,
11574
11858
  const timer = new Promise(
11575
11859
  (resolve2) => setTimeout(() => resolve2("timeout"), timeoutMs)
11576
11860
  );
11861
+ const abortPromise = signal ? new Promise((resolve2) => {
11862
+ if (signal.aborted) {
11863
+ resolve2("timeout");
11864
+ return;
11865
+ }
11866
+ signal.addEventListener("abort", () => resolve2("timeout"), { once: true });
11867
+ }) : null;
11577
11868
  const work = Promise.all([
11578
11869
  readStream3(proc.stdout, stdoutChunks),
11579
11870
  readStream3(proc.stderr, stderrChunks),
11580
11871
  proc.wait()
11581
11872
  ]);
11582
- const result = await Promise.race([work, timer]);
11873
+ const racers = [
11874
+ work,
11875
+ timer
11876
+ ];
11877
+ if (abortPromise !== null) racers.push(abortPromise);
11878
+ const result = await Promise.race(racers);
11583
11879
  if (result === "timeout") {
11584
- proc.kill("SIGTERM");
11585
- await new Promise((resolve2) => setTimeout(resolve2, 5e3));
11586
- try {
11587
- proc.kill("SIGKILL");
11588
- } catch {
11880
+ await proc.kill("SIGTERM");
11881
+ if (!signal?.aborted) {
11882
+ await new Promise((resolve2) => setTimeout(resolve2, 5e3));
11883
+ try {
11884
+ await proc.kill("SIGKILL");
11885
+ } catch {
11886
+ }
11589
11887
  }
11590
11888
  inflightProcs.delete(proc);
11591
11889
  return { stdout: "", stderr: "timed out", exitCode: 124 };
11592
11890
  }
11593
11891
  inflightProcs.delete(proc);
11892
+ try {
11893
+ await proc.kill("SIGTERM");
11894
+ } catch {
11895
+ }
11594
11896
  const [, , exitResult] = result;
11595
11897
  const dec = new TextDecoder();
11596
11898
  return {
@@ -11609,25 +11911,31 @@ function concat(chunks) {
11609
11911
  }
11610
11912
  return out;
11611
11913
  }
11914
+ var KILL_GRACE_MS = 2e3;
11612
11915
  async function killInflight() {
11613
- for (const proc of inflightProcs) {
11614
- try {
11615
- proc.kill("SIGTERM");
11616
- } catch {
11617
- }
11618
- }
11619
- if (inflightProcs.size > 0) {
11620
- await new Promise((resolve2) => setTimeout(resolve2, 5e3));
11621
- for (const proc of inflightProcs) {
11916
+ const procs = [...inflightProcs];
11917
+ if (procs.length === 0) return;
11918
+ await Promise.all(
11919
+ procs.map(async (proc) => {
11622
11920
  try {
11623
- proc.kill("SIGKILL");
11921
+ await proc.kill("SIGTERM");
11624
11922
  } catch {
11625
11923
  }
11626
- }
11627
- }
11924
+ const exited = await Promise.race([
11925
+ proc.wait().then(() => true),
11926
+ new Promise((r) => setTimeout(() => r(false), KILL_GRACE_MS))
11927
+ ]);
11928
+ if (!exited) {
11929
+ try {
11930
+ await proc.kill("SIGKILL");
11931
+ } catch {
11932
+ }
11933
+ }
11934
+ })
11935
+ );
11628
11936
  inflightProcs.clear();
11629
11937
  }
11630
- async function runHelpForCli(platform2, filePath, childEnv, cwd) {
11938
+ async function runHelpForCli(platform2, filePath, childEnv, cwd, signal) {
11631
11939
  const dashed = await runCommand(
11632
11940
  platform2,
11633
11941
  filePath,
@@ -11636,9 +11944,11 @@ async function runHelpForCli(platform2, filePath, childEnv, cwd) {
11636
11944
  void 0,
11637
11945
  1e4,
11638
11946
  MAX_OUTPUT_DEFAULT,
11639
- cwd
11947
+ cwd,
11948
+ signal
11640
11949
  );
11641
11950
  if (dashed.exitCode === 0 && dashed.stdout.trim()) return dashed.stdout;
11951
+ if (signal?.aborted) return "";
11642
11952
  const plain = await runCommand(
11643
11953
  platform2,
11644
11954
  filePath,
@@ -11647,7 +11957,8 @@ async function runHelpForCli(platform2, filePath, childEnv, cwd) {
11647
11957
  void 0,
11648
11958
  1e4,
11649
11959
  MAX_OUTPUT_DEFAULT,
11650
- cwd
11960
+ cwd,
11961
+ signal
11651
11962
  );
11652
11963
  if (plain.exitCode === 0 && plain.stdout.trim()) return plain.stdout;
11653
11964
  return dashed.stdout.trim() ? dashed.stdout : "";
@@ -11674,7 +11985,7 @@ async function expandGroupCommands(platform2, filePath, commands, childEnv, cwd)
11674
11985
  }
11675
11986
  return current;
11676
11987
  }
11677
- async function discoverCli(platform2, filePath, explicitName, childEnv, cwd) {
11988
+ async function discoverCli(platform2, filePath, explicitName, childEnv, cwd, signal) {
11678
11989
  const mcp = await runCommand(
11679
11990
  platform2,
11680
11991
  filePath,
@@ -11683,10 +11994,11 @@ async function discoverCli(platform2, filePath, explicitName, childEnv, cwd) {
11683
11994
  void 0,
11684
11995
  1e4,
11685
11996
  MAX_OUTPUT_DEFAULT,
11686
- cwd
11997
+ cwd,
11998
+ signal
11687
11999
  );
11688
12000
  const override = mcp.exitCode === 0 ? parseMcpOverride(mcp.stdout) : null;
11689
- const helpText2 = override ? "" : await runHelpForCli(platform2, filePath, childEnv, cwd);
12001
+ const helpText2 = override || signal?.aborted ? "" : await runHelpForCli(platform2, filePath, childEnv, cwd, signal);
11690
12002
  if (!override && !helpText2.trim()) {
11691
12003
  throw new Error(`${filePath} did not print help or --mcp descriptor`);
11692
12004
  }
@@ -11806,6 +12118,32 @@ function createToolExecutor(platform2, clis, allTools, childEnv, options, serveC
11806
12118
  }
11807
12119
  return { invoke, rpcTools };
11808
12120
  }
12121
+ async function discoverWithSignal(platform2, commands, childEnv, cwd) {
12122
+ const clis = [];
12123
+ let earlyShutdown = false;
12124
+ let inflightDone;
12125
+ const earlyAbort = new AbortController();
12126
+ const onShutdown = () => {
12127
+ earlyShutdown = true;
12128
+ earlyAbort.abort();
12129
+ inflightDone = killInflight();
12130
+ };
12131
+ platform2.onSignal?.("SIGTERM", onShutdown);
12132
+ platform2.onSignal?.("SIGINT", onShutdown);
12133
+ for (const cmd of commands) {
12134
+ try {
12135
+ const cli = await discoverCli(platform2, cmd.path, cmd.name, childEnv, cwd, earlyAbort.signal);
12136
+ clis.push(cli);
12137
+ } catch (err) {
12138
+ if (earlyShutdown) return { exitCode: 143, inflightDone };
12139
+ await platform2.write(2, `mcpcat serve: ${err.message}
12140
+ `);
12141
+ return { exitCode: 2 };
12142
+ }
12143
+ }
12144
+ if (earlyShutdown) return { exitCode: 143, inflightDone };
12145
+ return { clis };
12146
+ }
11809
12147
  async function runServe(platform2, options, version) {
11810
12148
  let resolvedBearer;
11811
12149
  let generatedBearer = false;
@@ -11849,17 +12187,17 @@ async function runServe(platform2, options, version) {
11849
12187
  }
11850
12188
  const serveCwd = options.cwd ?? platform2.cwd;
11851
12189
  const childEnv = buildChildEnv(platform2, options.envAllow);
11852
- const clis = [];
11853
- for (const cmd of options.commands) {
11854
- try {
11855
- const cli = await discoverCli(platform2, cmd.path, cmd.name, childEnv, serveCwd);
11856
- clis.push(cli);
11857
- } catch (err) {
11858
- await platform2.write(2, `mcpcat serve: ${err.message}
11859
- `);
11860
- return 2;
12190
+ const discovery = await discoverWithSignal(platform2, options.commands, childEnv, serveCwd);
12191
+ if ("exitCode" in discovery) {
12192
+ if (discovery.inflightDone !== void 0) {
12193
+ try {
12194
+ await discovery.inflightDone;
12195
+ } catch {
12196
+ }
11861
12197
  }
12198
+ return discovery.exitCode;
11862
12199
  }
12200
+ const { clis } = discovery;
11863
12201
  const allTools = clis.flatMap((cli) => buildTools(cli.name, cli.commands));
11864
12202
  for (const spec of options.toolTemplates) {
11865
12203
  const tool = parseToolTemplate(spec);
@@ -12085,6 +12423,7 @@ async function runProxyHttp(platform2, options, proxy, resolvedBearer, generated
12085
12423
  if (platform2.onSignal) {
12086
12424
  platform2.onSignal("SIGINT", shutdown);
12087
12425
  platform2.onSignal("SIGTERM", shutdown);
12426
+ platform2.onSignal("SIGHUP", shutdown);
12088
12427
  }
12089
12428
  const handler = (request) => handleProxyMcpRequest(
12090
12429
  request,
@@ -12244,11 +12583,12 @@ async function runHttpServer(platform2, options, tools, call, serverName, versio
12244
12583
  await platform2.write(2, `mcpcat serve: listening on ${listenUrl}
12245
12584
  `);
12246
12585
  let shutdownRequested = false;
12586
+ let inflightDone;
12247
12587
  const shutdown = () => {
12248
12588
  if (shutdownRequested) return;
12249
12589
  shutdownRequested = true;
12250
12590
  listener.close();
12251
- void killInflight();
12591
+ inflightDone = killInflight();
12252
12592
  if (tokenFilePath) {
12253
12593
  platform2.fs.unlink?.(tokenFilePath).catch(() => {
12254
12594
  });
@@ -12257,6 +12597,7 @@ async function runHttpServer(platform2, options, tools, call, serverName, versio
12257
12597
  if (platform2.onSignal) {
12258
12598
  platform2.onSignal("SIGINT", shutdown);
12259
12599
  platform2.onSignal("SIGTERM", shutdown);
12600
+ platform2.onSignal("SIGHUP", shutdown);
12260
12601
  }
12261
12602
  const handler = (request) => handleMcpRequest(
12262
12603
  request,
@@ -12284,6 +12625,12 @@ async function runHttpServer(platform2, options, tools, call, serverName, versio
12284
12625
  } catch {
12285
12626
  if (!shutdownRequested) throw new Error("listener closed unexpectedly");
12286
12627
  }
12628
+ if (inflightDone !== void 0) {
12629
+ try {
12630
+ await inflightDone;
12631
+ } catch {
12632
+ }
12633
+ }
12287
12634
  return 0;
12288
12635
  }
12289
12636
  async function handleMcpRequest(request, tools, call, serverName, version, serverOrigins, allowedOrigins, allowedHosts, resolvedBearer) {
@@ -12555,124 +12902,6 @@ async function signIn(options) {
12555
12902
  }
12556
12903
  }
12557
12904
 
12558
- // src/auth/token-source.ts
12559
- function mcpNamespace(server) {
12560
- return `mcp__${server.replace(/-/g, "_")}`;
12561
- }
12562
- function storeKey(name, serverUrl) {
12563
- const ns = mcpNamespace(name);
12564
- const url = String(new URL(serverUrl));
12565
- return `${ns}|${url}`;
12566
- }
12567
- function isKernel(platform2) {
12568
- return platform2.kind === "kernel";
12569
- }
12570
-
12571
- // src/auth/pi-store.ts
12572
- var AUTH_FILE = "mcp-auth.json";
12573
- var FILE_MODE = 384;
12574
- function parseStates(raw) {
12575
- if (!raw?.trim()) return {};
12576
- const parsed = JSON.parse(raw);
12577
- return typeof parsed === "object" && parsed !== null && !Array.isArray(parsed) ? parsed : {};
12578
- }
12579
- function serializeStates(states) {
12580
- return `${JSON.stringify(states, null, 2)}
12581
- `;
12582
- }
12583
- function legacyKey(serverUrl) {
12584
- return String(new URL(serverUrl));
12585
- }
12586
- var PiFileTokenSource = class {
12587
- platform;
12588
- authPath;
12589
- dirPath;
12590
- constructor(platform2) {
12591
- this.platform = platform2;
12592
- this.dirPath = userConfigDir(platform2);
12593
- this.authPath = `${this.dirPath}/${AUTH_FILE}`;
12594
- }
12595
- get path() {
12596
- return this.authPath;
12597
- }
12598
- async getToken(name, serverUrl) {
12599
- const state = await this.load(name, serverUrl);
12600
- if (!state?.tokens?.access_token) return void 0;
12601
- return {
12602
- accessToken: state.tokens.access_token,
12603
- expiresAt: state.tokensExpireAt
12604
- };
12605
- }
12606
- async load(name, serverUrl) {
12607
- const key = storeKey(name, serverUrl);
12608
- const legacy = legacyKey(serverUrl);
12609
- const release = await this.acquireLock();
12610
- try {
12611
- const raw = await this.readRaw();
12612
- const states = parseStates(raw);
12613
- if (states[key]) return states[key];
12614
- if (states[legacy]) {
12615
- states[key] = states[legacy];
12616
- delete states[legacy];
12617
- await this.writeStates(states);
12618
- return states[key];
12619
- }
12620
- return void 0;
12621
- } finally {
12622
- await release();
12623
- }
12624
- }
12625
- async save(name, serverUrl, state) {
12626
- const key = storeKey(name, serverUrl);
12627
- const release = await this.acquireLock();
12628
- try {
12629
- const raw = await this.readRaw();
12630
- const states = parseStates(raw);
12631
- states[key] = state;
12632
- await this.writeStates(states);
12633
- } finally {
12634
- await release();
12635
- }
12636
- }
12637
- async remove(name, serverUrl) {
12638
- const key = storeKey(name, serverUrl);
12639
- const legacy = legacyKey(serverUrl);
12640
- const release = await this.acquireLock();
12641
- try {
12642
- const raw = await this.readRaw();
12643
- const states = parseStates(raw);
12644
- const stored = key in states ? key : legacy in states ? legacy : void 0;
12645
- if (!stored) return false;
12646
- delete states[stored];
12647
- await this.writeStates(states);
12648
- return true;
12649
- } finally {
12650
- await release();
12651
- }
12652
- }
12653
- async acquireLock() {
12654
- await this.ensureDir();
12655
- return acquireLock(this.platform.fs, this.authPath);
12656
- }
12657
- async ensureDir() {
12658
- try {
12659
- await this.platform.fs.mkdir(this.dirPath);
12660
- } catch {
12661
- }
12662
- }
12663
- async readRaw() {
12664
- try {
12665
- const data = await this.platform.fs.readFile(this.authPath);
12666
- return new TextDecoder().decode(data);
12667
- } catch {
12668
- return void 0;
12669
- }
12670
- }
12671
- async writeStates(states) {
12672
- await this.platform.fs.writeFile(this.authPath, serializeStates(states), { mode: FILE_MODE });
12673
- }
12674
- };
12675
-
12676
12905
  // src/cli/auth-verbs.ts
12677
12906
  var resolvedSource;
12678
12907
  async function createTokenSource(platform2) {
@@ -14366,6 +14595,17 @@ async function runCall(platform2, conn, toolName, dataArg, toolArgs, opts) {
14366
14595
  return EXIT_USAGE;
14367
14596
  }
14368
14597
  fin = mergeArgs(base, c.value);
14598
+ } else if (!dataArg && !opts.noValidate) {
14599
+ const tools = await conn.listTools();
14600
+ const tool = tools.find((t) => t.name === toolName);
14601
+ const schema = tool?.inputSchema;
14602
+ const required = Array.isArray(schema?.required) ? schema.required : [];
14603
+ for (const r of required) {
14604
+ if (!Object.hasOwn(base, r)) {
14605
+ await writeErr(platform2, opts.json ?? false, "usage", `missing required flag --${r}`);
14606
+ return EXIT_USAGE;
14607
+ }
14608
+ }
14369
14609
  }
14370
14610
  return renderCallResult(
14371
14611
  platform2,
@@ -14583,7 +14823,10 @@ async function probeServer(_name, config, platform2) {
14583
14823
  const opts = { version: "probe" };
14584
14824
  if ("url" in config && config.url) {
14585
14825
  opts.url = config.url;
14586
- if ("headers" in config) opts.headers = config.headers;
14826
+ if ("headers" in config) {
14827
+ const expanded = expandHeaders(config.headers, platform2.env);
14828
+ if (expanded) opts.headers = expanded;
14829
+ }
14587
14830
  } else if ("command" in config && config.command) {
14588
14831
  opts.command = config.command;
14589
14832
  if ("args" in config) opts.args = config.args;
@@ -14717,6 +14960,10 @@ async function dispatchMultiTarget(platform2, parsed, version) {
14717
14960
  } catch {
14718
14961
  }
14719
14962
  }
14963
+ try {
14964
+ await Promise.race([killAllStdio(), new Promise((r) => setTimeout(r, 3e3))]);
14965
+ } catch {
14966
+ }
14720
14967
  platform2.exit(exitCode);
14721
14968
  }
14722
14969
  platform2.onSignal?.("SIGTERM", () => void killTreeAndExit(143));
@@ -14945,11 +15192,25 @@ function classifyError(err) {
14945
15192
  }
14946
15193
  async function resolveAuthProvider(platform2, hasAuthHeader, url, target, config) {
14947
15194
  if (hasAuthHeader || !url) return void 0;
14948
- const source = await createTokenSource(platform2);
15195
+ const piSource = new PiFileTokenSource(platform2);
14949
15196
  const entry = config.entry(target);
14950
15197
  const oauth = entry && "url" in entry.config ? entry.config.oauth : void 0;
14951
15198
  const name = entry ? target : `url:${new URL(url).origin}${new URL(url).pathname}`;
14952
- return createMcpAuthProvider({ name, serverUrl: url, source, oauth, platform: platform2 });
15199
+ const provider = createMcpAuthProvider({
15200
+ name,
15201
+ serverUrl: url,
15202
+ source: piSource,
15203
+ oauth,
15204
+ platform: platform2
15205
+ });
15206
+ const credentialSecrets = [];
15207
+ const state = await piSource.loadWithoutLock(name, url);
15208
+ if (state?.tokens?.access_token) credentialSecrets.push(state.tokens.access_token);
15209
+ if (state?.tokens?.refresh_token) credentialSecrets.push(state.tokens.refresh_token);
15210
+ if (state?.clientInformation && "client_secret" in state.clientInformation && state.clientInformation.client_secret) {
15211
+ credentialSecrets.push(state.clientInformation.client_secret);
15212
+ }
15213
+ return { provider, credentialSecrets };
14953
15214
  }
14954
15215
  function classifyConnectionError(err, target, interrupted) {
14955
15216
  if (err instanceof McpAuthError || err instanceof AuthStepUpError || err instanceof JerkSignInRequiredError) {
@@ -14995,7 +15256,7 @@ async function handleInputRequired(platform2, conn, err, respondData, json) {
14995
15256
  `);
14996
15257
  return EXIT_INPUT_REQUIRED;
14997
15258
  }
14998
- const isTty = platform2.isatty(0);
15259
+ const isTty = platform2.isatty(0) && platform2.isatty(2);
14999
15260
  const elicitResult = await handleElicitation(platform2, inputReq, isTty, respondData);
15000
15261
  if ("exitCode" in elicitResult) {
15001
15262
  await platform2.write(2, `${err.requestJson}
@@ -15041,6 +15302,10 @@ async function runClientVerb(platform2, version, parsed) {
15041
15302
  } catch {
15042
15303
  }
15043
15304
  }
15305
+ try {
15306
+ await Promise.race([killAllStdio(), new Promise((r) => setTimeout(r, 3e3))]);
15307
+ } catch {
15308
+ }
15044
15309
  platform2.exit(exitCode);
15045
15310
  }
15046
15311
  platform2.onSignal?.("SIGINT", () => {
@@ -15088,13 +15353,20 @@ async function runClientVerb(platform2, version, parsed) {
15088
15353
  };
15089
15354
  const mergedHeaders = { ...configHeaders, ...expanded };
15090
15355
  const hasAuthHeader = "Authorization" in mergedHeaders;
15091
- const authProvider = await resolveAuthProvider(
15356
+ const authResolved = await resolveAuthProvider(
15092
15357
  platform2,
15093
15358
  hasAuthHeader,
15094
15359
  resolved.url,
15095
15360
  target,
15096
15361
  config
15097
15362
  );
15363
+ const authProvider = authResolved?.provider;
15364
+ if (authResolved?.credentialSecrets) {
15365
+ for (const s of authResolved.credentialSecrets) {
15366
+ allSecrets.add(s);
15367
+ verbose.secrets.add(s);
15368
+ }
15369
+ }
15098
15370
  const roots = buildRoots(parsed.roots, !!resolved.command, platform2.cwd);
15099
15371
  let respondData;
15100
15372
  if (parsed.respondArg) {
@@ -15211,31 +15483,50 @@ function kernelFs(ctx) {
15211
15483
  }
15212
15484
  },
15213
15485
  rmdir: (path) => ctx.fs.rm(path),
15214
- unlink: (path) => ctx.fs.unlink(path)
15486
+ unlink: (path) => ctx.fs.unlink(path),
15487
+ async createExclusive(path) {
15488
+ const f = await ctx.open(path, { create: true, exclusive: true, write: true });
15489
+ await f.close();
15490
+ },
15491
+ chmod: ctx.fs.chmod ? (path, mode) => ctx.fs.chmod(path, mode) : void 0
15215
15492
  };
15216
15493
  }
15494
+ var groupSpawnSupported;
15217
15495
  async function kernelSpawn(ctx, options) {
15496
+ const tryGroup = groupSpawnSupported !== false;
15218
15497
  const result = await ctx.spawn({
15219
15498
  argv: options.argv,
15220
15499
  env: options.env,
15221
15500
  cwd: options.cwd,
15222
15501
  stdin: "pipe",
15223
15502
  stdout: "pipe",
15224
- stderr: "pipe"
15503
+ stderr: "pipe",
15504
+ ...tryGroup ? { pgid: 0 } : {}
15225
15505
  });
15226
15506
  const childPid = result.pid;
15507
+ if (groupSpawnSupported === void 0) {
15508
+ try {
15509
+ await ctx.kill(-childPid, "SIGCONT");
15510
+ groupSpawnSupported = true;
15511
+ } catch {
15512
+ groupSpawnSupported = false;
15513
+ }
15514
+ }
15515
+ const useGroupKill = groupSpawnSupported;
15227
15516
  return {
15228
15517
  stdin: result.stdin,
15229
15518
  stdout: result.stdout,
15230
15519
  stderr: result.stderr,
15231
15520
  wait: () => result.wait(),
15232
- kill: (signal) => {
15233
- try {
15234
- ctx.kill(-childPid, signal);
15235
- } catch {
15521
+ kill: async (signal) => {
15522
+ if (useGroupKill) {
15523
+ try {
15524
+ await ctx.kill(-childPid, signal);
15525
+ } catch {
15526
+ }
15236
15527
  }
15237
15528
  try {
15238
- ctx.kill(childPid, signal);
15529
+ await ctx.kill(childPid, signal);
15239
15530
  } catch {
15240
15531
  }
15241
15532
  }
@@ -15455,7 +15746,7 @@ async function main(ctx) {
15455
15746
  packageDir: "/node_modules/@ai-ecoverse/mcpcat"
15456
15747
  });
15457
15748
  const args = ctx.argv.slice(1);
15458
- return run(platform2, "0.14.1", args);
15749
+ return run(platform2, "0.14.3", args);
15459
15750
  }
15460
15751
  export {
15461
15752
  main as default