terminal-commands 0.1.2 → 0.2.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.
package/dist/stdio.js CHANGED
@@ -410,11 +410,11 @@ var require_codegen = __commonJS({
410
410
  const rhs = this.rhs === void 0 ? "" : ` = ${this.rhs}`;
411
411
  return `${varKind} ${this.name}${rhs};` + _n;
412
412
  }
413
- optimizeNames(names, constants2) {
413
+ optimizeNames(names, constants) {
414
414
  if (!names[this.name.str])
415
415
  return;
416
416
  if (this.rhs)
417
- this.rhs = optimizeExpr(this.rhs, names, constants2);
417
+ this.rhs = optimizeExpr(this.rhs, names, constants);
418
418
  return this;
419
419
  }
420
420
  get names() {
@@ -431,10 +431,10 @@ var require_codegen = __commonJS({
431
431
  render({ _n }) {
432
432
  return `${this.lhs} = ${this.rhs};` + _n;
433
433
  }
434
- optimizeNames(names, constants2) {
434
+ optimizeNames(names, constants) {
435
435
  if (this.lhs instanceof code_1.Name && !names[this.lhs.str] && !this.sideEffects)
436
436
  return;
437
- this.rhs = optimizeExpr(this.rhs, names, constants2);
437
+ this.rhs = optimizeExpr(this.rhs, names, constants);
438
438
  return this;
439
439
  }
440
440
  get names() {
@@ -495,8 +495,8 @@ var require_codegen = __commonJS({
495
495
  optimizeNodes() {
496
496
  return `${this.code}` ? this : void 0;
497
497
  }
498
- optimizeNames(names, constants2) {
499
- this.code = optimizeExpr(this.code, names, constants2);
498
+ optimizeNames(names, constants) {
499
+ this.code = optimizeExpr(this.code, names, constants);
500
500
  return this;
501
501
  }
502
502
  get names() {
@@ -525,12 +525,12 @@ var require_codegen = __commonJS({
525
525
  }
526
526
  return nodes.length > 0 ? this : void 0;
527
527
  }
528
- optimizeNames(names, constants2) {
528
+ optimizeNames(names, constants) {
529
529
  const { nodes } = this;
530
530
  let i = nodes.length;
531
531
  while (i--) {
532
532
  const n = nodes[i];
533
- if (n.optimizeNames(names, constants2))
533
+ if (n.optimizeNames(names, constants))
534
534
  continue;
535
535
  subtractNames(names, n.names);
536
536
  nodes.splice(i, 1);
@@ -583,12 +583,12 @@ var require_codegen = __commonJS({
583
583
  return void 0;
584
584
  return this;
585
585
  }
586
- optimizeNames(names, constants2) {
586
+ optimizeNames(names, constants) {
587
587
  var _a3;
588
- this.else = (_a3 = this.else) === null || _a3 === void 0 ? void 0 : _a3.optimizeNames(names, constants2);
589
- if (!(super.optimizeNames(names, constants2) || this.else))
588
+ this.else = (_a3 = this.else) === null || _a3 === void 0 ? void 0 : _a3.optimizeNames(names, constants);
589
+ if (!(super.optimizeNames(names, constants) || this.else))
590
590
  return;
591
- this.condition = optimizeExpr(this.condition, names, constants2);
591
+ this.condition = optimizeExpr(this.condition, names, constants);
592
592
  return this;
593
593
  }
594
594
  get names() {
@@ -611,10 +611,10 @@ var require_codegen = __commonJS({
611
611
  render(opts) {
612
612
  return `for(${this.iteration})` + super.render(opts);
613
613
  }
614
- optimizeNames(names, constants2) {
615
- if (!super.optimizeNames(names, constants2))
614
+ optimizeNames(names, constants) {
615
+ if (!super.optimizeNames(names, constants))
616
616
  return;
617
- this.iteration = optimizeExpr(this.iteration, names, constants2);
617
+ this.iteration = optimizeExpr(this.iteration, names, constants);
618
618
  return this;
619
619
  }
620
620
  get names() {
@@ -650,10 +650,10 @@ var require_codegen = __commonJS({
650
650
  render(opts) {
651
651
  return `for(${this.varKind} ${this.name} ${this.loop} ${this.iterable})` + super.render(opts);
652
652
  }
653
- optimizeNames(names, constants2) {
654
- if (!super.optimizeNames(names, constants2))
653
+ optimizeNames(names, constants) {
654
+ if (!super.optimizeNames(names, constants))
655
655
  return;
656
- this.iterable = optimizeExpr(this.iterable, names, constants2);
656
+ this.iterable = optimizeExpr(this.iterable, names, constants);
657
657
  return this;
658
658
  }
659
659
  get names() {
@@ -695,11 +695,11 @@ var require_codegen = __commonJS({
695
695
  (_b = this.finally) === null || _b === void 0 ? void 0 : _b.optimizeNodes();
696
696
  return this;
697
697
  }
698
- optimizeNames(names, constants2) {
698
+ optimizeNames(names, constants) {
699
699
  var _a3, _b;
700
- super.optimizeNames(names, constants2);
701
- (_a3 = this.catch) === null || _a3 === void 0 ? void 0 : _a3.optimizeNames(names, constants2);
702
- (_b = this.finally) === null || _b === void 0 ? void 0 : _b.optimizeNames(names, constants2);
700
+ super.optimizeNames(names, constants);
701
+ (_a3 = this.catch) === null || _a3 === void 0 ? void 0 : _a3.optimizeNames(names, constants);
702
+ (_b = this.finally) === null || _b === void 0 ? void 0 : _b.optimizeNames(names, constants);
703
703
  return this;
704
704
  }
705
705
  get names() {
@@ -1000,7 +1000,7 @@ var require_codegen = __commonJS({
1000
1000
  function addExprNames(names, from) {
1001
1001
  return from instanceof code_1._CodeOrName ? addNames(names, from.names) : names;
1002
1002
  }
1003
- function optimizeExpr(expr, names, constants2) {
1003
+ function optimizeExpr(expr, names, constants) {
1004
1004
  if (expr instanceof code_1.Name)
1005
1005
  return replaceName(expr);
1006
1006
  if (!canOptimize(expr))
@@ -1015,14 +1015,14 @@ var require_codegen = __commonJS({
1015
1015
  return items;
1016
1016
  }, []));
1017
1017
  function replaceName(n) {
1018
- const c = constants2[n.str];
1018
+ const c = constants[n.str];
1019
1019
  if (c === void 0 || names[n.str] !== 1)
1020
1020
  return n;
1021
1021
  delete names[n.str];
1022
1022
  return c;
1023
1023
  }
1024
1024
  function canOptimize(e) {
1025
- return e instanceof code_1._Code && e._items.some((c) => c instanceof code_1.Name && names[c.str] === 1 && constants2[c.str] !== void 0);
1025
+ return e instanceof code_1._Code && e._items.some((c) => c instanceof code_1.Name && names[c.str] === 1 && constants[c.str] !== void 0);
1026
1026
  }
1027
1027
  }
1028
1028
  function subtractNames(names, from) {
@@ -3262,8 +3262,8 @@ var require_utils = __commonJS({
3262
3262
  }
3263
3263
  return ind;
3264
3264
  }
3265
- function removeDotSegments(path2) {
3266
- let input2 = path2;
3265
+ function removeDotSegments(path4) {
3266
+ let input2 = path4;
3267
3267
  const output2 = [];
3268
3268
  let nextSlash = -1;
3269
3269
  let len = 0;
@@ -3672,8 +3672,8 @@ var require_schemes = __commonJS({
3672
3672
  }
3673
3673
  if (wsComponent.resourceName) {
3674
3674
  const queryIndex = wsComponent.resourceName.indexOf("?");
3675
- const path2 = queryIndex === -1 ? wsComponent.resourceName : wsComponent.resourceName.slice(0, queryIndex);
3676
- wsComponent.path = path2 && path2 !== "/" ? path2 : void 0;
3675
+ const path4 = queryIndex === -1 ? wsComponent.resourceName : wsComponent.resourceName.slice(0, queryIndex);
3676
+ wsComponent.path = path4 && path4 !== "/" ? path4 : void 0;
3677
3677
  wsComponent.query = queryIndex === -1 ? void 0 : wsComponent.resourceName.slice(queryIndex + 1);
3678
3678
  wsComponent.resourceName = void 0;
3679
3679
  }
@@ -4148,13 +4148,14 @@ var require_fast_uri = __commonJS({
4148
4148
  if (!malformedIPLiteral) {
4149
4149
  malformedHost = canonicalizeHost(parsed, options, schemeHandler, isIP);
4150
4150
  }
4151
- if (!schemeHandler || schemeHandler && !schemeHandler.skipNormalize) {
4152
- if (uri.indexOf("%") !== -1) {
4153
- if (parsed.host !== void 0 && !malformedIPLiteral) {
4154
- const host = isIP ? parsed.host : normalizePercentEncoding(parsed.host, true);
4155
- parsed.host = reescapeHostDelimiters(host, isIP);
4156
- }
4151
+ if (uri.indexOf("%") !== -1 && parsed.host !== void 0 && !malformedIPLiteral) {
4152
+ let host = isIP ? parsed.host : normalizePercentEncoding(parsed.host, true);
4153
+ if (!isIP) {
4154
+ host = normalizePercentEncoding(host.toLowerCase());
4157
4155
  }
4156
+ parsed.host = reescapeHostDelimiters(host, isIP);
4157
+ }
4158
+ if (!schemeHandler || schemeHandler && !schemeHandler.skipNormalize) {
4158
4159
  if (parsed.path) {
4159
4160
  parsed.path = normalizePathEncoding(parsed.path);
4160
4161
  }
@@ -8017,10 +8018,10 @@ function mergeDefs(...defs) {
8017
8018
  function cloneDef(schema) {
8018
8019
  return mergeDefs(schema._zod.def);
8019
8020
  }
8020
- function getElementAtPath(obj, path2) {
8021
- if (!path2)
8021
+ function getElementAtPath(obj, path4) {
8022
+ if (!path4)
8022
8023
  return obj;
8023
- return path2.reduce((acc, key) => acc?.[key], obj);
8024
+ return path4.reduce((acc, key) => acc?.[key], obj);
8024
8025
  }
8025
8026
  function promiseAllObject(promisesObj) {
8026
8027
  const keys = Object.keys(promisesObj);
@@ -8360,11 +8361,11 @@ function explicitlyAborted(x, startIndex = 0) {
8360
8361
  }
8361
8362
  return false;
8362
8363
  }
8363
- function prefixIssues(path2, issues) {
8364
+ function prefixIssues(path4, issues) {
8364
8365
  return issues.map((iss) => {
8365
8366
  var _a3;
8366
8367
  (_a3 = iss).path ?? (_a3.path = []);
8367
- iss.path.unshift(path2);
8368
+ iss.path.unshift(path4);
8368
8369
  return iss;
8369
8370
  });
8370
8371
  }
@@ -8814,16 +8815,16 @@ function flattenError(error62, mapper = (issue2) => issue2.message) {
8814
8815
  }
8815
8816
  function formatError(error62, mapper = (issue2) => issue2.message) {
8816
8817
  const fieldErrors = { _errors: [] };
8817
- const processError = (error63, path2 = []) => {
8818
+ const processError = (error63, path4 = []) => {
8818
8819
  for (const issue2 of error63.issues) {
8819
8820
  if (issue2.code === "invalid_union" && issue2.errors.length) {
8820
- issue2.errors.map((issues) => processError({ issues }, [...path2, ...issue2.path]));
8821
+ issue2.errors.map((issues) => processError({ issues }, [...path4, ...issue2.path]));
8821
8822
  } else if (issue2.code === "invalid_key") {
8822
- processError({ issues: issue2.issues }, [...path2, ...issue2.path]);
8823
+ processError({ issues: issue2.issues }, [...path4, ...issue2.path]);
8823
8824
  } else if (issue2.code === "invalid_element") {
8824
- processError({ issues: issue2.issues }, [...path2, ...issue2.path]);
8825
+ processError({ issues: issue2.issues }, [...path4, ...issue2.path]);
8825
8826
  } else {
8826
- const fullpath = [...path2, ...issue2.path];
8827
+ const fullpath = [...path4, ...issue2.path];
8827
8828
  if (fullpath.length === 0) {
8828
8829
  fieldErrors._errors.push(mapper(issue2));
8829
8830
  } else {
@@ -8862,17 +8863,17 @@ function formatError(error62, mapper = (issue2) => issue2.message) {
8862
8863
  }
8863
8864
  function treeifyError(error62, mapper = (issue2) => issue2.message) {
8864
8865
  const result = { errors: [] };
8865
- const processError = (error63, path2 = []) => {
8866
+ const processError = (error63, path4 = []) => {
8866
8867
  var _a3;
8867
8868
  for (const issue2 of error63.issues) {
8868
8869
  if (issue2.code === "invalid_union" && issue2.errors.length) {
8869
- issue2.errors.map((issues) => processError({ issues }, [...path2, ...issue2.path]));
8870
+ issue2.errors.map((issues) => processError({ issues }, [...path4, ...issue2.path]));
8870
8871
  } else if (issue2.code === "invalid_key") {
8871
- processError({ issues: issue2.issues }, [...path2, ...issue2.path]);
8872
+ processError({ issues: issue2.issues }, [...path4, ...issue2.path]);
8872
8873
  } else if (issue2.code === "invalid_element") {
8873
- processError({ issues: issue2.issues }, [...path2, ...issue2.path]);
8874
+ processError({ issues: issue2.issues }, [...path4, ...issue2.path]);
8874
8875
  } else {
8875
- const fullpath = [...path2, ...issue2.path];
8876
+ const fullpath = [...path4, ...issue2.path];
8876
8877
  if (fullpath.length === 0) {
8877
8878
  result.errors.push(mapper(issue2));
8878
8879
  continue;
@@ -8911,8 +8912,8 @@ function treeifyError(error62, mapper = (issue2) => issue2.message) {
8911
8912
  }
8912
8913
  function toDotPath(_path) {
8913
8914
  const segs = [];
8914
- const path2 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
8915
- for (const seg of path2) {
8915
+ const path4 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
8916
+ for (const seg of path4) {
8916
8917
  if (typeof seg === "number")
8917
8918
  segs.push(`[${seg}]`);
8918
8919
  else if (typeof seg === "symbol")
@@ -26014,13 +26015,13 @@ function resolveRef(ref, ctx) {
26014
26015
  if (!ref.startsWith("#")) {
26015
26016
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
26016
26017
  }
26017
- const path2 = ref.slice(1).split("/").filter(Boolean);
26018
- if (path2.length === 0) {
26018
+ const path4 = ref.slice(1).split("/").filter(Boolean);
26019
+ if (path4.length === 0) {
26019
26020
  return ctx.rootSchema;
26020
26021
  }
26021
26022
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
26022
- if (path2[0] === defsKey) {
26023
- const key = path2[1] === void 0 ? void 0 : decodeJSONPointerSegment(path2[1]);
26023
+ if (path4[0] === defsKey) {
26024
+ const key = path4[1] === void 0 ? void 0 : decodeJSONPointerSegment(path4[1]);
26024
26025
  if (!key || !ctx.defs[key]) {
26025
26026
  throw new Error(`Reference not found: ${ref}`);
26026
26027
  }
@@ -28504,9 +28505,6 @@ var StdioServerTransport = class {
28504
28505
  }
28505
28506
  };
28506
28507
 
28507
- // src/server.ts
28508
- import { readdir, writeFile } from "node:fs/promises";
28509
-
28510
28508
  // node_modules/zod/v3/helpers/util.js
28511
28509
  var util;
28512
28510
  (function(util2) {
@@ -28881,8 +28879,8 @@ function getErrorMap2() {
28881
28879
 
28882
28880
  // node_modules/zod/v3/helpers/parseUtil.js
28883
28881
  var makeIssue = (params) => {
28884
- const { data, path: path2, errorMaps, issueData } = params;
28885
- const fullPath = [...path2, ...issueData.path || []];
28882
+ const { data, path: path4, errorMaps, issueData } = params;
28883
+ const fullPath = [...path4, ...issueData.path || []];
28886
28884
  const fullIssue = {
28887
28885
  ...issueData,
28888
28886
  path: fullPath
@@ -28997,11 +28995,11 @@ var errorUtil;
28997
28995
 
28998
28996
  // node_modules/zod/v3/types.js
28999
28997
  var ParseInputLazyPath = class {
29000
- constructor(parent, value, path2, key) {
28998
+ constructor(parent, value, path4, key) {
29001
28999
  this._cachedPath = [];
29002
29000
  this.parent = parent;
29003
29001
  this.data = value;
29004
- this._path = path2;
29002
+ this._path = path4;
29005
29003
  this._key = key;
29006
29004
  }
29007
29005
  get path() {
@@ -32552,11 +32550,11 @@ function normalizeObjectSchema(schema) {
32552
32550
  }
32553
32551
  return void 0;
32554
32552
  }
32555
- function getDotPath(path2) {
32556
- if (path2.length === 0) {
32553
+ function getDotPath(path4) {
32554
+ if (path4.length === 0) {
32557
32555
  return "object root";
32558
32556
  }
32559
- return path2.reduce((acc, seg, index) => {
32557
+ return path4.reduce((acc, seg, index) => {
32560
32558
  if (index === 0) {
32561
32559
  return String(seg);
32562
32560
  }
@@ -34000,6 +33998,9 @@ var Protocol = class {
34000
33998
  this.setRequestHandler(GetTaskPayloadRequestSchema, async (request, extra) => {
34001
33999
  const handleTaskResult = async () => {
34002
34000
  const taskId = request.params.taskId;
34001
+ if (!await this._taskStore.getTask(taskId, extra.sessionId)) {
34002
+ throw new McpError(ErrorCode.InvalidParams, `Task not found: ${taskId}`);
34003
+ }
34003
34004
  if (this._taskMessageQueue) {
34004
34005
  let queuedMessage;
34005
34006
  while (queuedMessage = await this._taskMessageQueue.dequeue(taskId, extra.sessionId)) {
@@ -34030,12 +34031,12 @@ var Protocol = class {
34030
34031
  throw new McpError(ErrorCode.InvalidParams, `Task not found: ${taskId}`);
34031
34032
  }
34032
34033
  if (!isTerminal(task.status)) {
34033
- await this._waitForTaskUpdate(taskId, extra.signal);
34034
+ await this._waitForTaskUpdate(taskId, extra.signal, extra.sessionId);
34034
34035
  return await handleTaskResult();
34035
34036
  }
34036
34037
  if (isTerminal(task.status)) {
34037
34038
  const result = await this._taskStore.getTaskResult(taskId, extra.sessionId);
34038
- this._clearTaskQueue(taskId);
34039
+ this._clearTaskQueue(taskId, extra.sessionId);
34039
34040
  return {
34040
34041
  ...result,
34041
34042
  _meta: {
@@ -34072,7 +34073,7 @@ var Protocol = class {
34072
34073
  throw new McpError(ErrorCode.InvalidParams, `Cannot cancel task in terminal status: ${task.status}`);
34073
34074
  }
34074
34075
  await this._taskStore.updateTaskStatus(request.params.taskId, "cancelled", "Client cancelled task execution.", extra.sessionId);
34075
- this._clearTaskQueue(request.params.taskId);
34076
+ this._clearTaskQueue(request.params.taskId, extra.sessionId);
34076
34077
  const cancelledTask = await this._taskStore.getTask(request.params.taskId, extra.sessionId);
34077
34078
  if (!cancelledTask) {
34078
34079
  throw new McpError(ErrorCode.InvalidParams, `Task not found after cancellation: ${request.params.taskId}`);
@@ -34200,6 +34201,19 @@ var Protocol = class {
34200
34201
  const handler = this._requestHandlers.get(request.method) ?? this.fallbackRequestHandler;
34201
34202
  const capturedTransport = this._transport;
34202
34203
  const relatedTaskId = request.params?._meta?.[RELATED_TASK_META_KEY]?.taskId;
34204
+ const sessionId = capturedTransport?.sessionId;
34205
+ const store = this._taskStore;
34206
+ let relatedTaskFound = true;
34207
+ let relatedTaskLookup;
34208
+ if (relatedTaskId && store && this._taskMessageQueue && sessionId !== void 0) {
34209
+ relatedTaskFound = false;
34210
+ relatedTaskLookup = (async () => {
34211
+ if (!await store.getTask(relatedTaskId, sessionId)) {
34212
+ throw new McpError(ErrorCode.InvalidParams, `Task not found: ${relatedTaskId}`);
34213
+ }
34214
+ relatedTaskFound = true;
34215
+ })();
34216
+ }
34203
34217
  if (handler === void 0) {
34204
34218
  const errorResponse = {
34205
34219
  jsonrpc: "2.0",
@@ -34209,7 +34223,10 @@ var Protocol = class {
34209
34223
  message: "Method not found"
34210
34224
  }
34211
34225
  };
34212
- if (relatedTaskId && this._taskMessageQueue) {
34226
+ if (relatedTaskId && relatedTaskLookup) {
34227
+ const queuedError = { type: "error", message: errorResponse, timestamp: Date.now() };
34228
+ relatedTaskLookup.then(() => this._enqueueTaskMessage(relatedTaskId, queuedError, sessionId), () => capturedTransport?.send(errorResponse)).catch((error62) => this._onerror(new Error(`Failed to send an error response: ${error62}`)));
34229
+ } else if (relatedTaskId && this._taskMessageQueue) {
34213
34230
  this._enqueueTaskMessage(relatedTaskId, {
34214
34231
  type: "error",
34215
34232
  message: errorResponse,
@@ -34260,7 +34277,10 @@ var Protocol = class {
34260
34277
  closeSSEStream: extra?.closeSSEStream,
34261
34278
  closeStandaloneSSEStream: extra?.closeStandaloneSSEStream
34262
34279
  };
34263
- Promise.resolve().then(() => {
34280
+ (relatedTaskLookup ?? Promise.resolve()).then(() => {
34281
+ if (relatedTaskLookup && abortController.signal.aborted) {
34282
+ throw new McpError(ErrorCode.ConnectionClosed, "Request was cancelled");
34283
+ }
34264
34284
  if (taskCreationParams) {
34265
34285
  this.assertTaskHandlerCapability(request.method);
34266
34286
  }
@@ -34295,7 +34315,7 @@ var Protocol = class {
34295
34315
  ...error62["data"] !== void 0 && { data: error62["data"] }
34296
34316
  }
34297
34317
  };
34298
- if (relatedTaskId && this._taskMessageQueue) {
34318
+ if (relatedTaskId && this._taskMessageQueue && relatedTaskFound) {
34299
34319
  await this._enqueueTaskMessage(relatedTaskId, {
34300
34320
  type: "error",
34301
34321
  message: errorResponse,
@@ -34775,7 +34795,7 @@ var Protocol = class {
34775
34795
  throw new Error("Cannot enqueue task message: taskStore and taskMessageQueue are not configured");
34776
34796
  }
34777
34797
  const maxQueueSize = this._options?.maxTaskQueueSize;
34778
- await this._taskMessageQueue.enqueue(taskId, message, sessionId, maxQueueSize);
34798
+ await this._taskMessageQueue.enqueue(taskId, message, sessionId ?? this._transport?.sessionId, maxQueueSize);
34779
34799
  }
34780
34800
  /**
34781
34801
  * Clears the message queue for a task and rejects any pending request resolvers.
@@ -34804,12 +34824,13 @@ var Protocol = class {
34804
34824
  * Uses polling to check for updates at the task's configured poll interval.
34805
34825
  * @param taskId The task ID to wait for
34806
34826
  * @param signal Abort signal to cancel the wait
34827
+ * @param sessionId Session of the request that waits, passed to the task store
34807
34828
  * @returns Promise that resolves when an update occurs or rejects if aborted
34808
34829
  */
34809
- async _waitForTaskUpdate(taskId, signal) {
34830
+ async _waitForTaskUpdate(taskId, signal, sessionId) {
34810
34831
  let interval = this._options?.defaultTaskPollInterval ?? 1e3;
34811
34832
  try {
34812
- const task = await this._taskStore?.getTask(taskId);
34833
+ const task = await this._taskStore?.getTask(taskId, sessionId);
34813
34834
  if (task?.pollInterval) {
34814
34835
  interval = task.pollInterval;
34815
34836
  }
@@ -35688,6 +35709,42 @@ var ExperimentalMcpServerTasks = class {
35688
35709
  };
35689
35710
 
35690
35711
  // node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js
35712
+ function toolInputElementCount(value, max) {
35713
+ let count = 0;
35714
+ const stack = [value];
35715
+ while (stack.length > 0) {
35716
+ const node2 = stack.pop();
35717
+ if (node2 === null || typeof node2 !== "object")
35718
+ continue;
35719
+ if (Array.isArray(node2)) {
35720
+ for (const child of node2) {
35721
+ if (++count > max)
35722
+ return count;
35723
+ if (child !== null && typeof child === "object")
35724
+ stack.push(child);
35725
+ }
35726
+ } else {
35727
+ for (const key in node2) {
35728
+ if (!Object.prototype.hasOwnProperty.call(node2, key))
35729
+ continue;
35730
+ if (++count > max)
35731
+ return count;
35732
+ const child = node2[key];
35733
+ if (child !== null && typeof child === "object")
35734
+ stack.push(child);
35735
+ }
35736
+ }
35737
+ }
35738
+ return count;
35739
+ }
35740
+ function resolveMaxToolInputElements(value) {
35741
+ if (value === void 0 || value === Infinity)
35742
+ return void 0;
35743
+ if (typeof value !== "number" || Number.isNaN(value) || value < 1) {
35744
+ throw new RangeError(`maxToolInputElements must be a number of at least 1, or Infinity, got ${String(value)}`);
35745
+ }
35746
+ return value;
35747
+ }
35691
35748
  var McpServer = class {
35692
35749
  constructor(serverInfo, options) {
35693
35750
  this._registeredResources = {};
@@ -35699,6 +35756,7 @@ var McpServer = class {
35699
35756
  this._resourceHandlersInitialized = false;
35700
35757
  this._promptHandlersInitialized = false;
35701
35758
  this.server = new Server(serverInfo, options);
35759
+ this._maxToolInputElements = resolveMaxToolInputElements(options?.maxToolInputElements);
35702
35760
  }
35703
35761
  /**
35704
35762
  * Access experimental features.
@@ -35829,12 +35887,15 @@ var McpServer = class {
35829
35887
  * Validates tool input arguments against the tool's input schema.
35830
35888
  */
35831
35889
  async validateToolInput(tool, args, toolName) {
35890
+ if (this._maxToolInputElements !== void 0 && toolInputElementCount(args, this._maxToolInputElements) > this._maxToolInputElements) {
35891
+ throw new McpError(ErrorCode.InvalidParams, `Invalid arguments for tool ${toolName}: arguments contain more than the maximum of ${this._maxToolInputElements} elements`);
35892
+ }
35832
35893
  if (!tool.inputSchema) {
35833
35894
  return void 0;
35834
35895
  }
35835
35896
  const inputObj = normalizeObjectSchema(tool.inputSchema);
35836
35897
  const schemaToParse = inputObj ?? tool.inputSchema;
35837
- const parseResult = await safeParseAsync3(schemaToParse, args);
35898
+ const parseResult = await safeParseAsync3(schemaToParse, args ?? {});
35838
35899
  if (!parseResult.success) {
35839
35900
  const error62 = "error" in parseResult ? parseResult.error : "Unknown error";
35840
35901
  const errorMessage = getParseErrorMessage(error62);
@@ -36072,7 +36133,7 @@ var McpServer = class {
36072
36133
  }
36073
36134
  if (prompt.argsSchema) {
36074
36135
  const argsObj = normalizeObjectSchema(prompt.argsSchema);
36075
- const parseResult = await safeParseAsync3(argsObj, request.params.arguments);
36136
+ const parseResult = await safeParseAsync3(argsObj, request.params.arguments ?? {});
36076
36137
  if (!parseResult.success) {
36077
36138
  const error62 = "error" in parseResult ? parseResult.error : "Unknown error";
36078
36139
  const errorMessage = getParseErrorMessage(error62);
@@ -36479,14 +36540,28 @@ var EMPTY_COMPLETION_RESULT = {
36479
36540
  }
36480
36541
  };
36481
36542
 
36482
- // src/runner.ts
36483
- import { execFile } from "node:child_process";
36484
- import { promisify } from "node:util";
36543
+ // src/process-manager.ts
36544
+ import { randomUUID } from "node:crypto";
36545
+ import {
36546
+ closeSync,
36547
+ fsyncSync,
36548
+ mkdirSync,
36549
+ openSync,
36550
+ readFileSync,
36551
+ renameSync,
36552
+ rmSync,
36553
+ writeFileSync
36554
+ } from "node:fs";
36555
+ import path3 from "node:path";
36556
+ import { spawn as spawn2 } from "node:child_process";
36557
+
36558
+ // src/rooted-filesystem.ts
36559
+ import { spawn } from "node:child_process";
36560
+ import { realpathSync, statSync } from "node:fs";
36561
+ import path2 from "node:path";
36562
+ import { fileURLToPath } from "node:url";
36485
36563
 
36486
36564
  // src/security.ts
36487
- import { constants } from "node:fs";
36488
- import { access, lstat, realpath } from "node:fs/promises";
36489
- import os from "node:os";
36490
36565
  import path from "node:path";
36491
36566
  var DEFAULT_ENVIRONMENT_KEYS = [
36492
36567
  "LANG",
@@ -36519,34 +36594,7 @@ function configuredRoots(raw = process.env.MACHINE_TERMINAL_ROOTS) {
36519
36594
  }
36520
36595
  function isWithinRoot(candidate, root) {
36521
36596
  const relative = path.relative(root, candidate);
36522
- return relative === "" || !relative.startsWith(`..${path.sep}`) && relative !== "..";
36523
- }
36524
- async function resolveReadablePath(requestedPath, roots2, cwd = roots2[0] ?? os.homedir()) {
36525
- const resolvedRoots = await Promise.all(roots2.map((root) => realpath(root)));
36526
- const candidate = await realpath(path.resolve(cwd, requestedPath));
36527
- if (!resolvedRoots.some((root) => isWithinRoot(candidate, root))) {
36528
- throw new Error("Path is outside MACHINE_TERMINAL_ROOTS.");
36529
- }
36530
- await access(candidate, constants.R_OK);
36531
- return candidate;
36532
- }
36533
- async function resolveWritablePath(requestedPath, roots2, cwd = roots2[0] ?? os.homedir()) {
36534
- const absolute = path.resolve(cwd, requestedPath);
36535
- const resolvedParent = await realpath(path.dirname(absolute));
36536
- const resolvedRoots = await Promise.all(roots2.map((root) => realpath(root)));
36537
- const candidate = path.join(resolvedParent, path.basename(absolute));
36538
- if (!resolvedRoots.some((root) => isWithinRoot(candidate, root))) {
36539
- throw new Error("Path is outside MACHINE_TERMINAL_ROOTS.");
36540
- }
36541
- try {
36542
- const stats = await lstat(candidate);
36543
- if (stats.isSymbolicLink()) {
36544
- throw new Error("Writing through symbolic links is not allowed.");
36545
- }
36546
- } catch (error62) {
36547
- if (error62.code !== "ENOENT") throw error62;
36548
- }
36549
- return candidate;
36597
+ return relative === "" || !path.isAbsolute(relative) && !relative.startsWith(`..${path.sep}`) && relative !== "..";
36550
36598
  }
36551
36599
  function safeEnvironment(source = process.env) {
36552
36600
  return Object.fromEntries(
@@ -36571,68 +36619,668 @@ function assertProgramAllowed(program) {
36571
36619
  }
36572
36620
  }
36573
36621
 
36574
- // src/runner.ts
36575
- var execFileAsync = promisify(execFile);
36576
- async function runProgram(options) {
36577
- assertProgramAllowed(options.program);
36578
- try {
36579
- const { stdout, stderr } = await execFileAsync(
36580
- options.program,
36581
- options.args,
36582
- {
36583
- cwd: options.cwd,
36584
- env: safeEnvironment(),
36585
- encoding: "utf8",
36586
- maxBuffer: options.maxOutputChars,
36587
- timeout: options.timeoutMs,
36588
- windowsHide: true
36622
+ // src/rooted-filesystem.ts
36623
+ var filesystemHelperPath = fileURLToPath(
36624
+ new URL(
36625
+ `../dist/native/${process.platform}-${process.arch}/fs-helper${process.platform === "win32" ? ".exe" : ""}`,
36626
+ import.meta.url
36627
+ )
36628
+ );
36629
+ var RootedFilesystem = class {
36630
+ roots;
36631
+ #specs;
36632
+ #aliases;
36633
+ #child;
36634
+ #pending = /* @__PURE__ */ new Map();
36635
+ #nextID = 0;
36636
+ #buffer = "";
36637
+ #failure;
36638
+ #initialized = false;
36639
+ ready;
36640
+ constructor(roots2) {
36641
+ if (!roots2.length || roots2.length > 128)
36642
+ throw new Error("ROOTED_FILESYSTEM_ROOT_LIMIT");
36643
+ this.#aliases = roots2.map((root) => path2.resolve(root));
36644
+ this.#specs = roots2.map((root) => {
36645
+ const name = realpathSync(root);
36646
+ const info = statSync(name, { bigint: true });
36647
+ if (!info.isDirectory())
36648
+ throw new Error("ROOTED_FILESYSTEM_EXPECTED_DIRECTORY");
36649
+ return { path: name, dev: info.dev.toString(), ino: info.ino.toString() };
36650
+ });
36651
+ this.roots = this.#specs.map((root) => root.path);
36652
+ this.#child = spawn(filesystemHelperPath, [], {
36653
+ stdio: ["pipe", "pipe", "pipe"],
36654
+ windowsHide: true,
36655
+ env: safeEnvironment()
36656
+ });
36657
+ this.#child.stderr.resume();
36658
+ this.#child.on(
36659
+ "error",
36660
+ () => this.#fail(new Error("ROOTED_FILESYSTEM_HELPER_UNAVAILABLE"))
36661
+ );
36662
+ this.#child.on(
36663
+ "close",
36664
+ () => this.#fail(new Error("ROOTED_FILESYSTEM_HELPER_CLOSED"))
36665
+ );
36666
+ this.#child.stdin.on(
36667
+ "error",
36668
+ () => this.#fail(new Error("ROOTED_FILESYSTEM_HELPER_CLOSED"))
36669
+ );
36670
+ this.#child.stdout.on(
36671
+ "error",
36672
+ () => this.#fail(new Error("ROOTED_FILESYSTEM_HELPER_CLOSED"))
36673
+ );
36674
+ this.#child.stderr.on(
36675
+ "error",
36676
+ () => this.#fail(new Error("ROOTED_FILESYSTEM_HELPER_CLOSED"))
36677
+ );
36678
+ this.#child.stdout.setEncoding("utf8");
36679
+ this.#child.stdout.on("data", (data) => {
36680
+ this.#buffer += data;
36681
+ if (Buffer.byteLength(this.#buffer) > 4 * 1024 * 1024) {
36682
+ this.#fail(new Error("ROOTED_FILESYSTEM_REPLY_LIMIT"));
36683
+ return;
36684
+ }
36685
+ let newline;
36686
+ while ((newline = this.#buffer.indexOf("\n")) !== -1) {
36687
+ const line = this.#buffer.slice(0, newline);
36688
+ this.#buffer = this.#buffer.slice(newline + 1);
36689
+ try {
36690
+ const reply = JSON.parse(line);
36691
+ const waiting = this.#pending.get(reply.id);
36692
+ if (!waiting) continue;
36693
+ this.#pending.delete(reply.id);
36694
+ clearTimeout(waiting.timer);
36695
+ if (reply.error) waiting.reject(new Error(reply.error));
36696
+ else waiting.resolve(reply);
36697
+ } catch {
36698
+ this.#fail(new Error("ROOTED_FILESYSTEM_INVALID_REPLY"));
36699
+ return;
36700
+ }
36589
36701
  }
36702
+ this.#referenceWork();
36703
+ });
36704
+ this.ready = this.#request("init", { roots: this.#specs }).then(() => {
36705
+ this.#initialized = true;
36706
+ });
36707
+ void this.ready.catch(() => void 0);
36708
+ }
36709
+ #referenceWork() {
36710
+ const method = this.#pending.size ? "ref" : "unref";
36711
+ this.#child[method]();
36712
+ for (const stream of [
36713
+ this.#child.stdin,
36714
+ this.#child.stdout,
36715
+ this.#child.stderr
36716
+ ])
36717
+ stream[method]();
36718
+ }
36719
+ #fail(error62) {
36720
+ this.#failure ??= error62;
36721
+ for (const waiting of this.#pending.values()) {
36722
+ clearTimeout(waiting.timer);
36723
+ waiting.reject(this.#failure);
36724
+ }
36725
+ this.#pending.clear();
36726
+ this.#child.kill();
36727
+ this.#referenceWork();
36728
+ }
36729
+ #request(operation, values) {
36730
+ if (this.#failure) return Promise.reject(this.#failure);
36731
+ if (this.#pending.size >= 16)
36732
+ return Promise.reject(new Error("ROOTED_FILESYSTEM_PENDING_LIMIT"));
36733
+ const id = ++this.#nextID;
36734
+ const message = JSON.stringify({ id, operation, ...values }) + "\n";
36735
+ if (Buffer.byteLength(message) >= 4 * 1024 * 1024)
36736
+ return Promise.reject(new Error("ROOTED_FILESYSTEM_INPUT_LIMIT"));
36737
+ return new Promise((resolve, reject) => {
36738
+ const timer = setTimeout(
36739
+ () => this.#fail(new Error("ROOTED_FILESYSTEM_TIMEOUT")),
36740
+ 1e4
36741
+ );
36742
+ this.#pending.set(id, { resolve, reject, timer });
36743
+ this.#referenceWork();
36744
+ this.#child.stdin.write(message);
36745
+ });
36746
+ }
36747
+ resolve(requestedPath) {
36748
+ const candidate = path2.resolve(this.#aliases[0], requestedPath);
36749
+ const index = this.roots.findIndex(
36750
+ (root, i) => isWithinRoot(candidate, root) || isWithinRoot(candidate, this.#aliases[i])
36590
36751
  );
36591
- return { exitCode: 0, signal: null, stdout, stderr, timedOut: false };
36592
- } catch (error62) {
36593
- const failure2 = error62;
36752
+ if (index === -1)
36753
+ throw new Error("Path is outside MACHINE_TERMINAL_ROOTS.");
36754
+ const base = isWithinRoot(candidate, this.roots[index]) ? this.roots[index] : this.#aliases[index];
36755
+ const relative = path2.relative(base, candidate) || ".";
36756
+ if (relative.length > 4096) throw new Error("ROOTED_FILESYSTEM_PATH_LIMIT");
36594
36757
  return {
36595
- exitCode: typeof failure2.code === "number" ? failure2.code : null,
36596
- signal: failure2.signal ?? null,
36597
- stdout: failure2.stdout ?? "",
36598
- stderr: failure2.stderr ?? failure2.message,
36599
- timedOut: failure2.killed === true && failure2.signal === "SIGTERM"
36758
+ root: index,
36759
+ path: relative,
36760
+ displayPath: path2.join(this.roots[index], relative)
36600
36761
  };
36601
36762
  }
36602
- }
36763
+ async read(target, maxCharacters) {
36764
+ await this.ready;
36765
+ const reply = await this.#request("read", { ...target, maxCharacters });
36766
+ const decoded = new TextDecoder().decode(
36767
+ Buffer.from(reply.bytes ?? "", "base64"),
36768
+ { stream: reply.hasUnread }
36769
+ );
36770
+ return {
36771
+ contents: decoded.slice(0, maxCharacters),
36772
+ truncated: reply.hasUnread || decoded.length > maxCharacters
36773
+ };
36774
+ }
36775
+ async write(target, contents, overwrite) {
36776
+ await this.ready;
36777
+ return (await this.#request("write", { ...target, contents, overwrite })).bytesWritten;
36778
+ }
36779
+ async list(target) {
36780
+ await this.ready;
36781
+ const reply = await this.#request("list", { ...target });
36782
+ return { entries: reply.entries ?? [], truncated: reply.truncated };
36783
+ }
36784
+ async execution(requestedPath, program, args) {
36785
+ await this.ready;
36786
+ const target = this.resolve(requestedPath);
36787
+ return {
36788
+ roots: [this.#specs[target.root]],
36789
+ path: target.path,
36790
+ program,
36791
+ args
36792
+ };
36793
+ }
36794
+ async close() {
36795
+ if (this.#child.exitCode !== null || this.#child.signalCode !== null)
36796
+ return;
36797
+ const exited = new Promise(
36798
+ (resolve) => this.#child.once("close", () => resolve())
36799
+ );
36800
+ this.#fail(new Error("ROOTED_FILESYSTEM_CLOSED"));
36801
+ await exited;
36802
+ }
36803
+ get available() {
36804
+ return this.#initialized && !this.#failure;
36805
+ }
36806
+ };
36603
36807
 
36604
- // src/file-reader.ts
36605
- import { open as open2 } from "node:fs/promises";
36606
- async function readBoundedTextFile(filename, maxCharacters) {
36607
- const handle = await open2(filename, "r");
36608
- try {
36609
- const stats = await handle.stat();
36610
- const buffer = Buffer.allocUnsafe(maxCharacters * 4 + 4);
36611
- const { bytesRead } = await handle.read(buffer, 0, buffer.length, 0);
36612
- const hasUnreadBytes = bytesRead < stats.size;
36613
- const decoded = new TextDecoder().decode(buffer.subarray(0, bytesRead), {
36614
- stream: hasUnreadBytes
36808
+ // src/process-manager.ts
36809
+ var MAX_EVENT_CHARACTERS = 4096;
36810
+ var MAX_RETAINED_EVENTS = 128;
36811
+ var MAX_RETAINED_EVENT_CHARACTERS = 64e3;
36812
+ var LOCAL_SESSION_RETENTION_MS = 60 * 6e4;
36813
+ var MAX_TASK_TOMBSTONES = 2e4;
36814
+ var TASK_RECEIPT_RETENTION_MS = 30 * 24 * 60 * 6e4;
36815
+ var TERMINATION_GRACE_MS = 1500;
36816
+ function appendBounded(current, value, limit) {
36817
+ if (current.length >= limit) return current;
36818
+ return `${current}${value.toString("utf8")}`.slice(0, limit);
36819
+ }
36820
+ function snapshot(session) {
36821
+ return {
36822
+ sessionId: session.sessionId,
36823
+ ...session.taskId ? { taskId: session.taskId } : {},
36824
+ program: session.program,
36825
+ args: session.args,
36826
+ cwd: session.cwd,
36827
+ pid: session.child.pid ?? null,
36828
+ running: session.running,
36829
+ exitCode: session.exitCode,
36830
+ signal: session.signal,
36831
+ stdout: session.stdout,
36832
+ stderr: session.stderr,
36833
+ timedOut: session.timedOut
36834
+ };
36835
+ }
36836
+ var ProcessManager = class {
36837
+ constructor(limits = {
36838
+ maxRunning: 32,
36839
+ maxRetained: 512
36840
+ }, receiptFile = process.env.MACHINE_TERMINAL_TASK_RECEIPTS_FILE) {
36841
+ this.limits = limits;
36842
+ this.receiptFile = receiptFile;
36843
+ if (!Number.isInteger(limits.maxRunning) || limits.maxRunning < 1 || !Number.isInteger(limits.maxRetained) || limits.maxRetained < limits.maxRunning) {
36844
+ throw new Error("INVALID_PROCESS_LIMITS: Invalid local process limits.");
36845
+ }
36846
+ this.#loadReceipts();
36847
+ }
36848
+ limits;
36849
+ receiptFile;
36850
+ #sessions = /* @__PURE__ */ new Map();
36851
+ #taskSessions = /* @__PURE__ */ new Map();
36852
+ #taskReceipts = /* @__PURE__ */ new Map();
36853
+ #loadReceipts() {
36854
+ if (!this.receiptFile) return;
36855
+ let raw;
36856
+ try {
36857
+ raw = readFileSync(this.receiptFile, "utf8");
36858
+ } catch (error62) {
36859
+ if (error62.code === "ENOENT") return;
36860
+ throw error62;
36861
+ }
36862
+ const parsed = JSON.parse(raw);
36863
+ if (parsed.version !== 1 || !Array.isArray(parsed.receipts)) {
36864
+ throw new Error(
36865
+ "INVALID_TASK_RECEIPTS: Refusing to drop existing replay receipts."
36866
+ );
36867
+ }
36868
+ for (const receipt of parsed.receipts) {
36869
+ if (typeof receipt.taskId !== "string" || !Number.isSafeInteger(receipt.createdAt)) {
36870
+ throw new Error("INVALID_TASK_RECEIPTS: Corrupt task-receipt record.");
36871
+ }
36872
+ this.#taskReceipts.set(receipt.taskId, receipt.createdAt);
36873
+ }
36874
+ this.#pruneReceipts();
36875
+ }
36876
+ #persistReceipts() {
36877
+ if (!this.receiptFile) return;
36878
+ mkdirSync(path3.dirname(this.receiptFile), { recursive: true, mode: 448 });
36879
+ const temporary = this.receiptFile + "." + process.pid + "." + randomUUID() + ".tmp";
36880
+ try {
36881
+ writeFileSync(
36882
+ temporary,
36883
+ JSON.stringify({
36884
+ version: 1,
36885
+ receipts: [...this.#taskReceipts].map(([taskId, createdAt]) => ({
36886
+ taskId,
36887
+ createdAt
36888
+ }))
36889
+ }),
36890
+ { mode: 384, flag: "wx", flush: true }
36891
+ );
36892
+ renameSync(temporary, this.receiptFile);
36893
+ if (process.platform !== "win32") {
36894
+ const directory = openSync(path3.dirname(this.receiptFile), "r");
36895
+ try {
36896
+ fsyncSync(directory);
36897
+ } finally {
36898
+ closeSync(directory);
36899
+ }
36900
+ }
36901
+ } finally {
36902
+ rmSync(temporary, { force: true });
36903
+ }
36904
+ }
36905
+ #pruneReceipts() {
36906
+ const cutoff = Date.now() - TASK_RECEIPT_RETENTION_MS;
36907
+ let dirty = false;
36908
+ for (const [taskId, createdAt] of this.#taskReceipts) {
36909
+ if (createdAt < cutoff && !this.#taskSessions.has(taskId)) {
36910
+ this.#taskReceipts.delete(taskId);
36911
+ dirty = true;
36912
+ }
36913
+ }
36914
+ if (dirty) this.#persistReceipts();
36915
+ }
36916
+ #recordTaskReceipt(taskId) {
36917
+ this.#taskReceipts.set(taskId, Date.now());
36918
+ try {
36919
+ this.#persistReceipts();
36920
+ } catch (error62) {
36921
+ this.#taskReceipts.delete(taskId);
36922
+ throw error62;
36923
+ }
36924
+ }
36925
+ #signalProcessTree(session, signal) {
36926
+ const pid = session.child.pid;
36927
+ if (!pid || pid < 1) return;
36928
+ if (process.platform === "win32") {
36929
+ const killer = spawn2("taskkill.exe", ["/PID", String(pid), "/T", "/F"], {
36930
+ windowsHide: true,
36931
+ stdio: "ignore"
36932
+ });
36933
+ killer.on("error", () => session.child.kill("SIGKILL"));
36934
+ killer.on("close", (code) => {
36935
+ if (code !== 0 && session.running) session.child.kill("SIGKILL");
36936
+ });
36937
+ return;
36938
+ }
36939
+ try {
36940
+ process.kill(-pid, signal);
36941
+ return;
36942
+ } catch (error62) {
36943
+ if (error62.code === "ESRCH") return;
36944
+ }
36945
+ session.child.kill(signal);
36946
+ }
36947
+ #unixProcessGroupExists(session) {
36948
+ if (process.platform === "win32") return false;
36949
+ const pid = session.child.pid;
36950
+ if (!pid || pid < 1) return false;
36951
+ try {
36952
+ process.kill(-pid, 0);
36953
+ return true;
36954
+ } catch (error62) {
36955
+ return error62.code !== "ESRCH";
36956
+ }
36957
+ }
36958
+ #finishSession(session, exitCode, signal) {
36959
+ if (session.finishedRecorded) return;
36960
+ session.finishedRecorded = true;
36961
+ session.running = false;
36962
+ session.finishedAt = Date.now();
36963
+ session.exitCode = exitCode;
36964
+ session.signal = signal;
36965
+ if (session.timeout) clearTimeout(session.timeout);
36966
+ if (session.forceKillTimer) {
36967
+ clearTimeout(session.forceKillTimer);
36968
+ session.forceKillTimer = void 0;
36969
+ }
36970
+ this.#record(session, "finished", {
36971
+ exitCode,
36972
+ signal,
36973
+ timedOut: session.timedOut
36974
+ });
36975
+ }
36976
+ #requestTermination(session) {
36977
+ if (!session.running) return;
36978
+ session.terminationRequested = true;
36979
+ this.#signalProcessTree(session, "SIGTERM");
36980
+ if (!session.forceKillTimer) {
36981
+ session.forceKillTimer = setTimeout(() => {
36982
+ session.forceKillTimer = void 0;
36983
+ if (process.platform !== "win32" || session.running) {
36984
+ this.#signalProcessTree(session, "SIGKILL");
36985
+ }
36986
+ const pending = session.pendingTerminationClose;
36987
+ if (pending) {
36988
+ session.pendingTerminationClose = void 0;
36989
+ this.#finishSession(session, pending.exitCode, pending.signal);
36990
+ }
36991
+ }, TERMINATION_GRACE_MS);
36992
+ }
36993
+ }
36994
+ #pruneFinished() {
36995
+ const cutoff = Date.now() - LOCAL_SESSION_RETENTION_MS;
36996
+ for (const [sessionId, session] of this.#sessions) {
36997
+ if (session.finishedAt !== void 0 && session.finishedAt < cutoff && session.watchers.size === 0) {
36998
+ this.#sessions.delete(sessionId);
36999
+ if (session.taskId) this.#taskSessions.delete(session.taskId);
37000
+ }
37001
+ }
37002
+ }
37003
+ #record(session, kind, details = {}) {
37004
+ const event = {
37005
+ sessionId: session.sessionId,
37006
+ ...session.taskId ? { taskId: session.taskId } : {},
37007
+ sequence: ++session.nextSequence,
37008
+ kind,
37009
+ ...details
37010
+ };
37011
+ session.events.push(event);
37012
+ session.retainedEventCharacters += event.data?.length ?? 0;
37013
+ while (session.events.length > MAX_RETAINED_EVENTS || session.retainedEventCharacters > MAX_RETAINED_EVENT_CHARACTERS) {
37014
+ const removed = session.events.shift();
37015
+ session.retainedEventCharacters -= removed.data?.length ?? 0;
37016
+ }
37017
+ for (const wake of session.watchers) wake();
37018
+ }
37019
+ #output(session, stream, chunk) {
37020
+ const before = session[stream].length;
37021
+ const next = appendBounded(
37022
+ session[stream],
37023
+ chunk,
37024
+ session.maxOutputCharacters
37025
+ );
37026
+ session[stream] = next;
37027
+ const appended = next.slice(before);
37028
+ for (let i = 0; i < appended.length; i += MAX_EVENT_CHARACTERS) {
37029
+ this.#record(session, stream, {
37030
+ offset: before + i,
37031
+ data: appended.slice(i, i + MAX_EVENT_CHARACTERS)
37032
+ });
37033
+ }
37034
+ }
37035
+ async watch(sessionId, afterSequence, timeoutMs = 15e3, maxEvents = 32) {
37036
+ this.#pruneFinished();
37037
+ const session = this.#sessions.get(sessionId);
37038
+ if (!session)
37039
+ throw new Error("The requested process session was not found.");
37040
+ if (!Number.isSafeInteger(afterSequence) || afterSequence < 0) {
37041
+ throw new Error("afterSequence must be a non-negative integer.");
37042
+ }
37043
+ if (!Number.isInteger(timeoutMs) || timeoutMs < 100 || timeoutMs > 2e4) {
37044
+ throw new Error("timeoutMs must be between 100 and 20000.");
37045
+ }
37046
+ if (!Number.isInteger(maxEvents) || maxEvents < 1 || maxEvents > 32) {
37047
+ throw new Error("maxEvents must be between 1 and 32.");
37048
+ }
37049
+ const collect = () => {
37050
+ const first = session.events[0]?.sequence ?? session.nextSequence + 1;
37051
+ const missedEvents = afterSequence + 1 < first;
37052
+ const events = session.events.filter((event) => event.sequence > afterSequence).slice(0, maxEvents);
37053
+ return {
37054
+ sessionId,
37055
+ events,
37056
+ nextSequence: events.at(-1)?.sequence ?? Math.max(afterSequence, session.nextSequence),
37057
+ missedEvents,
37058
+ finished: !session.running
37059
+ };
37060
+ };
37061
+ const initial = collect();
37062
+ if (initial.events.length || initial.finished || initial.missedEvents) {
37063
+ return initial;
37064
+ }
37065
+ return new Promise((resolve) => {
37066
+ let timer;
37067
+ const finish = () => {
37068
+ clearTimeout(timer);
37069
+ session.watchers.delete(finish);
37070
+ resolve(collect());
37071
+ };
37072
+ session.watchers.add(finish);
37073
+ timer = setTimeout(finish, timeoutMs);
37074
+ if (session.nextSequence > afterSequence || !session.running) finish();
37075
+ });
37076
+ }
37077
+ start(options) {
37078
+ this.#pruneReceipts();
37079
+ if (options.taskId) {
37080
+ const existingSession = this.#taskSessions.get(options.taskId);
37081
+ if (existingSession) {
37082
+ const existing = this.#sessions.get(existingSession);
37083
+ if (!existing) throw new Error("PROCESS_TASK_SESSION_LOST");
37084
+ if (existing.program !== options.program || existing.cwd !== options.cwd || existing.args.join("\0") !== options.args.join("\0")) {
37085
+ throw new Error(
37086
+ "PROCESS_TASK_CONFLICT: Task ID already started with different arguments."
37087
+ );
37088
+ }
37089
+ const result2 = snapshot(existing);
37090
+ return {
37091
+ ...result2,
37092
+ nextStdoutOffset: result2.stdout.length,
37093
+ nextStderrOffset: result2.stderr.length
37094
+ };
37095
+ }
37096
+ if (this.#taskReceipts.has(options.taskId)) {
37097
+ throw new Error(
37098
+ "PROCESS_TASK_SESSION_LOST: Task already ran; will not execute again."
37099
+ );
37100
+ }
37101
+ }
37102
+ this.#pruneFinished();
37103
+ if (this.#sessions.size >= this.limits.maxRetained) {
37104
+ throw new Error("PROCESS_LIMIT_REACHED: Local process history is full.");
37105
+ }
37106
+ const running = [...this.#sessions.values()].filter(
37107
+ (session2) => session2.running
37108
+ ).length;
37109
+ if (running >= this.limits.maxRunning) {
37110
+ throw new Error(
37111
+ "PROCESS_LIMIT_REACHED: Too many concurrent local processes."
37112
+ );
37113
+ }
37114
+ if (options.taskId && this.#taskReceipts.size >= MAX_TASK_TOMBSTONES) {
37115
+ throw new Error(
37116
+ "PROCESS_LIMIT_REACHED: Local task receipt capacity reached."
37117
+ );
37118
+ }
37119
+ assertProgramAllowed(options.program);
37120
+ if (options.rootedExecution && (options.rootedExecution.program !== options.program || options.rootedExecution.args.join("\0") !== options.args.join("\0")))
37121
+ throw new Error("ROOTED_EXECUTION_MISMATCH");
37122
+ const rootedPayload = options.rootedExecution ? JSON.stringify(options.rootedExecution) : void 0;
37123
+ if (rootedPayload && Buffer.byteLength(rootedPayload) >= 4 * 1024 * 1024)
37124
+ throw new Error("ROOTED_EXECUTION_INPUT_LIMIT");
37125
+ if (options.taskId) this.#recordTaskReceipt(options.taskId);
37126
+ const child = spawn2(
37127
+ options.rootedExecution ? filesystemHelperPath : options.program,
37128
+ options.rootedExecution ? ["--exec"] : options.args,
37129
+ {
37130
+ cwd: options.rootedExecution ? void 0 : options.cwd,
37131
+ env: safeEnvironment(),
37132
+ stdio: ["pipe", "pipe", "pipe"],
37133
+ windowsHide: true,
37134
+ // A separate Unix process group lets us terminate descendants too.
37135
+ detached: process.platform !== "win32"
37136
+ }
37137
+ );
37138
+ child.stdin.on("error", () => void 0);
37139
+ child.stdin.end(rootedPayload);
37140
+ const session = {
37141
+ sessionId: randomUUID(),
37142
+ ...options.taskId ? { taskId: options.taskId } : {},
37143
+ program: options.program,
37144
+ args: [...options.args],
37145
+ cwd: options.cwd,
37146
+ child,
37147
+ maxOutputCharacters: options.maxOutputCharacters,
37148
+ stdout: "",
37149
+ stderr: "",
37150
+ running: true,
37151
+ exitCode: null,
37152
+ signal: null,
37153
+ timedOut: false,
37154
+ nextSequence: 0,
37155
+ events: [],
37156
+ retainedEventCharacters: 0,
37157
+ watchers: /* @__PURE__ */ new Set()
37158
+ };
37159
+ this.#sessions.set(session.sessionId, session);
37160
+ if (session.taskId)
37161
+ this.#taskSessions.set(session.taskId, session.sessionId);
37162
+ this.#record(session, "started");
37163
+ child.stdout.on("data", (chunk) => {
37164
+ this.#output(session, "stdout", chunk);
37165
+ });
37166
+ child.stderr.on("data", (chunk) => {
37167
+ this.#output(session, "stderr", chunk);
36615
37168
  });
37169
+ child.once("error", (error62) => {
37170
+ session.stderr = appendBounded(
37171
+ session.stderr,
37172
+ error62.message,
37173
+ session.maxOutputCharacters
37174
+ );
37175
+ session.running = false;
37176
+ session.exitCode = null;
37177
+ session.signal = null;
37178
+ if (session.timeout) clearTimeout(session.timeout);
37179
+ });
37180
+ child.once("close", (exitCode, signal) => {
37181
+ if (session.terminationRequested && session.forceKillTimer && this.#unixProcessGroupExists(session)) {
37182
+ session.pendingTerminationClose = { exitCode, signal };
37183
+ if (session.timeout) clearTimeout(session.timeout);
37184
+ return;
37185
+ }
37186
+ this.#finishSession(session, exitCode, signal);
37187
+ });
37188
+ session.timeout = setTimeout(() => {
37189
+ if (!session.running) return;
37190
+ session.timedOut = true;
37191
+ this.#requestTermination(session);
37192
+ }, options.timeoutMs);
37193
+ const result = snapshot(session);
36616
37194
  return {
36617
- contents: decoded.slice(0, maxCharacters),
36618
- truncated: hasUnreadBytes || decoded.length > maxCharacters
37195
+ ...result,
37196
+ nextStdoutOffset: result.stdout.length,
37197
+ nextStderrOffset: result.stderr.length
36619
37198
  };
36620
- } finally {
36621
- await handle.close();
36622
37199
  }
36623
- }
37200
+ read(sessionId, stdoutOffset, stderrOffset, maxOutputCharacters) {
37201
+ this.#pruneFinished();
37202
+ const session = this.#sessions.get(sessionId);
37203
+ if (!session)
37204
+ throw new Error("The requested process session was not found.");
37205
+ const safeStdoutOffset = Math.max(
37206
+ 0,
37207
+ Math.min(stdoutOffset, session.stdout.length)
37208
+ );
37209
+ const safeStderrOffset = Math.max(
37210
+ 0,
37211
+ Math.min(stderrOffset, session.stderr.length)
37212
+ );
37213
+ const stdout = session.stdout.slice(
37214
+ safeStdoutOffset,
37215
+ safeStdoutOffset + maxOutputCharacters
37216
+ );
37217
+ const stderr = session.stderr.slice(
37218
+ safeStderrOffset,
37219
+ safeStderrOffset + maxOutputCharacters
37220
+ );
37221
+ return {
37222
+ ...snapshot(session),
37223
+ stdout,
37224
+ stderr,
37225
+ nextStdoutOffset: safeStdoutOffset + stdout.length,
37226
+ nextStderrOffset: safeStderrOffset + stderr.length
37227
+ };
37228
+ }
37229
+ terminate(sessionId) {
37230
+ this.#pruneFinished();
37231
+ const session = this.#sessions.get(sessionId);
37232
+ if (!session)
37233
+ throw new Error("The requested process session was not found.");
37234
+ this.#requestTermination(session);
37235
+ return snapshot(session);
37236
+ }
37237
+ list() {
37238
+ this.#pruneFinished();
37239
+ return [...this.#sessions.values()].map(snapshot);
37240
+ }
37241
+ close() {
37242
+ for (const session of this.#sessions.values()) {
37243
+ if (session.timeout) clearTimeout(session.timeout);
37244
+ this.#requestTermination(session);
37245
+ }
37246
+ for (const session of this.#sessions.values()) {
37247
+ for (const wake of session.watchers) wake();
37248
+ }
37249
+ this.#sessions.clear();
37250
+ this.#taskSessions.clear();
37251
+ }
37252
+ };
36624
37253
 
36625
37254
  // src/server.ts
36626
37255
  var roots = configuredRoots();
37256
+ var processManager = new ProcessManager();
37257
+ var sharedFilesystem;
37258
+ function defaultFilesystem() {
37259
+ return sharedFilesystem ??= new RootedFilesystem(roots);
37260
+ }
37261
+ async function initializeFilesystemBoundary() {
37262
+ await defaultFilesystem().ready;
37263
+ }
37264
+ async function closeFilesystemBoundary() {
37265
+ await sharedFilesystem?.close();
37266
+ }
36627
37267
  function textResult(value) {
36628
37268
  return {
36629
37269
  content: [{ type: "text", text: JSON.stringify(value, null, 2) }],
36630
37270
  structuredContent: value
36631
37271
  };
36632
37272
  }
36633
- function createServer() {
37273
+ function createServer(options = {}) {
37274
+ const filesystem = options.filesystem ?? defaultFilesystem();
37275
+ const requireAuthorizedAgent = () => {
37276
+ if (!options.allowDestructive) {
37277
+ throw new Error(
37278
+ "LOCAL_APPROVAL_REQUIRED: Connect through the approved Terminal Commands agent."
37279
+ );
37280
+ }
37281
+ };
36634
37282
  const server2 = new McpServer(
36635
- { name: "terminal-commands", version: "0.1.0" },
37283
+ { name: "terminal-commands", version: "0.2.0" },
36636
37284
  {
36637
37285
  instructions: "This server controls the user's machine. Prefer dedicated file tools over commands. Every command and write can modify or expose local data and must receive user approval. Never request secrets or bypass configured roots and safety controls."
36638
37286
  }
@@ -36685,15 +37333,12 @@ function createServer() {
36685
37333
  }
36686
37334
  },
36687
37335
  async ({ path: requestedPath }) => {
36688
- const directory = await resolveReadablePath(requestedPath, roots);
36689
- const entries = await readdir(directory, { withFileTypes: true });
37336
+ const directory = filesystem.resolve(requestedPath);
37337
+ const { entries, truncated } = await filesystem.list(directory);
36690
37338
  return textResult({
36691
- path: directory,
36692
- entries: entries.slice(0, 1e3).map((entry) => ({
36693
- name: entry.name,
36694
- type: entry.isDirectory() ? "directory" : entry.isFile() ? "file" : "other"
36695
- })),
36696
- truncated: entries.length > 1e3
37339
+ path: directory.displayPath,
37340
+ entries,
37341
+ truncated
36697
37342
  });
36698
37343
  }
36699
37344
  );
@@ -36718,13 +37363,13 @@ function createServer() {
36718
37363
  }
36719
37364
  },
36720
37365
  async ({ path: requestedPath, maxCharacters }) => {
36721
- const filename = await resolveReadablePath(requestedPath, roots);
36722
- const { contents, truncated } = await readBoundedTextFile(
37366
+ const filename = filesystem.resolve(requestedPath);
37367
+ const { contents, truncated } = await filesystem.read(
36723
37368
  filename,
36724
37369
  maxCharacters
36725
37370
  );
36726
37371
  return textResult({
36727
- path: filename,
37372
+ path: filename.displayPath,
36728
37373
  contents,
36729
37374
  truncated
36730
37375
  });
@@ -36751,23 +37396,26 @@ function createServer() {
36751
37396
  }
36752
37397
  },
36753
37398
  async ({ path: requestedPath, contents, overwrite }) => {
36754
- const filename = await resolveWritablePath(requestedPath, roots);
36755
- await writeFile(filename, contents, {
36756
- encoding: "utf8",
36757
- flag: overwrite ? "w" : "wx"
36758
- });
37399
+ requireAuthorizedAgent();
37400
+ const filename = filesystem.resolve(requestedPath);
37401
+ const bytesWritten = await filesystem.write(
37402
+ filename,
37403
+ contents,
37404
+ overwrite
37405
+ );
36759
37406
  return textResult({
36760
- path: filename,
36761
- bytesWritten: Buffer.byteLength(contents)
37407
+ path: filename.displayPath,
37408
+ bytesWritten
36762
37409
  });
36763
37410
  }
36764
37411
  );
36765
37412
  server2.registerTool(
36766
- "run_program",
37413
+ "start_process",
36767
37414
  {
36768
- title: "Run a local program",
36769
- description: "Run one executable without a shell. Shells and privilege-elevation programs are blocked unless explicitly enabled by local configuration.",
37415
+ title: "Start a process",
37416
+ description: "Start one approved executable without a shell on this machine and return a session ID for reading its output.",
36770
37417
  inputSchema: {
37418
+ taskId: external_exports.string().uuid().optional(),
36771
37419
  program: external_exports.string().min(1),
36772
37420
  args: external_exports.array(external_exports.string()).max(100).default([]),
36773
37421
  cwd: external_exports.string().min(1).optional(),
@@ -36775,14 +37423,20 @@ function createServer() {
36775
37423
  maxOutputCharacters: external_exports.number().int().min(1e3).max(2e5).default(5e4)
36776
37424
  },
36777
37425
  outputSchema: {
37426
+ sessionId: external_exports.string(),
37427
+ taskId: external_exports.string().uuid().optional(),
36778
37428
  program: external_exports.string(),
36779
37429
  args: external_exports.array(external_exports.string()),
36780
37430
  cwd: external_exports.string(),
37431
+ pid: external_exports.number().int().nullable(),
37432
+ running: external_exports.boolean(),
36781
37433
  exitCode: external_exports.number().int().nullable(),
36782
37434
  signal: external_exports.string().nullable(),
36783
37435
  stdout: external_exports.string(),
36784
37436
  stderr: external_exports.string(),
36785
- timedOut: external_exports.boolean()
37437
+ timedOut: external_exports.boolean(),
37438
+ nextStdoutOffset: external_exports.number().int().nonnegative(),
37439
+ nextStderrOffset: external_exports.number().int().nonnegative()
36786
37440
  },
36787
37441
  annotations: {
36788
37442
  readOnlyHint: false,
@@ -36790,30 +37444,191 @@ function createServer() {
36790
37444
  openWorldHint: true
36791
37445
  }
36792
37446
  },
36793
- async ({ program, args, cwd, timeoutMs, maxOutputCharacters }) => {
36794
- const workingDirectory = await resolveReadablePath(
37447
+ async ({ taskId, program, args, cwd, timeoutMs, maxOutputCharacters }) => {
37448
+ requireAuthorizedAgent();
37449
+ const workingDirectory = filesystem.resolve(cwd ?? roots[0]);
37450
+ const rootedExecution = await filesystem.execution(
36795
37451
  cwd ?? roots[0],
36796
- roots
36797
- );
36798
- const result = await runProgram({
36799
37452
  program,
36800
- args,
36801
- cwd: workingDirectory,
37453
+ args
37454
+ );
37455
+ return textResult(
37456
+ processManager.start({
37457
+ taskId,
37458
+ program,
37459
+ args,
37460
+ cwd: workingDirectory.displayPath,
37461
+ rootedExecution,
37462
+ timeoutMs,
37463
+ maxOutputCharacters
37464
+ })
37465
+ );
37466
+ }
37467
+ );
37468
+ server2.registerTool(
37469
+ "read_process_output",
37470
+ {
37471
+ title: "Read process output",
37472
+ description: "Read new stdout and stderr from a previously started process session.",
37473
+ inputSchema: {
37474
+ sessionId: external_exports.string().uuid(),
37475
+ stdoutOffset: external_exports.number().int().min(0).default(0),
37476
+ stderrOffset: external_exports.number().int().min(0).default(0),
37477
+ maxOutputCharacters: external_exports.number().int().min(1e3).max(2e5).default(5e4)
37478
+ },
37479
+ outputSchema: {
37480
+ sessionId: external_exports.string(),
37481
+ taskId: external_exports.string().uuid().optional(),
37482
+ program: external_exports.string(),
37483
+ args: external_exports.array(external_exports.string()),
37484
+ cwd: external_exports.string(),
37485
+ pid: external_exports.number().int().nullable(),
37486
+ running: external_exports.boolean(),
37487
+ exitCode: external_exports.number().int().nullable(),
37488
+ signal: external_exports.string().nullable(),
37489
+ stdout: external_exports.string(),
37490
+ stderr: external_exports.string(),
37491
+ timedOut: external_exports.boolean(),
37492
+ nextStdoutOffset: external_exports.number().int().nonnegative(),
37493
+ nextStderrOffset: external_exports.number().int().nonnegative()
37494
+ },
37495
+ annotations: {
37496
+ readOnlyHint: true,
37497
+ destructiveHint: false,
37498
+ openWorldHint: false
37499
+ }
37500
+ },
37501
+ async ({ sessionId, stdoutOffset, stderrOffset, maxOutputCharacters }) => textResult(
37502
+ processManager.read(
37503
+ sessionId,
37504
+ stdoutOffset,
37505
+ stderrOffset,
37506
+ maxOutputCharacters
37507
+ )
37508
+ )
37509
+ );
37510
+ server2.registerTool(
37511
+ "watch_process_events",
37512
+ {
37513
+ title: "Watch local process events",
37514
+ description: "Wait for sequenced, bounded process events after a cursor. Used internally by the companion to push progress over WebSocket.",
37515
+ inputSchema: {
37516
+ sessionId: external_exports.string().uuid(),
37517
+ afterSequence: external_exports.number().int().nonnegative().default(0),
37518
+ timeoutMs: external_exports.number().int().min(100).max(2e4).default(1e4),
37519
+ maxEvents: external_exports.number().int().min(1).max(32).default(32)
37520
+ },
37521
+ outputSchema: {
37522
+ sessionId: external_exports.string().uuid(),
37523
+ events: external_exports.array(
37524
+ external_exports.object({
37525
+ sessionId: external_exports.string().uuid(),
37526
+ taskId: external_exports.string().uuid().optional(),
37527
+ sequence: external_exports.number().int().positive(),
37528
+ kind: external_exports.enum(["started", "stdout", "stderr", "finished"]),
37529
+ offset: external_exports.number().int().nonnegative().optional(),
37530
+ data: external_exports.string().max(4096).optional(),
37531
+ exitCode: external_exports.number().int().nullable().optional(),
37532
+ signal: external_exports.string().nullable().optional(),
37533
+ timedOut: external_exports.boolean().optional()
37534
+ })
37535
+ ).max(32),
37536
+ nextSequence: external_exports.number().int().nonnegative(),
37537
+ missedEvents: external_exports.boolean(),
37538
+ finished: external_exports.boolean()
37539
+ },
37540
+ annotations: {
37541
+ readOnlyHint: true,
37542
+ destructiveHint: false,
37543
+ openWorldHint: false
37544
+ }
37545
+ },
37546
+ async ({ sessionId, afterSequence, timeoutMs, maxEvents }) => textResult(
37547
+ await processManager.watch(
37548
+ sessionId,
37549
+ afterSequence,
36802
37550
  timeoutMs,
36803
- maxOutputChars: maxOutputCharacters
36804
- });
36805
- return textResult({ program, args, cwd: workingDirectory, ...result });
37551
+ maxEvents
37552
+ )
37553
+ )
37554
+ );
37555
+ server2.registerTool(
37556
+ "terminate_process",
37557
+ {
37558
+ title: "Terminate a process",
37559
+ description: "Stop a previously started process session on this machine.",
37560
+ inputSchema: { sessionId: external_exports.string().uuid() },
37561
+ outputSchema: {
37562
+ sessionId: external_exports.string(),
37563
+ taskId: external_exports.string().uuid().optional(),
37564
+ program: external_exports.string(),
37565
+ args: external_exports.array(external_exports.string()),
37566
+ cwd: external_exports.string(),
37567
+ pid: external_exports.number().int().nullable(),
37568
+ running: external_exports.boolean(),
37569
+ exitCode: external_exports.number().int().nullable(),
37570
+ signal: external_exports.string().nullable(),
37571
+ stdout: external_exports.string(),
37572
+ stderr: external_exports.string(),
37573
+ timedOut: external_exports.boolean()
37574
+ },
37575
+ annotations: {
37576
+ readOnlyHint: false,
37577
+ destructiveHint: true,
37578
+ openWorldHint: false
37579
+ }
37580
+ },
37581
+ async ({ sessionId }) => {
37582
+ requireAuthorizedAgent();
37583
+ return textResult(processManager.terminate(sessionId));
36806
37584
  }
36807
37585
  );
37586
+ server2.registerTool(
37587
+ "list_processes",
37588
+ {
37589
+ title: "List process sessions",
37590
+ description: "List process sessions started through Terminal Commands.",
37591
+ inputSchema: {},
37592
+ outputSchema: {
37593
+ processes: external_exports.array(
37594
+ external_exports.object({
37595
+ sessionId: external_exports.string(),
37596
+ taskId: external_exports.string().uuid().optional(),
37597
+ program: external_exports.string(),
37598
+ args: external_exports.array(external_exports.string()),
37599
+ cwd: external_exports.string(),
37600
+ pid: external_exports.number().int().nullable(),
37601
+ running: external_exports.boolean(),
37602
+ exitCode: external_exports.number().int().nullable(),
37603
+ signal: external_exports.string().nullable(),
37604
+ stdout: external_exports.string(),
37605
+ stderr: external_exports.string(),
37606
+ timedOut: external_exports.boolean()
37607
+ })
37608
+ )
37609
+ },
37610
+ annotations: {
37611
+ readOnlyHint: true,
37612
+ destructiveHint: false,
37613
+ openWorldHint: false
37614
+ }
37615
+ },
37616
+ async () => textResult({ processes: processManager.list() })
37617
+ );
36808
37618
  return server2;
36809
37619
  }
36810
37620
 
36811
37621
  // src/stdio.ts
36812
- var server = createServer();
37622
+ var server = createServer({
37623
+ allowDestructive: process.env.MACHINE_TERMINAL_TRUST_STDIO === "1"
37624
+ });
36813
37625
  var transport = new StdioServerTransport();
37626
+ await initializeFilesystemBoundary();
36814
37627
  await server.connect(transport);
36815
37628
  async function shutdown() {
37629
+ processManager.close();
36816
37630
  await server.close();
37631
+ await closeFilesystemBoundary();
36817
37632
  process.exit(0);
36818
37633
  }
36819
37634
  process.on("SIGINT", () => void shutdown());