@costgate/momentum-mcp 0.2.0 → 0.2.2

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/README.md CHANGED
@@ -9,7 +9,7 @@ MOMENTUM_TOKEN=mom_agent_xxx \
9
9
  ```
10
10
 
11
11
  整条命令不用自己拼 —— 在 Momentum 的「设置 › Agent」里签发令牌时会直接给出,
12
- 默认用 `@latest`,发新版不用改配置;想固定某一版时把 latest 换成版本号(当前是 0.2.0)。
12
+ 默认用 `@latest`,发新版不用改配置;想固定某一版时把 latest 换成版本号(当前是 0.2.2)。
13
13
 
14
14
  | 环境变量 | 必填 | 说明 |
15
15
  |---|---|---|
@@ -18,4 +18,4 @@ MOMENTUM_TOKEN=mom_agent_xxx \
18
18
  | `MOMENTUM_CF_ACCESS_CLIENT_ID` | 否 | 部署在 Cloudflare Access 后面时才需要 |
19
19
  | `MOMENTUM_CF_ACCESS_CLIENT_SECRET` | 否 | 同上 |
20
20
 
21
- 版本 0.2.0。客户端和服务端版本不一致时,启动日志(stderr)会明确警告。
21
+ 版本 0.2.2。客户端和服务端版本不一致时,启动日志(stderr)会明确警告。
package/momentum-mcp.mjs CHANGED
@@ -7195,7 +7195,7 @@ var require_dist = __commonJS({
7195
7195
  }
7196
7196
  });
7197
7197
 
7198
- // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
7198
+ // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.30.0_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
7199
7199
  import process2 from "node:process";
7200
7200
 
7201
7201
  // ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/core/core.js
@@ -11699,7 +11699,7 @@ function preprocess(fn, schema) {
11699
11699
  // ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v4/classic/external.js
11700
11700
  config(en_default());
11701
11701
 
11702
- // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/types.js
11702
+ // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.30.0_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/types.js
11703
11703
  var LATEST_PROTOCOL_VERSION = "2025-11-25";
11704
11704
  var SUPPORTED_PROTOCOL_VERSIONS = [LATEST_PROTOCOL_VERSION, "2025-06-18", "2025-03-26", "2024-11-05", "2024-10-07"];
11705
11705
  var RELATED_TASK_META_KEY = "io.modelcontextprotocol/related-task";
@@ -13230,7 +13230,7 @@ var UrlElicitationRequiredError = class extends McpError {
13230
13230
  }
13231
13231
  };
13232
13232
 
13233
- // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/stdio.js
13233
+ // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.30.0_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/stdio.js
13234
13234
  var STDIO_DEFAULT_MAX_BUFFER_SIZE = 10 * 1024 * 1024;
13235
13235
  var ReadBuffer = class {
13236
13236
  constructor(options) {
@@ -13267,7 +13267,7 @@ function serializeMessage(message) {
13267
13267
  return JSON.stringify(message) + "\n";
13268
13268
  }
13269
13269
 
13270
- // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
13270
+ // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.30.0_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/server/stdio.js
13271
13271
  var StdioServerTransport = class {
13272
13272
  constructor(_stdin = process2.stdin, _stdout = process2.stdout, options) {
13273
13273
  this._stdin = _stdin;
@@ -15339,7 +15339,7 @@ var allowErrorProps = SuperJSON.allowErrorProps;
15339
15339
 
15340
15340
  // src/version.ts
15341
15341
  var UNKNOWN = "unknown";
15342
- var MCP_VERSION = true ? "0.2.0" : versionFromRepo();
15342
+ var MCP_VERSION = true ? "0.2.2" : versionFromRepo();
15343
15343
  var CLIENT_HEADER = `momentum-mcp/${MCP_VERSION}`;
15344
15344
  function compareVersions(a, b) {
15345
15345
  const parse4 = (v) => {
@@ -19477,7 +19477,7 @@ function object2(shape, params) {
19477
19477
  return new ZodMiniObject(def);
19478
19478
  }
19479
19479
 
19480
- // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/server/zod-compat.js
19480
+ // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.30.0_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/server/zod-compat.js
19481
19481
  function isZ4Schema(s) {
19482
19482
  const schema = s;
19483
19483
  return !!schema._zod;
@@ -19637,7 +19637,7 @@ function getLiteralValue(schema) {
19637
19637
  return void 0;
19638
19638
  }
19639
19639
 
19640
- // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/interfaces.js
19640
+ // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.30.0_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/interfaces.js
19641
19641
  function isTerminal(status) {
19642
19642
  return status === "completed" || status === "failed" || status === "cancelled";
19643
19643
  }
@@ -20926,7 +20926,7 @@ var zodToJsonSchema = (schema, options) => {
20926
20926
  return combined;
20927
20927
  };
20928
20928
 
20929
- // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/server/zod-json-schema-compat.js
20929
+ // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.30.0_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/server/zod-json-schema-compat.js
20930
20930
  function mapMiniTarget(t) {
20931
20931
  if (!t)
20932
20932
  return "draft-7";
@@ -20968,7 +20968,7 @@ function parseWithCompat(schema, data) {
20968
20968
  return result.data;
20969
20969
  }
20970
20970
 
20971
- // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/protocol.js
20971
+ // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.30.0_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/protocol.js
20972
20972
  var DEFAULT_REQUEST_TIMEOUT_MSEC = 6e4;
20973
20973
  var Protocol = class {
20974
20974
  constructor(_options) {
@@ -21009,9 +21009,6 @@ var Protocol = class {
21009
21009
  this.setRequestHandler(GetTaskPayloadRequestSchema, async (request, extra) => {
21010
21010
  const handleTaskResult = async () => {
21011
21011
  const taskId = request.params.taskId;
21012
- if (!await this._taskStore.getTask(taskId, extra.sessionId)) {
21013
- throw new McpError(ErrorCode.InvalidParams, `Task not found: ${taskId}`);
21014
- }
21015
21012
  if (this._taskMessageQueue) {
21016
21013
  let queuedMessage;
21017
21014
  while (queuedMessage = await this._taskMessageQueue.dequeue(taskId, extra.sessionId)) {
@@ -21042,12 +21039,12 @@ var Protocol = class {
21042
21039
  throw new McpError(ErrorCode.InvalidParams, `Task not found: ${taskId}`);
21043
21040
  }
21044
21041
  if (!isTerminal(task.status)) {
21045
- await this._waitForTaskUpdate(taskId, extra.signal, extra.sessionId);
21042
+ await this._waitForTaskUpdate(taskId, extra.signal);
21046
21043
  return await handleTaskResult();
21047
21044
  }
21048
21045
  if (isTerminal(task.status)) {
21049
21046
  const result = await this._taskStore.getTaskResult(taskId, extra.sessionId);
21050
- this._clearTaskQueue(taskId, extra.sessionId);
21047
+ this._clearTaskQueue(taskId);
21051
21048
  return {
21052
21049
  ...result,
21053
21050
  _meta: {
@@ -21084,7 +21081,7 @@ var Protocol = class {
21084
21081
  throw new McpError(ErrorCode.InvalidParams, `Cannot cancel task in terminal status: ${task.status}`);
21085
21082
  }
21086
21083
  await this._taskStore.updateTaskStatus(request.params.taskId, "cancelled", "Client cancelled task execution.", extra.sessionId);
21087
- this._clearTaskQueue(request.params.taskId, extra.sessionId);
21084
+ this._clearTaskQueue(request.params.taskId);
21088
21085
  const cancelledTask = await this._taskStore.getTask(request.params.taskId, extra.sessionId);
21089
21086
  if (!cancelledTask) {
21090
21087
  throw new McpError(ErrorCode.InvalidParams, `Task not found after cancellation: ${request.params.taskId}`);
@@ -21212,19 +21209,6 @@ var Protocol = class {
21212
21209
  const handler = this._requestHandlers.get(request.method) ?? this.fallbackRequestHandler;
21213
21210
  const capturedTransport = this._transport;
21214
21211
  const relatedTaskId = request.params?._meta?.[RELATED_TASK_META_KEY]?.taskId;
21215
- const sessionId = capturedTransport?.sessionId;
21216
- const store = this._taskStore;
21217
- let relatedTaskFound = true;
21218
- let relatedTaskLookup;
21219
- if (relatedTaskId && store && this._taskMessageQueue && sessionId !== void 0) {
21220
- relatedTaskFound = false;
21221
- relatedTaskLookup = (async () => {
21222
- if (!await store.getTask(relatedTaskId, sessionId)) {
21223
- throw new McpError(ErrorCode.InvalidParams, `Task not found: ${relatedTaskId}`);
21224
- }
21225
- relatedTaskFound = true;
21226
- })();
21227
- }
21228
21212
  if (handler === void 0) {
21229
21213
  const errorResponse = {
21230
21214
  jsonrpc: "2.0",
@@ -21234,10 +21218,7 @@ var Protocol = class {
21234
21218
  message: "Method not found"
21235
21219
  }
21236
21220
  };
21237
- if (relatedTaskId && relatedTaskLookup) {
21238
- const queuedError = { type: "error", message: errorResponse, timestamp: Date.now() };
21239
- relatedTaskLookup.then(() => this._enqueueTaskMessage(relatedTaskId, queuedError, sessionId), () => capturedTransport?.send(errorResponse)).catch((error2) => this._onerror(new Error(`Failed to send an error response: ${error2}`)));
21240
- } else if (relatedTaskId && this._taskMessageQueue) {
21221
+ if (relatedTaskId && this._taskMessageQueue) {
21241
21222
  this._enqueueTaskMessage(relatedTaskId, {
21242
21223
  type: "error",
21243
21224
  message: errorResponse,
@@ -21288,10 +21269,7 @@ var Protocol = class {
21288
21269
  closeSSEStream: extra?.closeSSEStream,
21289
21270
  closeStandaloneSSEStream: extra?.closeStandaloneSSEStream
21290
21271
  };
21291
- (relatedTaskLookup ?? Promise.resolve()).then(() => {
21292
- if (relatedTaskLookup && abortController.signal.aborted) {
21293
- throw new McpError(ErrorCode.ConnectionClosed, "Request was cancelled");
21294
- }
21272
+ Promise.resolve().then(() => {
21295
21273
  if (taskCreationParams) {
21296
21274
  this.assertTaskHandlerCapability(request.method);
21297
21275
  }
@@ -21326,7 +21304,7 @@ var Protocol = class {
21326
21304
  ...error2["data"] !== void 0 && { data: error2["data"] }
21327
21305
  }
21328
21306
  };
21329
- if (relatedTaskId && this._taskMessageQueue && relatedTaskFound) {
21307
+ if (relatedTaskId && this._taskMessageQueue) {
21330
21308
  await this._enqueueTaskMessage(relatedTaskId, {
21331
21309
  type: "error",
21332
21310
  message: errorResponse,
@@ -21806,7 +21784,7 @@ var Protocol = class {
21806
21784
  throw new Error("Cannot enqueue task message: taskStore and taskMessageQueue are not configured");
21807
21785
  }
21808
21786
  const maxQueueSize = this._options?.maxTaskQueueSize;
21809
- await this._taskMessageQueue.enqueue(taskId, message, sessionId ?? this._transport?.sessionId, maxQueueSize);
21787
+ await this._taskMessageQueue.enqueue(taskId, message, sessionId, maxQueueSize);
21810
21788
  }
21811
21789
  /**
21812
21790
  * Clears the message queue for a task and rejects any pending request resolvers.
@@ -21835,13 +21813,12 @@ var Protocol = class {
21835
21813
  * Uses polling to check for updates at the task's configured poll interval.
21836
21814
  * @param taskId The task ID to wait for
21837
21815
  * @param signal Abort signal to cancel the wait
21838
- * @param sessionId Session of the request that waits, passed to the task store
21839
21816
  * @returns Promise that resolves when an update occurs or rejects if aborted
21840
21817
  */
21841
- async _waitForTaskUpdate(taskId, signal, sessionId) {
21818
+ async _waitForTaskUpdate(taskId, signal) {
21842
21819
  let interval = this._options?.defaultTaskPollInterval ?? 1e3;
21843
21820
  try {
21844
- const task = await this._taskStore?.getTask(taskId, sessionId);
21821
+ const task = await this._taskStore?.getTask(taskId);
21845
21822
  if (task?.pollInterval) {
21846
21823
  interval = task.pollInterval;
21847
21824
  }
@@ -21945,7 +21922,7 @@ function mergeCapabilities(base, additional) {
21945
21922
  return result;
21946
21923
  }
21947
21924
 
21948
- // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/validation/ajv-provider.js
21925
+ // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.30.0_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/validation/ajv-provider.js
21949
21926
  var import_ajv = __toESM(require_ajv(), 1);
21950
21927
  var import_ajv_formats = __toESM(require_dist(), 1);
21951
21928
  function createDefaultAjvInstance() {
@@ -22013,7 +21990,7 @@ var AjvJsonSchemaValidator = class {
22013
21990
  }
22014
21991
  };
22015
21992
 
22016
- // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/server.js
21993
+ // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.30.0_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/server.js
22017
21994
  var ExperimentalServerTasks = class {
22018
21995
  constructor(_server) {
22019
21996
  this._server = _server;
@@ -22226,7 +22203,7 @@ var ExperimentalServerTasks = class {
22226
22203
  }
22227
22204
  };
22228
22205
 
22229
- // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/helpers.js
22206
+ // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.30.0_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/helpers.js
22230
22207
  function assertToolsCallTaskCapability(requests, method, entityName) {
22231
22208
  if (!requests) {
22232
22209
  throw new Error(`${entityName} does not support task creation (required for ${method})`);
@@ -22261,7 +22238,7 @@ function assertClientRequestTaskCapability(requests, method, entityName) {
22261
22238
  }
22262
22239
  }
22263
22240
 
22264
- // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/server/index.js
22241
+ // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.30.0_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/server/index.js
22265
22242
  var Server = class extends Protocol {
22266
22243
  /**
22267
22244
  * Initializes this server with the given name and version information.
@@ -22632,7 +22609,7 @@ var Server = class extends Protocol {
22632
22609
  }
22633
22610
  };
22634
22611
 
22635
- // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/server/completable.js
22612
+ // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.30.0_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/server/completable.js
22636
22613
  var COMPLETABLE_SYMBOL = Symbol.for("mcp.completable");
22637
22614
  function isCompletable(schema) {
22638
22615
  return !!schema && typeof schema === "object" && COMPLETABLE_SYMBOL in schema;
@@ -22646,7 +22623,229 @@ var McpZodTypeKind;
22646
22623
  McpZodTypeKind2["Completable"] = "McpCompletable";
22647
22624
  })(McpZodTypeKind || (McpZodTypeKind = {}));
22648
22625
 
22649
- // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/toolNameValidation.js
22626
+ // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.30.0_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/uriTemplate.js
22627
+ var MAX_TEMPLATE_LENGTH = 1e6;
22628
+ var MAX_VARIABLE_LENGTH = 1e6;
22629
+ var MAX_TEMPLATE_EXPRESSIONS = 1e4;
22630
+ var MAX_REGEX_LENGTH = 1e6;
22631
+ var UriTemplate = class _UriTemplate {
22632
+ /**
22633
+ * Returns true if the given string contains any URI template expressions.
22634
+ * A template expression is a sequence of characters enclosed in curly braces,
22635
+ * like {foo} or {?bar}.
22636
+ */
22637
+ static isTemplate(str) {
22638
+ return /\{[^}\s]+\}/.test(str);
22639
+ }
22640
+ static validateLength(str, max, context) {
22641
+ if (str.length > max) {
22642
+ throw new Error(`${context} exceeds maximum length of ${max} characters (got ${str.length})`);
22643
+ }
22644
+ }
22645
+ get variableNames() {
22646
+ return this.parts.flatMap((part) => typeof part === "string" ? [] : part.names);
22647
+ }
22648
+ constructor(template) {
22649
+ _UriTemplate.validateLength(template, MAX_TEMPLATE_LENGTH, "Template");
22650
+ this.template = template;
22651
+ this.parts = this.parse(template);
22652
+ }
22653
+ toString() {
22654
+ return this.template;
22655
+ }
22656
+ parse(template) {
22657
+ const parts = [];
22658
+ let currentText = "";
22659
+ let i = 0;
22660
+ let expressionCount = 0;
22661
+ while (i < template.length) {
22662
+ if (template[i] === "{") {
22663
+ if (currentText) {
22664
+ parts.push(currentText);
22665
+ currentText = "";
22666
+ }
22667
+ const end = template.indexOf("}", i);
22668
+ if (end === -1)
22669
+ throw new Error("Unclosed template expression");
22670
+ expressionCount++;
22671
+ if (expressionCount > MAX_TEMPLATE_EXPRESSIONS) {
22672
+ throw new Error(`Template contains too many expressions (max ${MAX_TEMPLATE_EXPRESSIONS})`);
22673
+ }
22674
+ const expr = template.slice(i + 1, end);
22675
+ const operator = this.getOperator(expr);
22676
+ const exploded = expr.includes("*");
22677
+ const names = this.getNames(expr);
22678
+ const name = names[0];
22679
+ for (const name2 of names) {
22680
+ _UriTemplate.validateLength(name2, MAX_VARIABLE_LENGTH, "Variable name");
22681
+ }
22682
+ parts.push({ name, operator, names, exploded });
22683
+ i = end + 1;
22684
+ } else {
22685
+ currentText += template[i];
22686
+ i++;
22687
+ }
22688
+ }
22689
+ if (currentText) {
22690
+ parts.push(currentText);
22691
+ }
22692
+ return parts;
22693
+ }
22694
+ getOperator(expr) {
22695
+ const operators = ["+", "#", ".", "/", "?", "&"];
22696
+ return operators.find((op) => expr.startsWith(op)) || "";
22697
+ }
22698
+ getNames(expr) {
22699
+ const operator = this.getOperator(expr);
22700
+ return expr.slice(operator.length).split(",").map((name) => name.replace("*", "").trim()).filter((name) => name.length > 0);
22701
+ }
22702
+ encodeValue(value, operator) {
22703
+ _UriTemplate.validateLength(value, MAX_VARIABLE_LENGTH, "Variable value");
22704
+ if (operator === "+" || operator === "#") {
22705
+ return encodeURI(value);
22706
+ }
22707
+ return encodeURIComponent(value);
22708
+ }
22709
+ expandPart(part, variables) {
22710
+ if (part.operator === "?" || part.operator === "&") {
22711
+ const pairs = part.names.map((name) => {
22712
+ const value2 = variables[name];
22713
+ if (value2 === void 0)
22714
+ return "";
22715
+ const encoded2 = Array.isArray(value2) ? value2.map((v) => this.encodeValue(v, part.operator)).join(",") : this.encodeValue(value2.toString(), part.operator);
22716
+ return `${name}=${encoded2}`;
22717
+ }).filter((pair) => pair.length > 0);
22718
+ if (pairs.length === 0)
22719
+ return "";
22720
+ const separator = part.operator === "?" ? "?" : "&";
22721
+ return separator + pairs.join("&");
22722
+ }
22723
+ if (part.names.length > 1) {
22724
+ const values2 = part.names.map((name) => variables[name]).filter((v) => v !== void 0);
22725
+ if (values2.length === 0)
22726
+ return "";
22727
+ return values2.map((v) => Array.isArray(v) ? v[0] : v).join(",");
22728
+ }
22729
+ const value = variables[part.name];
22730
+ if (value === void 0)
22731
+ return "";
22732
+ const values = Array.isArray(value) ? value : [value];
22733
+ const encoded = values.map((v) => this.encodeValue(v, part.operator));
22734
+ switch (part.operator) {
22735
+ case "":
22736
+ return encoded.join(",");
22737
+ case "+":
22738
+ return encoded.join(",");
22739
+ case "#":
22740
+ return "#" + encoded.join(",");
22741
+ case ".":
22742
+ return "." + encoded.join(".");
22743
+ case "/":
22744
+ return "/" + encoded.join("/");
22745
+ default:
22746
+ return encoded.join(",");
22747
+ }
22748
+ }
22749
+ expand(variables) {
22750
+ let result = "";
22751
+ let hasQueryParam = false;
22752
+ for (const part of this.parts) {
22753
+ if (typeof part === "string") {
22754
+ result += part;
22755
+ continue;
22756
+ }
22757
+ const expanded = this.expandPart(part, variables);
22758
+ if (!expanded)
22759
+ continue;
22760
+ if ((part.operator === "?" || part.operator === "&") && hasQueryParam) {
22761
+ result += expanded.replace("?", "&");
22762
+ } else {
22763
+ result += expanded;
22764
+ }
22765
+ if (part.operator === "?" || part.operator === "&") {
22766
+ hasQueryParam = true;
22767
+ }
22768
+ }
22769
+ return result;
22770
+ }
22771
+ escapeRegExp(str) {
22772
+ return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
22773
+ }
22774
+ partToRegExp(part) {
22775
+ const patterns = [];
22776
+ for (const name2 of part.names) {
22777
+ _UriTemplate.validateLength(name2, MAX_VARIABLE_LENGTH, "Variable name");
22778
+ }
22779
+ if (part.operator === "?" || part.operator === "&") {
22780
+ for (let i = 0; i < part.names.length; i++) {
22781
+ const name2 = part.names[i];
22782
+ const prefix = i === 0 ? "\\" + part.operator : "&";
22783
+ patterns.push({
22784
+ pattern: prefix + this.escapeRegExp(name2) + "=([^&]+)",
22785
+ name: name2
22786
+ });
22787
+ }
22788
+ return patterns;
22789
+ }
22790
+ let pattern;
22791
+ const name = part.name;
22792
+ switch (part.operator) {
22793
+ case "":
22794
+ pattern = part.exploded ? "([^/,]+(?:,[^/,]+)*)" : "([^/,]+)";
22795
+ break;
22796
+ case "+":
22797
+ case "#":
22798
+ pattern = "(.+)";
22799
+ break;
22800
+ case ".":
22801
+ pattern = "\\.([^/,]+)";
22802
+ break;
22803
+ case "/":
22804
+ pattern = "/" + (part.exploded ? "([^/,]+(?:,[^/,]+)*)" : "([^/,]+)");
22805
+ break;
22806
+ default:
22807
+ pattern = "([^/]+)";
22808
+ }
22809
+ patterns.push({ pattern, name });
22810
+ return patterns;
22811
+ }
22812
+ match(uri) {
22813
+ _UriTemplate.validateLength(uri, MAX_TEMPLATE_LENGTH, "URI");
22814
+ let pattern = "^";
22815
+ const names = [];
22816
+ for (const part of this.parts) {
22817
+ if (typeof part === "string") {
22818
+ pattern += this.escapeRegExp(part);
22819
+ } else {
22820
+ const patterns = this.partToRegExp(part);
22821
+ for (const { pattern: partPattern, name } of patterns) {
22822
+ pattern += partPattern;
22823
+ names.push({ name, exploded: part.exploded });
22824
+ }
22825
+ }
22826
+ }
22827
+ pattern += "$";
22828
+ _UriTemplate.validateLength(pattern, MAX_REGEX_LENGTH, "Generated regex pattern");
22829
+ const regex = new RegExp(pattern);
22830
+ const match = uri.match(regex);
22831
+ if (!match)
22832
+ return null;
22833
+ const result = {};
22834
+ for (let i = 0; i < names.length; i++) {
22835
+ const { name, exploded } = names[i];
22836
+ const value = match[i + 1];
22837
+ const cleanName = name.replace("*", "");
22838
+ if (exploded && value.includes(",")) {
22839
+ result[cleanName] = value.split(",");
22840
+ } else {
22841
+ result[cleanName] = value;
22842
+ }
22843
+ }
22844
+ return result;
22845
+ }
22846
+ };
22847
+
22848
+ // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.30.0_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/toolNameValidation.js
22650
22849
  var TOOL_NAME_REGEX = /^[A-Za-z0-9._-]{1,128}$/;
22651
22850
  function validateToolName(name) {
22652
22851
  const warnings = [];
@@ -22704,7 +22903,7 @@ function validateAndWarnToolName(name) {
22704
22903
  return result.isValid;
22705
22904
  }
22706
22905
 
22707
- // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/mcp-server.js
22906
+ // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.30.0_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/mcp-server.js
22708
22907
  var ExperimentalMcpServerTasks = class {
22709
22908
  constructor(_mcpServer) {
22710
22909
  this._mcpServer = _mcpServer;
@@ -22719,43 +22918,7 @@ var ExperimentalMcpServerTasks = class {
22719
22918
  }
22720
22919
  };
22721
22920
 
22722
- // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js
22723
- function toolInputElementCount(value, max) {
22724
- let count = 0;
22725
- const stack = [value];
22726
- while (stack.length > 0) {
22727
- const node = stack.pop();
22728
- if (node === null || typeof node !== "object")
22729
- continue;
22730
- if (Array.isArray(node)) {
22731
- for (const child of node) {
22732
- if (++count > max)
22733
- return count;
22734
- if (child !== null && typeof child === "object")
22735
- stack.push(child);
22736
- }
22737
- } else {
22738
- for (const key in node) {
22739
- if (!Object.prototype.hasOwnProperty.call(node, key))
22740
- continue;
22741
- if (++count > max)
22742
- return count;
22743
- const child = node[key];
22744
- if (child !== null && typeof child === "object")
22745
- stack.push(child);
22746
- }
22747
- }
22748
- }
22749
- return count;
22750
- }
22751
- function resolveMaxToolInputElements(value) {
22752
- if (value === void 0 || value === Infinity)
22753
- return void 0;
22754
- if (typeof value !== "number" || Number.isNaN(value) || value < 1) {
22755
- throw new RangeError(`maxToolInputElements must be a number of at least 1, or Infinity, got ${String(value)}`);
22756
- }
22757
- return value;
22758
- }
22921
+ // ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.30.0_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/server/mcp.js
22759
22922
  var McpServer = class {
22760
22923
  constructor(serverInfo, options) {
22761
22924
  this._registeredResources = {};
@@ -22767,7 +22930,6 @@ var McpServer = class {
22767
22930
  this._resourceHandlersInitialized = false;
22768
22931
  this._promptHandlersInitialized = false;
22769
22932
  this.server = new Server(serverInfo, options);
22770
- this._maxToolInputElements = resolveMaxToolInputElements(options?.maxToolInputElements);
22771
22933
  }
22772
22934
  /**
22773
22935
  * Access experimental features.
@@ -22898,15 +23060,12 @@ var McpServer = class {
22898
23060
  * Validates tool input arguments against the tool's input schema.
22899
23061
  */
22900
23062
  async validateToolInput(tool, args, toolName) {
22901
- if (this._maxToolInputElements !== void 0 && toolInputElementCount(args, this._maxToolInputElements) > this._maxToolInputElements) {
22902
- throw new McpError(ErrorCode.InvalidParams, `Invalid arguments for tool ${toolName}: arguments contain more than the maximum of ${this._maxToolInputElements} elements`);
22903
- }
22904
23063
  if (!tool.inputSchema) {
22905
23064
  return void 0;
22906
23065
  }
22907
23066
  const inputObj = normalizeObjectSchema(tool.inputSchema);
22908
23067
  const schemaToParse = inputObj ?? tool.inputSchema;
22909
- const parseResult = await safeParseAsync3(schemaToParse, args ?? {});
23068
+ const parseResult = await safeParseAsync3(schemaToParse, args);
22910
23069
  if (!parseResult.success) {
22911
23070
  const error2 = "error" in parseResult ? parseResult.error : "Unknown error";
22912
23071
  const errorMessage = getParseErrorMessage(error2);
@@ -23144,7 +23303,7 @@ var McpServer = class {
23144
23303
  }
23145
23304
  if (prompt.argsSchema) {
23146
23305
  const argsObj = normalizeObjectSchema(prompt.argsSchema);
23147
- const parseResult = await safeParseAsync3(argsObj, request.params.arguments ?? {});
23306
+ const parseResult = await safeParseAsync3(argsObj, request.params.arguments);
23148
23307
  if (!parseResult.success) {
23149
23308
  const error2 = "error" in parseResult ? parseResult.error : "Unknown error";
23150
23309
  const errorMessage = getParseErrorMessage(error2);
@@ -23475,6 +23634,30 @@ var McpServer = class {
23475
23634
  }
23476
23635
  }
23477
23636
  };
23637
+ var ResourceTemplate = class {
23638
+ constructor(uriTemplate, _callbacks) {
23639
+ this._callbacks = _callbacks;
23640
+ this._uriTemplate = typeof uriTemplate === "string" ? new UriTemplate(uriTemplate) : uriTemplate;
23641
+ }
23642
+ /**
23643
+ * Gets the URI template pattern.
23644
+ */
23645
+ get uriTemplate() {
23646
+ return this._uriTemplate;
23647
+ }
23648
+ /**
23649
+ * Gets the list callback, if one was provided.
23650
+ */
23651
+ get listCallback() {
23652
+ return this._callbacks.list;
23653
+ }
23654
+ /**
23655
+ * Gets the callback for completing a specific URI template variable, if one was provided.
23656
+ */
23657
+ completeCallback(variable) {
23658
+ return this._callbacks.complete?.[variable];
23659
+ }
23660
+ };
23478
23661
  var EMPTY_OBJECT_JSON_SCHEMA = {
23479
23662
  type: "object",
23480
23663
  properties: {}
@@ -23551,6 +23734,68 @@ var EMPTY_COMPLETION_RESULT = {
23551
23734
  }
23552
23735
  };
23553
23736
 
23737
+ // src/prompts.ts
23738
+ var TASK_ARG = external_exports.string().min(1).describe("\u4EFB\u52A1\u7F16\u53F7\uFF0C\u5982 MOM-12");
23739
+ var user = (lines) => [
23740
+ { role: "user", content: { type: "text", text: lines.filter((l) => typeof l === "string").join("\n") } }
23741
+ ];
23742
+ function createPrompts(profile = "work") {
23743
+ const canDigest = profile === "full";
23744
+ return [
23745
+ {
23746
+ name: "start_task",
23747
+ title: "\u5F00\u59CB\u505A\u4EFB\u52A1",
23748
+ description: "\u9886\u53D6\u4E00\u4E2A Momentum \u4EFB\u52A1\u5E76\u6309\u56E2\u961F\u6D41\u7A0B\u5F00\u5DE5\uFF1A\u8BFB\u4E0A\u4E0B\u6587\u3001\u8BB2\u6E05\u65B9\u6848\u3001\u52A8\u624B\u3001\u5173\u952E\u8282\u70B9\u7559\u8BC4\u8BBA\u3002",
23749
+ argsSchema: { task: TASK_ARG, note: external_exports.string().optional().describe("\u8FD9\u6B21\u8981\u505A\u4EC0\u4E48\u3001\u6709\u4EC0\u4E48\u989D\u5916\u8981\u6C42") },
23750
+ render: ({ task, note }) => user([
23751
+ `\u8BF7\u5F00\u59CB\u505A Momentum \u4EFB\u52A1 ${task}\u3002`,
23752
+ "",
23753
+ `1. \u76F4\u63A5\u8C03 begin_task("${task}")\uFF1A\u5B83\u4E00\u6B21\u5B8C\u6210\u89E3\u6790\u7F16\u53F7\u3001\u5F00\u8FD0\u884C\u3001\u9886\u53D6\u5E76\u8FD4\u56DE\u7D27\u51D1\u4E0A\u4E0B\u6587\uFF0C\u4E0D\u5FC5\u5148 whoami / get_task\u3002\u5FC3\u8DF3\u81EA\u52A8\u7EED\u7EA6\u3002`,
23754
+ "2. \u8BFB\u4E0A\u4E0B\u6587\uFF1A\u63CF\u8FF0\u3001\u9A8C\u6536\u6807\u51C6\uFF08\u8BB0\u4E0B specVersion\uFF0C\u4EA4\u4ED8\u65F6\u8981\u7528\uFF09\u3001\u4F9D\u8D56\u3001\u5DF2\u6709\u51B3\u5B9A\u3001\u5F85\u7B54\u95EE\u9898\u548C\u6700\u65B0\u4EA4\u4ED8\u3002\u88AB\u4F9D\u8D56\u5361\u4F4F\u3001\u6216\u6709\u963B\u585E\u95EE\u9898\u6CA1\u7B54\u65F6\uFF0C\u5148\u505C\u4E0B\u6765\u544A\u8BC9\u6211\u3002",
23755
+ "3. \u52A8\u624B\u524D\u5148\u7528\u5927\u767D\u8BDD\u8BB2\u6E05\u6253\u7B97\u600E\u4E48\u505A\u3001\u6BCF\u6761\u9A8C\u6536\u6807\u51C6\u6253\u7B97\u600E\u4E48\u9A8C\u8BC1\uFF1B\u65B9\u6848\u503C\u5F97\u7559\u6863\u5C31\u7528 update_task_plan \u5199\u8FDB\u6267\u884C\u7EC6\u5316\u3002",
23756
+ "4. \u5F00\u59CB\u5E72\u6D3B\u3002\u7F3A\u4FE1\u606F\u5148\u95EE\u6211\uFF1B\u6211\u7B54\u4E0D\u4E86\u3001\u8981\u56E2\u961F\u62CD\u677F\u7684\u624D\u7528 ask_question\u3002\u5173\u952E\u8282\u70B9\u7528 comment_on_task \u5199\u4E00\u6761\u77ED\u8FDB\u5C55\uFF08\u5148\u7ED3\u8BBA\u3001\u518D\u8981\u70B9\uFF09\u3002",
23757
+ "5. \u505A\u5B8C\u6309\u300C\u5199\u4EA4\u4ED8\u8BF4\u660E\u300D\uFF08write_delivery\uFF09\u7684\u8981\u6C42\u8C03 finish_task_work \u63D0\u4EA4\u4EA4\u4ED8\u5E76\u79FB\u5230\u8BC4\u5BA1\u3002",
23758
+ note && "",
23759
+ note && `\u8865\u5145\u8981\u6C42\uFF1A${note}`
23760
+ ])
23761
+ },
23762
+ {
23763
+ name: "digest_discussion",
23764
+ title: "\u6574\u7406\u8BA8\u8BBA\u6210\u63D0\u6848",
23765
+ description: "\u628A\u5F53\u524D\u4F1A\u8BDD\u91CC\u7684\u8BA8\u8BBA\u6574\u7406\u6210\u4EFB\u52A1\u7684\u4FEE\u6539\u63D0\u6848\uFF1A\u62CD\u677F\u7684\u51B3\u5B9A\u3001\u5F85\u7B54\u95EE\u9898\u3001\u8BF4\u660E\u4E0E\u9A8C\u6536\u6807\u51C6\u7684\u6539\u52A8\u3002",
23766
+ argsSchema: { task: TASK_ARG, focus: external_exports.string().optional().describe("\u53EA\u6574\u7406\u8BA8\u8BBA\u91CC\u7684\u54EA\u4E00\u90E8\u5206") },
23767
+ render: ({ task, focus }) => user([
23768
+ `\u628A\u6211\u4EEC\u8FD9\u6BB5\u8BA8\u8BBA\u6574\u7406\u6210\u4EFB\u52A1 ${task} \u7684\u4FEE\u6539\u63D0\u6848\u3002`,
23769
+ focus && `\u53EA\u6574\u7406\u8FD9\u90E8\u5206\uFF1A${focus}`,
23770
+ "",
23771
+ `1. \u5148\u8C03 get_task_context("${task}") \u770B\u5F53\u524D\u8BF4\u660E\u3001\u7248\u672C\u53F7 specVersion\u3001\u5DF2\u6709\u51B3\u5B9A\u548C\u5F85\u7B54\u95EE\u9898\uFF0C\u5DF2\u6709\u7684\u4E0D\u8981\u91CD\u590D\u3002`,
23772
+ "2. \u4ECE\u8BA8\u8BBA\u91CC\u63D0\u53D6\u4E09\u7C7B\u4E1C\u897F\uFF1A",
23773
+ " - \u5DF2\u7ECF\u62CD\u677F\u7684\u51B3\u5B9A\uFF1A\u4E00\u6761\u53EA\u8BF4\u4E00\u4EF6\u4E8B\uFF0C\u5199\u6E05\u7406\u7531\uFF1B",
23774
+ " - \u8FD8\u6CA1\u6709\u7B54\u6848\u7684\u95EE\u9898\uFF1A\u6807\u51FA\u54EA\u4E9B\u4F1A\u5361\u4F4F\u8FDB\u5EA6\uFF1B",
23775
+ " - \u63CF\u8FF0\u6216\u9A8C\u6536\u6807\u51C6\u8981\u600E\u4E48\u6539\uFF1A\u9A8C\u6536\u6807\u51C6\u6BCF\u6761\u53EF\u6838\u5BF9\uFF0C\u4FDD\u7559\u539F\u6709\u7684 id\u3002",
23776
+ " \u8BA8\u8BBA\u4E2D\u7684\u8BBE\u60F3\u3001\u53EA\u6709\u6211\u4E00\u65B9\u63D0\u8FC7\u7684\u60F3\u6CD5\u4E0D\u7B97\u51B3\u5B9A\uFF0C\u4E0D\u80FD\u81EA\u884C\u8BA4\u5B9A\u3002",
23777
+ "3. \u5148\u628A\u8349\u7A3F\u7528\u5927\u767D\u8BDD\u5217\u7ED9\u6211\u8FC7\u76EE\uFF0C\u6211\u786E\u8BA4\u540E\u518D\u63D0\u4EA4\u3002",
23778
+ canDigest ? "4. \u786E\u8BA4\u540E\u8C03 propose_digest\uFF0Cspec_change.expected_version \u586B\u7B2C 1 \u6B65\u8BFB\u5230\u7684 specVersion\u3002\u5B83\u662F\u4E00\u6761\u5F85\u4EBA\u786E\u8BA4\u7684\u63D0\u6848\uFF1A\u63A5\u53D7\u540E\u4E00\u6B21\u751F\u6548\u3001\u8BF4\u660E\u5F62\u6210\u65B0\u7248\u672C\uFF0C\u5728\u90A3\u4E4B\u524D\u4EFB\u52A1\u6CA1\u6709\u4EFB\u4F55\u6539\u52A8\u3002" : "4. \u5F53\u524D\u5DE5\u5177\u6863\uFF08work\uFF09\u6CA1\u6709 propose_digest\uFF1A\u786E\u8BA4\u540E\u628A\u51B3\u5B9A\u548C\u8BF4\u660E\u6539\u52A8\u7528 comment_on_task \u8BB0\u5230\u4EFB\u52A1\u4E0B\uFF0C\u963B\u585E\u95EE\u9898\u7528 ask_question \u63D0\u51FA\u6765\uFF1B\u5E76\u63D0\u9192\u6211\u8BF4\u660E\u672C\u8EAB\u8981\u5728 Momentum \u754C\u9762\u91CC\u6539\uFF0C\u6216\u628A MOMENTUM_TOOL_PROFILE \u8BBE\u6210 full \u540E\u518D\u63D0\u4EA4\u63D0\u6848\u3002"
23779
+ ])
23780
+ },
23781
+ {
23782
+ name: "write_delivery",
23783
+ title: "\u5199\u4EA4\u4ED8\u8BF4\u660E",
23784
+ description: "\u6309\u4EFB\u52A1\u8BF4\u660E\u9010\u6761\u8986\u76D6\u9A8C\u6536\u6807\u51C6\uFF0C\u5199\u597D\u4EA4\u4ED8\u8BF4\u660E\u5E76\u8C03 finish_task_work \u63D0\u4EA4\u3001\u79FB\u5230\u8BC4\u5BA1\u3002",
23785
+ argsSchema: { task: TASK_ARG },
23786
+ render: ({ task }) => user([
23787
+ `\u4E3A\u4EFB\u52A1 ${task} \u5199\u4EA4\u4ED8\u8BF4\u660E\u5E76\u63D0\u4EA4\u3002`,
23788
+ "",
23789
+ `1. \u624B\u4E0A\u6CA1\u6709\u9A8C\u6536\u6807\u51C6\u548C specVersion \u65F6\u5148\u8C03 get_task_context("${task}")\u3002based_on_spec_version \u586B\u4F60\u5B9E\u9645\u5BF9\u7167\u7684\u90A3\u4E2A\u7248\u672C\uFF1B\u5F00\u5DE5\u540E\u8BF4\u660E\u5347\u8FC7\u7248\uFF0C\u5148\u5BF9\u7167\u65B0\u7248\u672C\u770B\u8FD8\u5DEE\u4EC0\u4E48\u3002`,
23790
+ "2. summary \u5199\u7ED9\u4EFB\u52A1\u6307\u6D3E\u7684\u4EBA\u770B\uFF1A\u5927\u767D\u8BDD\u8BB2\u505A\u4E86\u4EC0\u4E48\u3001\u5173\u952E\u53D6\u820D\u3001\u5BF9\u4F7F\u7528\u8005\u7684\u5F71\u54CD\uFF1B\u6D41\u7A0B\u6216\u6A21\u5757\u5173\u7CFB\u7528 mermaid \u753B\u51FA\u6765\u3002\u5DE5\u7A0B\u5E08\u591A\u8BB2\u5B9E\u73B0\u53D6\u820D\uFF0C\u5176\u4ED6\u4EBA\u53EA\u8BB2\u7ED3\u679C\u3002",
23791
+ "3. results \u9010\u6761\u8986\u76D6\u6BCF\u4E2A\u9A8C\u6536\u6807\u51C6\uFF08criterionId \u7528\u8BF4\u660E\u91CC\u7684 id\uFF09\uFF1Aoutcome \u53EA\u7528 passed / failed / unverified\uFF0Cevidence \u5199\u522B\u4EBA\u80FD\u6838\u5BF9\u7684\u8BC1\u636E\uFF08\u6D4B\u8BD5\u540D\u3001\u547D\u4EE4\u8F93\u51FA\u3001\u94FE\u63A5\uFF09\u3002\u6CA1\u6709\u771F\u6B63\u9A8C\u8BC1\u8FC7\u7684\u6807 unverified\uFF0C\u4E0D\u8981\u731C\u3002",
23792
+ "4. artifacts \u653E PR\u3001\u6587\u6863\u7B49\u94FE\u63A5\uFF1B\u6CA1\u505A\u5B8C\u7684\u5199\u8FDB remaining_work\uFF1B\u63A5\u624B\u7684\u4EBA\u9700\u8981\u77E5\u9053\u7684\u5199\u8FDB handoff\u3002",
23793
+ "5. \u8C03 finish_task_work \u63D0\u4EA4\uFF1Aidempotency_key \u53D6\u4E00\u4E2A\u7A33\u5B9A\u7684\u503C\uFF0C\u67D0\u4E00\u6B65\u5931\u8D25\u65F6\u7528\u76F8\u540C\u53C2\u6570\u91CD\u8BD5\u3002\u4EFB\u52A1\u4F1A\u8FDB\u8BC4\u5BA1\uFF0C\u8BC4\u5BA1\u901A\u8FC7\u524D\u4E0D\u7B97\u5B8C\u6210\u3002"
23794
+ ])
23795
+ }
23796
+ ];
23797
+ }
23798
+
23554
23799
  // ../../packages/core/src/task-schemas.ts
23555
23800
  var markdownSchema = external_exports.string().max(2e5);
23556
23801
  var httpUrl = external_exports.string().url().max(2e3).refine((url) => /^https?:\/\//i.test(url), "\u53EA\u652F\u6301 HTTP(S) \u94FE\u63A5");
@@ -23601,11 +23846,13 @@ var RunHeartbeats = class {
23601
23846
  lastRunOfTask = /* @__PURE__ */ new Map();
23602
23847
  pending = [];
23603
23848
  timer = null;
23849
+ closed = false;
23604
23850
  intervalMs;
23605
23851
  leaseSeconds;
23606
23852
  log;
23607
23853
  /** 开始替这次运行续约。expectClaim = 它手上应当有领取,续不上要告诉模型 */
23608
23854
  track(runId, taskId, expectClaim = false) {
23855
+ if (this.closed) return;
23609
23856
  this.runs.set(runId, { taskId, expectClaim });
23610
23857
  if (taskId) this.lastRunOfTask.set(taskId, runId);
23611
23858
  if (!this.timer) {
@@ -23628,6 +23875,10 @@ var RunHeartbeats = class {
23628
23875
  has(runId) {
23629
23876
  return this.runs.has(runId);
23630
23877
  }
23878
+ /** 正在续约的运行数 */
23879
+ get size() {
23880
+ return this.runs.size;
23881
+ }
23631
23882
  /** 取走攒下的提醒。每条只给模型看一次 */
23632
23883
  drainNotices() {
23633
23884
  return this.pending.splice(0);
@@ -23636,6 +23887,15 @@ var RunHeartbeats = class {
23636
23887
  if (this.timer) clearInterval(this.timer);
23637
23888
  this.timer = null;
23638
23889
  }
23890
+ /**
23891
+ * 永久停掉:之后再 track 也不会续约。远程会话(http.ts)结束时用 —— 会话关掉的那一刻
23892
+ * 可能还有一个 begin_task 在路上,它回来时的 track 不能把一个已经没人的会话重新续活
23893
+ */
23894
+ close() {
23895
+ this.closed = true;
23896
+ this.runs.clear();
23897
+ this.stop();
23898
+ }
23639
23899
  /** 给所有在跟的运行各发一次心跳。定时器调它,测试也直接调它 */
23640
23900
  async tick() {
23641
23901
  await Promise.all([...this.runs].map(([runId, run2]) => this.beatOne(runId, run2)));
@@ -23977,6 +24237,14 @@ var BEGIN_OUTPUT = external_exports.object({
23977
24237
  context: CONTEXT_SCHEMA.optional(),
23978
24238
  proposalId: external_exports.string().optional()
23979
24239
  }).passthrough();
24240
+ var NAMED = external_exports.object({ id: external_exports.string(), name: external_exports.string() }).passthrough();
24241
+ var WHOAMI_OUTPUT = external_exports.object({
24242
+ kind: external_exports.enum(["agent", "human"]),
24243
+ actorId: external_exports.string().nullable(),
24244
+ orgId: external_exports.string().nullable(),
24245
+ agent: NAMED.optional(),
24246
+ instance: NAMED.optional()
24247
+ }).passthrough();
23980
24248
  var PAGE_OUTPUT = external_exports.object({ items: external_exports.array(external_exports.unknown()) }).passthrough();
23981
24249
  var TASKS_OUTPUT = external_exports.object({ items: external_exports.array(external_exports.object(TASK_FIELDS).passthrough()) }).passthrough();
23982
24250
  var BROWSE_OUTCOME = external_exports.enum(["ok", "no_projects", "no_match", "project_unavailable", "failed"]);
@@ -23986,7 +24254,7 @@ var BROWSE_OUTPUT = external_exports.object({
23986
24254
  items: external_exports.array(external_exports.unknown()),
23987
24255
  nextOffset: external_exports.number().nullable()
23988
24256
  }).passthrough();
23989
- var READ = { readOnlyHint: true, openWorldHint: false };
24257
+ var READ = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false };
23990
24258
  var write = (destructiveHint, idempotentHint) => ({
23991
24259
  readOnlyHint: false,
23992
24260
  destructiveHint,
@@ -24010,7 +24278,7 @@ var TOOL_META = {
24010
24278
  list_task_deliveries: { annotations: READ, outputSchema: PAGE_OUTPUT },
24011
24279
  poll_events: { annotations: READ, outputSchema: PAGE_OUTPUT },
24012
24280
  current_cycle: { annotations: READ },
24013
- whoami: { annotations: READ },
24281
+ whoami: { annotations: READ, outputSchema: WHOAMI_OUTPUT },
24014
24282
  // 开工 / 收尾:重复调用沿用同一次运行、交付按 idempotency_key 去重
24015
24283
  begin_task: { annotations: write(false, true), outputSchema: BEGIN_OUTPUT },
24016
24284
  finish_task_work: { annotations: write(false, true), outputSchema: FINISH_OUTPUT },
@@ -25381,6 +25649,52 @@ function explain(err) {
25381
25649
  return `\u5931\u8D25\uFF1A${message}`;
25382
25650
  }
25383
25651
 
25652
+ // src/resources.ts
25653
+ var SPEC_URI = (key, version2) => `momentum://task/${encodeURIComponent(key)}/spec${version2 === void 0 ? "" : `/${version2}`}`;
25654
+ var UUID2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
25655
+ function renderSpec(key, spec, current) {
25656
+ const at = spec.createdAt instanceof Date ? spec.createdAt.toISOString() : spec.createdAt;
25657
+ const criteria = spec.acceptance?.criteria ?? [];
25658
+ return [
25659
+ `# ${key} \xB7 ${spec.title}`,
25660
+ "",
25661
+ `\u8BF4\u660E\u7248\u672C v${spec.version}\uFF08\u4E0D\u53EF\u53D8\uFF0C${current ? "\u5F53\u524D\u7248\uFF0C" : ""}\u5730\u5740 ${SPEC_URI(key, spec.version)}\uFF09\xB7 ${at}`,
25662
+ ...spec.changeSummary ? [`\u672C\u7248\u53D8\u66F4\uFF1A${spec.changeSummary}`] : [],
25663
+ "",
25664
+ "## \u63CF\u8FF0",
25665
+ "",
25666
+ spec.descriptionMd?.trim() || "\uFF08\u65E0\u63CF\u8FF0\uFF09",
25667
+ "",
25668
+ "## \u9A8C\u6536\u6807\u51C6",
25669
+ "",
25670
+ ...criteria.length ? criteria.map((c) => `- [${c.id}] ${c.text}`) : ["\uFF08\u672A\u5B9A\u4E49\u9A8C\u6536\u6807\u51C6\uFF09"]
25671
+ ].join("\n");
25672
+ }
25673
+ function createSpecReader(client) {
25674
+ async function resolve(ref) {
25675
+ const [found] = UUID2.test(ref) ? [await client.task.ref.query({ taskId: ref })] : await client.task.list.query({ key: ref, limit: 1 });
25676
+ if (!found) throw new Error(`\u627E\u4E0D\u5230\u4EFB\u52A1 '${ref}'`);
25677
+ return { id: found.id, key: found.key };
25678
+ }
25679
+ return async function readSpec(ref, version2) {
25680
+ if (version2 !== void 0 && !/^\d+$/.test(version2)) {
25681
+ throw new Error(`\u8BF4\u660E\u7248\u672C\u53F7\u5FC5\u987B\u662F\u975E\u8D1F\u6574\u6570\uFF0C\u6536\u5230 '${version2}'`);
25682
+ }
25683
+ try {
25684
+ const task = await resolve(ref);
25685
+ const current = (await client.task.context.query({ taskId: task.id })).specVersion;
25686
+ const wanted = version2 === void 0 ? current : Number(version2);
25687
+ const spec = await client.task.spec.query({ taskId: task.id, version: wanted });
25688
+ return {
25689
+ mimeType: "text/markdown",
25690
+ text: renderSpec(task.key, spec, wanted === current)
25691
+ };
25692
+ } catch (err) {
25693
+ throw new Error(explain(err));
25694
+ }
25695
+ };
25696
+ }
25697
+
25384
25698
  // src/server.ts
25385
25699
  var SERVER_INFO = {
25386
25700
  name: "momentum",
@@ -25426,6 +25740,29 @@ function createMcpServer(client, profile = "work", options = {}) {
25426
25740
  (args, extra) => tool.handler(args, extra._meta)
25427
25741
  );
25428
25742
  }
25743
+ for (const prompt of createPrompts(profile)) {
25744
+ server.registerPrompt(
25745
+ prompt.name,
25746
+ { title: prompt.title, description: prompt.description, argsSchema: prompt.argsSchema },
25747
+ (args) => ({ description: prompt.description, messages: prompt.render(args) })
25748
+ );
25749
+ }
25750
+ const readSpec = createSpecReader(client);
25751
+ const one = (value) => Array.isArray(value) ? value[0] ?? "" : value ?? "";
25752
+ server.registerResource(
25753
+ "task_spec",
25754
+ new ResourceTemplate("momentum://task/{key}/spec", { list: void 0 }),
25755
+ { title: "\u4EFB\u52A1\u8BF4\u660E\uFF08\u5F53\u524D\u7248\uFF09", description: "\u4EFB\u52A1\u5F53\u524D\u7248\u672C\u7684\u6807\u9898\u3001\u63CF\u8FF0\u548C\u9A8C\u6536\u6807\u51C6\uFF0C\u6B63\u6587\u91CC\u5199\u660E\u7248\u672C\u53F7\u548C\u90A3\u4E00\u7248\u7684\u4E0D\u53EF\u53D8\u5730\u5740\u3002", mimeType: "text/markdown" },
25756
+ async (uri, vars) => ({ contents: [{ uri: uri.href, ...await readSpec(decodeURIComponent(one(vars.key))) }] })
25757
+ );
25758
+ server.registerResource(
25759
+ "task_spec_version",
25760
+ new ResourceTemplate("momentum://task/{key}/spec/{version}", { list: void 0 }),
25761
+ { title: "\u4EFB\u52A1\u8BF4\u660E\uFF08\u6307\u5B9A\u7248\u672C\uFF09", description: "\u4EFB\u52A1\u8BF4\u660E\u7684\u67D0\u4E00\u7248\uFF0C\u5185\u5BB9\u4E0D\u53EF\u53D8\u3002\u4EA4\u4ED8\u65F6 based_on_spec_version \u5BF9\u7167\u7684\u5C31\u662F\u5B83\u3002", mimeType: "text/markdown" },
25762
+ async (uri, vars) => ({
25763
+ contents: [{ uri: uri.href, ...await readSpec(decodeURIComponent(one(vars.key)), decodeURIComponent(one(vars.version))) }]
25764
+ })
25765
+ );
25429
25766
  return server;
25430
25767
  }
25431
25768
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@costgate/momentum-mcp",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "Momentum MCP Server —— 把 Momentum 的任务、领取与交付接进任意 MCP 客户端",
5
5
  "type": "module",
6
6
  "bin": {