mmt-mcp 1.46.5 → 1.47.0-pre

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/server.cjs CHANGED
@@ -21242,6 +21242,7 @@ var testToJsfunc = async (ctx, root, importTracker = new ImportTracker()) => {
21242
21242
  const useCallCache = typeof cacheProbe === "number" && Number.isFinite(cacheProbe);
21243
21243
  const cacheTitle = JSON.stringify(ctx.test.title || ctx.name || fnName);
21244
21244
  const cacheSpecLiteral = JSON.stringify(cacheSpec);
21245
+ const cacheFilePathLiteral = JSON.stringify(ctx.filePath || "");
21245
21246
  const inputKeys = Object.keys(replaced.inputs || {});
21246
21247
  const resolvedInputsLiteral = inputKeys.length ? "{ " + inputKeys.map((k) => `${k}`).join(", ") + " }" : "{}";
21247
21248
  if (useCallCache && !root) {
@@ -21256,7 +21257,7 @@ var testToJsfunc = async (ctx, root, importTracker = new ImportTracker()) => {
21256
21257
 
21257
21258
  let outputs = {${outputParams}};
21258
21259
  ${indentLines(flow)}
21259
- setTestCallCache_(${cacheTitle}, __mmtResolvedInputs, outputs, parseCacheExpiryAtMs_(${cacheSpecLiteral}));
21260
+ setTestCallCache_(${cacheTitle}, __mmtResolvedInputs, outputs, parseCacheExpiryAtMs_(${cacheSpecLiteral}), ${cacheFilePathLiteral});
21260
21261
  return outputs;
21261
21262
  };
21262
21263
  `;
@@ -21268,7 +21269,7 @@ var testToJsfunc = async (ctx, root, importTracker = new ImportTracker()) => {
21268
21269
 
21269
21270
  let outputs = {${outputParams}};
21270
21271
  ${indentLines(flow)}
21271
- setTestCallCache_(${cacheTitle}, __mmtResolvedInputs, outputs, parseCacheExpiryAtMs_(${cacheSpecLiteral}));
21272
+ setTestCallCache_(${cacheTitle}, __mmtResolvedInputs, outputs, parseCacheExpiryAtMs_(${cacheSpecLiteral}), ${cacheFilePathLiteral});
21272
21273
  return outputs;
21273
21274
  };
21274
21275
  `;
@@ -21683,6 +21684,7 @@ __export(testHelper_exports, {
21683
21684
  lessOrEqual_: () => lessOrEqual_,
21684
21685
  less_: () => less_,
21685
21686
  listRunningServers_: () => listRunningServers_,
21687
+ listTestCallCacheEntries_: () => listTestCallCacheEntries_,
21686
21688
  matches_: () => matches_,
21687
21689
  notContains_: () => notContains_,
21688
21690
  notEndsWith_: () => notEndsWith_,
@@ -23023,7 +23025,7 @@ var getTestCallCache_ = (title, inputs) => {
23023
23025
  }
23024
23026
  return clone;
23025
23027
  };
23026
- var setTestCallCache_ = (title, inputs, outputs, expiresAt) => {
23028
+ var setTestCallCache_ = (title, inputs, outputs, expiresAt, filePath) => {
23027
23029
  if (typeof expiresAt !== "number" || !Number.isFinite(expiresAt)) {
23028
23030
  return;
23029
23031
  }
@@ -23033,11 +23035,36 @@ var setTestCallCache_ = (title, inputs, outputs, expiresAt) => {
23033
23035
  delete rest.cached;
23034
23036
  clone._ = rest;
23035
23037
  }
23038
+ const path6 = typeof filePath === "string" && filePath.trim() ? filePath.trim() : void 0;
23036
23039
  __mmtTestCallCache.set(testCallCacheKey_(title, inputs), {
23040
+ title: String(title ?? ""),
23041
+ inputs: deepCloneCacheValue_(inputs ?? {}) || {},
23037
23042
  outputs: clone,
23038
- expiresAt
23043
+ expiresAt,
23044
+ ...path6 ? { filePath: path6 } : {}
23039
23045
  });
23040
23046
  };
23047
+ var listTestCallCacheEntries_ = () => {
23048
+ const now = Date.now();
23049
+ const out = [];
23050
+ for (const [key, entry] of __mmtTestCallCache.entries()) {
23051
+ if (now >= entry.expiresAt) {
23052
+ __mmtTestCallCache.delete(key);
23053
+ continue;
23054
+ }
23055
+ out.push({
23056
+ kind: "test-call",
23057
+ title: entry.title,
23058
+ ...entry.filePath ? { filePath: entry.filePath } : {},
23059
+ inputs: deepCloneCacheValue_(entry.inputs) || {},
23060
+ outputs: deepCloneCacheValue_(entry.outputs),
23061
+ expiresAt: entry.expiresAt,
23062
+ remainingMs: entry.expiresAt - now
23063
+ });
23064
+ }
23065
+ out.sort((a, b) => a.remainingMs - b.remainingMs);
23066
+ return out;
23067
+ };
23041
23068
  var resolveReporter = () => typeof __mmtReportStep === "function" ? __mmtReportStep : void 0;
23042
23069
  var ensurePayload = (event) => {
23043
23070
  const payload = { ...event };
@@ -27167,6 +27194,17 @@ async function executeApi(prepared, options, preLogs) {
27167
27194
  }
27168
27195
 
27169
27196
  // ../core/src/env/envStore.ts
27197
+ var activeEnvStores = /* @__PURE__ */ new Set();
27198
+ function registerActiveEnvStore(store) {
27199
+ if (store) {
27200
+ activeEnvStores.add(store);
27201
+ }
27202
+ }
27203
+ function unregisterActiveEnvStore(store) {
27204
+ if (store) {
27205
+ activeEnvStores.delete(store);
27206
+ }
27207
+ }
27170
27208
  var ENV_FILE_PATH_KEY = "__mmtEnvFilePath";
27171
27209
  function isEnvFilePathValue(value) {
27172
27210
  if (typeof value !== "string") {
@@ -27202,14 +27240,17 @@ function firstEnvFileOutput(outputs, declaredKeys) {
27202
27240
  }
27203
27241
  return null;
27204
27242
  }
27205
- function makeEnvFileGetter(store, rawPath) {
27206
- let cached;
27243
+ function makeEnvFileGetter(store, envName, rawPath) {
27207
27244
  let inFlight;
27208
27245
  const path6 = rawPath.trim();
27209
27246
  const getter = async () => {
27210
27247
  const now = Date.now();
27211
- if (cached && now < cached.expiresAt) {
27212
- return cached.value;
27248
+ const hit = store.liveCache.get(envName);
27249
+ if (hit && now < hit.expiresAt) {
27250
+ return hit.value;
27251
+ }
27252
+ if (hit) {
27253
+ store.liveCache.delete(envName);
27213
27254
  }
27214
27255
  if (inFlight) {
27215
27256
  return inFlight;
@@ -27225,9 +27266,9 @@ function makeEnvFileGetter(store, rawPath) {
27225
27266
  const value = firstEnvFileOutput(result?.outputs, result?.outputKeys);
27226
27267
  const expiresAt = parseCacheExpiryAtMs(result?.cache, Date.now());
27227
27268
  if (typeof expiresAt === "number" && Number.isFinite(expiresAt) && expiresAt > Date.now()) {
27228
- cached = { value, expiresAt };
27269
+ store.liveCache.set(envName, { filePath: path6, value, expiresAt });
27229
27270
  } else {
27230
- cached = void 0;
27271
+ store.liveCache.delete(envName);
27231
27272
  }
27232
27273
  return value;
27233
27274
  } catch {
@@ -27252,11 +27293,12 @@ function plainEnvValuesForClone(values) {
27252
27293
  function createEnvStore(initial, options) {
27253
27294
  const store = {
27254
27295
  values: {},
27296
+ liveCache: /* @__PURE__ */ new Map(),
27255
27297
  resolveFilePath: options?.resolveFilePath
27256
27298
  };
27257
27299
  for (const [name, value] of Object.entries(initial || {})) {
27258
27300
  if (isEnvFilePathValue(value)) {
27259
- store.values[name] = makeEnvFileGetter(store, value);
27301
+ store.values[name] = makeEnvFileGetter(store, name, value);
27260
27302
  } else {
27261
27303
  store.values[name] = value;
27262
27304
  }
@@ -29591,77 +29633,87 @@ async function runFile(options) {
29591
29633
  };
29592
29634
  }
29593
29635
  attachEnvFileRunner(options.envStore, options);
29594
- if (docType === "api") {
29595
- return executeApi(prepared, options, preLogs);
29636
+ const trackStore = !options.__mmtIsSuiteBundleChildRun && !options.__mmtEnvValueRun;
29637
+ if (trackStore) {
29638
+ registerActiveEnvStore(options.envStore);
29596
29639
  }
29597
- if (docType === "test") {
29598
- if (options.tagFilter) {
29599
- try {
29600
- const testDoc = yamlToTest(prepared.rawText);
29601
- if (decideTagRun("test", testDoc.tags, options.tagFilter, options.tagParentSelected === true) === "skip") {
29602
- options.reporter && options.reporter({
29603
- scope: "suite-item",
29604
- status: "skipped",
29605
- runId: options.runId,
29606
- filePath: prepared.filePath,
29607
- title: testDoc.title,
29608
- docType: "test",
29609
- id: options.id
29610
- });
29611
- return {
29612
- js: "",
29613
- result: { success: true, durationMs: 0, errors: [], itemStatus: "skipped" },
29614
- identifier: prepared.baseName,
29615
- displayName: testDoc.title || prepared.baseName,
29616
- docType: "test",
29617
- inputsUsed: prepared.inputsUsed,
29618
- envVarsUsed: prepared.envVarsUsed
29619
- };
29640
+ try {
29641
+ if (docType === "api") {
29642
+ return await executeApi(prepared, options, preLogs);
29643
+ }
29644
+ if (docType === "test") {
29645
+ if (options.tagFilter) {
29646
+ try {
29647
+ const testDoc = yamlToTest(prepared.rawText);
29648
+ if (decideTagRun("test", testDoc.tags, options.tagFilter, options.tagParentSelected === true) === "skip") {
29649
+ options.reporter && options.reporter({
29650
+ scope: "suite-item",
29651
+ status: "skipped",
29652
+ runId: options.runId,
29653
+ filePath: prepared.filePath,
29654
+ title: testDoc.title,
29655
+ docType: "test",
29656
+ id: options.id
29657
+ });
29658
+ return {
29659
+ js: "",
29660
+ result: { success: true, durationMs: 0, errors: [], itemStatus: "skipped" },
29661
+ identifier: prepared.baseName,
29662
+ displayName: testDoc.title || prepared.baseName,
29663
+ docType: "test",
29664
+ inputsUsed: prepared.inputsUsed,
29665
+ envVarsUsed: prepared.envVarsUsed
29666
+ };
29667
+ }
29668
+ } catch {
29620
29669
  }
29621
- } catch {
29622
29670
  }
29671
+ return await executeTest(prepared, options, preLogs);
29623
29672
  }
29624
- return executeTest(prepared, options, preLogs);
29625
- }
29626
- if (docType === "suite") {
29627
- let bundle = options.suiteBundle;
29628
- if (!bundle) {
29629
- const tree = await buildSuiteHierarchyFromSuiteFile({
29630
- suiteFilePath: prepared.filePath,
29631
- suiteRawText: prepared.rawText,
29632
- fileLoader: options.fileLoader,
29633
- projectRoot: options.projectRoot
29634
- });
29635
- bundle = createSuiteBundle({
29636
- rootSuitePath: prepared.filePath,
29637
- hierarchy: tree,
29638
- servers: tree.servers,
29639
- environment: tree.environment,
29640
- export: tree.export
29673
+ if (docType === "suite") {
29674
+ let bundle = options.suiteBundle;
29675
+ if (!bundle) {
29676
+ const tree = await buildSuiteHierarchyFromSuiteFile({
29677
+ suiteFilePath: prepared.filePath,
29678
+ suiteRawText: prepared.rawText,
29679
+ fileLoader: options.fileLoader,
29680
+ projectRoot: options.projectRoot
29681
+ });
29682
+ bundle = createSuiteBundle({
29683
+ rootSuitePath: prepared.filePath,
29684
+ hierarchy: tree,
29685
+ servers: tree.servers,
29686
+ environment: tree.environment,
29687
+ export: tree.export
29688
+ });
29689
+ }
29690
+ return await executeSuiteBundle({
29691
+ bundle,
29692
+ options: { ...options, suiteBundle: bundle },
29693
+ preLogs,
29694
+ runFile
29641
29695
  });
29642
29696
  }
29643
- return executeSuiteBundle({
29644
- bundle,
29645
- options: { ...options, suiteBundle: bundle },
29646
- preLogs,
29647
- runFile
29648
- });
29649
- }
29650
- if (docType === "loadtest") {
29651
- return executeLoadTest(prepared, options, preLogs, runFile);
29652
- }
29653
- if (options.__mmtEnvValueRun) {
29654
- return {
29655
- js: "",
29656
- result: { success: true, durationMs: 0, errors: [], outputs: {} },
29657
- identifier: prepared.baseName,
29658
- displayName: prepared.baseName,
29659
- docType,
29660
- inputsUsed: prepared.inputsUsed,
29661
- envVarsUsed: prepared.envVarsUsed
29662
- };
29697
+ if (docType === "loadtest") {
29698
+ return await executeLoadTest(prepared, options, preLogs, runFile);
29699
+ }
29700
+ if (options.__mmtEnvValueRun) {
29701
+ return {
29702
+ js: "",
29703
+ result: { success: true, durationMs: 0, errors: [], outputs: {} },
29704
+ identifier: prepared.baseName,
29705
+ displayName: prepared.baseName,
29706
+ docType,
29707
+ inputsUsed: prepared.inputsUsed,
29708
+ envVarsUsed: prepared.envVarsUsed
29709
+ };
29710
+ }
29711
+ throw new Error("Run is currently supported for test or api documents only.");
29712
+ } finally {
29713
+ if (trackStore) {
29714
+ unregisterActiveEnvStore(options.envStore);
29715
+ }
29663
29716
  }
29664
- throw new Error("Run is currently supported for test or api documents only.");
29665
29717
  }
29666
29718
  function outputKeysFromYaml(rawText) {
29667
29719
  try {
@@ -31810,6 +31862,18 @@ function createHttpAgentWithTracking(hostname) {
31810
31862
  httpAgentPool.set(agentKey, agent);
31811
31863
  return agent;
31812
31864
  }
31865
+ function recordConnectionActivity(socket) {
31866
+ const connId = socketConnectionIds.get(socket);
31867
+ if (connId) {
31868
+ connectionTracker.activity(connId, { incrementRequests: true });
31869
+ }
31870
+ }
31871
+ function markConnectionIdle(socket) {
31872
+ const connId = socketConnectionIds.get(socket);
31873
+ if (connId) {
31874
+ connectionTracker.idle(connId);
31875
+ }
31876
+ }
31813
31877
 
31814
31878
  // ../core/src/network/httpErrors.ts
31815
31879
  function toNetworkError(err, config, duration, warning) {
@@ -32525,7 +32589,16 @@ async function sendHttpRequest(req, config) {
32525
32589
  return axios2.request({ ...baseRequestConfig, httpsAgent, httpAgent });
32526
32590
  };
32527
32591
  const start = Date.now();
32592
+ const noteKeepAliveActivity = (source) => {
32593
+ const socket = source?.request?.socket || source?.socket;
32594
+ if (!socket) {
32595
+ return;
32596
+ }
32597
+ recordConnectionActivity(socket);
32598
+ markConnectionIdle(socket);
32599
+ };
32528
32600
  const toSuccess = (response, warning) => {
32601
+ noteKeepAliveActivity(response);
32529
32602
  const duration = Date.now() - start;
32530
32603
  const headers = normalizeAxiosHeaders(response.headers);
32531
32604
  return {
@@ -32542,6 +32615,8 @@ async function sendHttpRequest(req, config) {
32542
32615
  const duration = Date.now() - start;
32543
32616
  if (err?.response && Number(err.response.status) >= 400) {
32544
32617
  dropKeepAliveSocket(err);
32618
+ } else if (err?.response) {
32619
+ noteKeepAliveActivity(err.response);
32545
32620
  }
32546
32621
  if (err?.response) {
32547
32622
  const headers = normalizeAxiosHeaders(err.response.headers);
package/dist/server.js CHANGED
@@ -21242,6 +21242,7 @@ var testToJsfunc = async (ctx, root, importTracker = new ImportTracker()) => {
21242
21242
  const useCallCache = typeof cacheProbe === "number" && Number.isFinite(cacheProbe);
21243
21243
  const cacheTitle = JSON.stringify(ctx.test.title || ctx.name || fnName);
21244
21244
  const cacheSpecLiteral = JSON.stringify(cacheSpec);
21245
+ const cacheFilePathLiteral = JSON.stringify(ctx.filePath || "");
21245
21246
  const inputKeys = Object.keys(replaced.inputs || {});
21246
21247
  const resolvedInputsLiteral = inputKeys.length ? "{ " + inputKeys.map((k) => `${k}`).join(", ") + " }" : "{}";
21247
21248
  if (useCallCache && !root) {
@@ -21256,7 +21257,7 @@ var testToJsfunc = async (ctx, root, importTracker = new ImportTracker()) => {
21256
21257
 
21257
21258
  let outputs = {${outputParams}};
21258
21259
  ${indentLines(flow)}
21259
- setTestCallCache_(${cacheTitle}, __mmtResolvedInputs, outputs, parseCacheExpiryAtMs_(${cacheSpecLiteral}));
21260
+ setTestCallCache_(${cacheTitle}, __mmtResolvedInputs, outputs, parseCacheExpiryAtMs_(${cacheSpecLiteral}), ${cacheFilePathLiteral});
21260
21261
  return outputs;
21261
21262
  };
21262
21263
  `;
@@ -21268,7 +21269,7 @@ var testToJsfunc = async (ctx, root, importTracker = new ImportTracker()) => {
21268
21269
 
21269
21270
  let outputs = {${outputParams}};
21270
21271
  ${indentLines(flow)}
21271
- setTestCallCache_(${cacheTitle}, __mmtResolvedInputs, outputs, parseCacheExpiryAtMs_(${cacheSpecLiteral}));
21272
+ setTestCallCache_(${cacheTitle}, __mmtResolvedInputs, outputs, parseCacheExpiryAtMs_(${cacheSpecLiteral}), ${cacheFilePathLiteral});
21272
21273
  return outputs;
21273
21274
  };
21274
21275
  `;
@@ -21683,6 +21684,7 @@ __export(testHelper_exports, {
21683
21684
  lessOrEqual_: () => lessOrEqual_,
21684
21685
  less_: () => less_,
21685
21686
  listRunningServers_: () => listRunningServers_,
21687
+ listTestCallCacheEntries_: () => listTestCallCacheEntries_,
21686
21688
  matches_: () => matches_,
21687
21689
  notContains_: () => notContains_,
21688
21690
  notEndsWith_: () => notEndsWith_,
@@ -23023,7 +23025,7 @@ var getTestCallCache_ = (title, inputs) => {
23023
23025
  }
23024
23026
  return clone;
23025
23027
  };
23026
- var setTestCallCache_ = (title, inputs, outputs, expiresAt) => {
23028
+ var setTestCallCache_ = (title, inputs, outputs, expiresAt, filePath) => {
23027
23029
  if (typeof expiresAt !== "number" || !Number.isFinite(expiresAt)) {
23028
23030
  return;
23029
23031
  }
@@ -23033,11 +23035,36 @@ var setTestCallCache_ = (title, inputs, outputs, expiresAt) => {
23033
23035
  delete rest.cached;
23034
23036
  clone._ = rest;
23035
23037
  }
23038
+ const path6 = typeof filePath === "string" && filePath.trim() ? filePath.trim() : void 0;
23036
23039
  __mmtTestCallCache.set(testCallCacheKey_(title, inputs), {
23040
+ title: String(title ?? ""),
23041
+ inputs: deepCloneCacheValue_(inputs ?? {}) || {},
23037
23042
  outputs: clone,
23038
- expiresAt
23043
+ expiresAt,
23044
+ ...path6 ? { filePath: path6 } : {}
23039
23045
  });
23040
23046
  };
23047
+ var listTestCallCacheEntries_ = () => {
23048
+ const now = Date.now();
23049
+ const out = [];
23050
+ for (const [key, entry] of __mmtTestCallCache.entries()) {
23051
+ if (now >= entry.expiresAt) {
23052
+ __mmtTestCallCache.delete(key);
23053
+ continue;
23054
+ }
23055
+ out.push({
23056
+ kind: "test-call",
23057
+ title: entry.title,
23058
+ ...entry.filePath ? { filePath: entry.filePath } : {},
23059
+ inputs: deepCloneCacheValue_(entry.inputs) || {},
23060
+ outputs: deepCloneCacheValue_(entry.outputs),
23061
+ expiresAt: entry.expiresAt,
23062
+ remainingMs: entry.expiresAt - now
23063
+ });
23064
+ }
23065
+ out.sort((a, b) => a.remainingMs - b.remainingMs);
23066
+ return out;
23067
+ };
23041
23068
  var resolveReporter = () => typeof __mmtReportStep === "function" ? __mmtReportStep : void 0;
23042
23069
  var ensurePayload = (event) => {
23043
23070
  const payload = { ...event };
@@ -27167,6 +27194,17 @@ async function executeApi(prepared, options, preLogs) {
27167
27194
  }
27168
27195
 
27169
27196
  // ../core/src/env/envStore.ts
27197
+ var activeEnvStores = /* @__PURE__ */ new Set();
27198
+ function registerActiveEnvStore(store) {
27199
+ if (store) {
27200
+ activeEnvStores.add(store);
27201
+ }
27202
+ }
27203
+ function unregisterActiveEnvStore(store) {
27204
+ if (store) {
27205
+ activeEnvStores.delete(store);
27206
+ }
27207
+ }
27170
27208
  var ENV_FILE_PATH_KEY = "__mmtEnvFilePath";
27171
27209
  function isEnvFilePathValue(value) {
27172
27210
  if (typeof value !== "string") {
@@ -27202,14 +27240,17 @@ function firstEnvFileOutput(outputs, declaredKeys) {
27202
27240
  }
27203
27241
  return null;
27204
27242
  }
27205
- function makeEnvFileGetter(store, rawPath) {
27206
- let cached;
27243
+ function makeEnvFileGetter(store, envName, rawPath) {
27207
27244
  let inFlight;
27208
27245
  const path6 = rawPath.trim();
27209
27246
  const getter = async () => {
27210
27247
  const now = Date.now();
27211
- if (cached && now < cached.expiresAt) {
27212
- return cached.value;
27248
+ const hit = store.liveCache.get(envName);
27249
+ if (hit && now < hit.expiresAt) {
27250
+ return hit.value;
27251
+ }
27252
+ if (hit) {
27253
+ store.liveCache.delete(envName);
27213
27254
  }
27214
27255
  if (inFlight) {
27215
27256
  return inFlight;
@@ -27225,9 +27266,9 @@ function makeEnvFileGetter(store, rawPath) {
27225
27266
  const value = firstEnvFileOutput(result?.outputs, result?.outputKeys);
27226
27267
  const expiresAt = parseCacheExpiryAtMs(result?.cache, Date.now());
27227
27268
  if (typeof expiresAt === "number" && Number.isFinite(expiresAt) && expiresAt > Date.now()) {
27228
- cached = { value, expiresAt };
27269
+ store.liveCache.set(envName, { filePath: path6, value, expiresAt });
27229
27270
  } else {
27230
- cached = void 0;
27271
+ store.liveCache.delete(envName);
27231
27272
  }
27232
27273
  return value;
27233
27274
  } catch {
@@ -27252,11 +27293,12 @@ function plainEnvValuesForClone(values) {
27252
27293
  function createEnvStore(initial, options) {
27253
27294
  const store = {
27254
27295
  values: {},
27296
+ liveCache: /* @__PURE__ */ new Map(),
27255
27297
  resolveFilePath: options?.resolveFilePath
27256
27298
  };
27257
27299
  for (const [name, value] of Object.entries(initial || {})) {
27258
27300
  if (isEnvFilePathValue(value)) {
27259
- store.values[name] = makeEnvFileGetter(store, value);
27301
+ store.values[name] = makeEnvFileGetter(store, name, value);
27260
27302
  } else {
27261
27303
  store.values[name] = value;
27262
27304
  }
@@ -29591,77 +29633,87 @@ async function runFile(options) {
29591
29633
  };
29592
29634
  }
29593
29635
  attachEnvFileRunner(options.envStore, options);
29594
- if (docType === "api") {
29595
- return executeApi(prepared, options, preLogs);
29636
+ const trackStore = !options.__mmtIsSuiteBundleChildRun && !options.__mmtEnvValueRun;
29637
+ if (trackStore) {
29638
+ registerActiveEnvStore(options.envStore);
29596
29639
  }
29597
- if (docType === "test") {
29598
- if (options.tagFilter) {
29599
- try {
29600
- const testDoc = yamlToTest(prepared.rawText);
29601
- if (decideTagRun("test", testDoc.tags, options.tagFilter, options.tagParentSelected === true) === "skip") {
29602
- options.reporter && options.reporter({
29603
- scope: "suite-item",
29604
- status: "skipped",
29605
- runId: options.runId,
29606
- filePath: prepared.filePath,
29607
- title: testDoc.title,
29608
- docType: "test",
29609
- id: options.id
29610
- });
29611
- return {
29612
- js: "",
29613
- result: { success: true, durationMs: 0, errors: [], itemStatus: "skipped" },
29614
- identifier: prepared.baseName,
29615
- displayName: testDoc.title || prepared.baseName,
29616
- docType: "test",
29617
- inputsUsed: prepared.inputsUsed,
29618
- envVarsUsed: prepared.envVarsUsed
29619
- };
29640
+ try {
29641
+ if (docType === "api") {
29642
+ return await executeApi(prepared, options, preLogs);
29643
+ }
29644
+ if (docType === "test") {
29645
+ if (options.tagFilter) {
29646
+ try {
29647
+ const testDoc = yamlToTest(prepared.rawText);
29648
+ if (decideTagRun("test", testDoc.tags, options.tagFilter, options.tagParentSelected === true) === "skip") {
29649
+ options.reporter && options.reporter({
29650
+ scope: "suite-item",
29651
+ status: "skipped",
29652
+ runId: options.runId,
29653
+ filePath: prepared.filePath,
29654
+ title: testDoc.title,
29655
+ docType: "test",
29656
+ id: options.id
29657
+ });
29658
+ return {
29659
+ js: "",
29660
+ result: { success: true, durationMs: 0, errors: [], itemStatus: "skipped" },
29661
+ identifier: prepared.baseName,
29662
+ displayName: testDoc.title || prepared.baseName,
29663
+ docType: "test",
29664
+ inputsUsed: prepared.inputsUsed,
29665
+ envVarsUsed: prepared.envVarsUsed
29666
+ };
29667
+ }
29668
+ } catch {
29620
29669
  }
29621
- } catch {
29622
29670
  }
29671
+ return await executeTest(prepared, options, preLogs);
29623
29672
  }
29624
- return executeTest(prepared, options, preLogs);
29625
- }
29626
- if (docType === "suite") {
29627
- let bundle = options.suiteBundle;
29628
- if (!bundle) {
29629
- const tree = await buildSuiteHierarchyFromSuiteFile({
29630
- suiteFilePath: prepared.filePath,
29631
- suiteRawText: prepared.rawText,
29632
- fileLoader: options.fileLoader,
29633
- projectRoot: options.projectRoot
29634
- });
29635
- bundle = createSuiteBundle({
29636
- rootSuitePath: prepared.filePath,
29637
- hierarchy: tree,
29638
- servers: tree.servers,
29639
- environment: tree.environment,
29640
- export: tree.export
29673
+ if (docType === "suite") {
29674
+ let bundle = options.suiteBundle;
29675
+ if (!bundle) {
29676
+ const tree = await buildSuiteHierarchyFromSuiteFile({
29677
+ suiteFilePath: prepared.filePath,
29678
+ suiteRawText: prepared.rawText,
29679
+ fileLoader: options.fileLoader,
29680
+ projectRoot: options.projectRoot
29681
+ });
29682
+ bundle = createSuiteBundle({
29683
+ rootSuitePath: prepared.filePath,
29684
+ hierarchy: tree,
29685
+ servers: tree.servers,
29686
+ environment: tree.environment,
29687
+ export: tree.export
29688
+ });
29689
+ }
29690
+ return await executeSuiteBundle({
29691
+ bundle,
29692
+ options: { ...options, suiteBundle: bundle },
29693
+ preLogs,
29694
+ runFile
29641
29695
  });
29642
29696
  }
29643
- return executeSuiteBundle({
29644
- bundle,
29645
- options: { ...options, suiteBundle: bundle },
29646
- preLogs,
29647
- runFile
29648
- });
29649
- }
29650
- if (docType === "loadtest") {
29651
- return executeLoadTest(prepared, options, preLogs, runFile);
29652
- }
29653
- if (options.__mmtEnvValueRun) {
29654
- return {
29655
- js: "",
29656
- result: { success: true, durationMs: 0, errors: [], outputs: {} },
29657
- identifier: prepared.baseName,
29658
- displayName: prepared.baseName,
29659
- docType,
29660
- inputsUsed: prepared.inputsUsed,
29661
- envVarsUsed: prepared.envVarsUsed
29662
- };
29697
+ if (docType === "loadtest") {
29698
+ return await executeLoadTest(prepared, options, preLogs, runFile);
29699
+ }
29700
+ if (options.__mmtEnvValueRun) {
29701
+ return {
29702
+ js: "",
29703
+ result: { success: true, durationMs: 0, errors: [], outputs: {} },
29704
+ identifier: prepared.baseName,
29705
+ displayName: prepared.baseName,
29706
+ docType,
29707
+ inputsUsed: prepared.inputsUsed,
29708
+ envVarsUsed: prepared.envVarsUsed
29709
+ };
29710
+ }
29711
+ throw new Error("Run is currently supported for test or api documents only.");
29712
+ } finally {
29713
+ if (trackStore) {
29714
+ unregisterActiveEnvStore(options.envStore);
29715
+ }
29663
29716
  }
29664
- throw new Error("Run is currently supported for test or api documents only.");
29665
29717
  }
29666
29718
  function outputKeysFromYaml(rawText) {
29667
29719
  try {
@@ -31810,6 +31862,18 @@ function createHttpAgentWithTracking(hostname) {
31810
31862
  httpAgentPool.set(agentKey, agent);
31811
31863
  return agent;
31812
31864
  }
31865
+ function recordConnectionActivity(socket) {
31866
+ const connId = socketConnectionIds.get(socket);
31867
+ if (connId) {
31868
+ connectionTracker.activity(connId, { incrementRequests: true });
31869
+ }
31870
+ }
31871
+ function markConnectionIdle(socket) {
31872
+ const connId = socketConnectionIds.get(socket);
31873
+ if (connId) {
31874
+ connectionTracker.idle(connId);
31875
+ }
31876
+ }
31813
31877
 
31814
31878
  // ../core/src/network/httpErrors.ts
31815
31879
  function toNetworkError(err, config, duration, warning) {
@@ -32525,7 +32589,16 @@ async function sendHttpRequest(req, config) {
32525
32589
  return axios2.request({ ...baseRequestConfig, httpsAgent, httpAgent });
32526
32590
  };
32527
32591
  const start = Date.now();
32592
+ const noteKeepAliveActivity = (source) => {
32593
+ const socket = source?.request?.socket || source?.socket;
32594
+ if (!socket) {
32595
+ return;
32596
+ }
32597
+ recordConnectionActivity(socket);
32598
+ markConnectionIdle(socket);
32599
+ };
32528
32600
  const toSuccess = (response, warning) => {
32601
+ noteKeepAliveActivity(response);
32529
32602
  const duration = Date.now() - start;
32530
32603
  const headers = normalizeAxiosHeaders(response.headers);
32531
32604
  return {
@@ -32542,6 +32615,8 @@ async function sendHttpRequest(req, config) {
32542
32615
  const duration = Date.now() - start;
32543
32616
  if (err?.response && Number(err.response.status) >= 400) {
32544
32617
  dropKeepAliveSocket(err);
32618
+ } else if (err?.response) {
32619
+ noteKeepAliveActivity(err.response);
32545
32620
  }
32546
32621
  if (err?.response) {
32547
32622
  const headers = normalizeAxiosHeaders(err.response.headers);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mmt-mcp",
3
- "version": "1.46.5",
3
+ "version": "1.47.0-pre",
4
4
  "description": "Multimeter MCP server for Cursor, Copilot, and Claude. Scaffold, validate, format, and run YAML .mmt API tests. Do not invent .mmt syntax.",
5
5
  "mcpName": "io.github.mshobeyri/multimeter",
6
6
  "type": "module",