@costgate/momentum-mcp 0.1.36 → 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/README.md +2 -2
- package/momentum-mcp.mjs +505 -114
- package/package.json +1 -1
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.
|
|
12
|
+
默认用 `@latest`,发新版不用改配置;想固定某一版时把 latest 换成版本号(当前是 0.2.0)。
|
|
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.
|
|
21
|
+
版本 0.2.0。客户端和服务端版本不一致时,启动日志(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.
|
|
7198
|
+
// ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_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.
|
|
11702
|
+
// ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_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.
|
|
13233
|
+
// ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_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.
|
|
13270
|
+
// ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_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.
|
|
15342
|
+
var MCP_VERSION = true ? "0.2.0" : 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.
|
|
19480
|
+
// ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_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.
|
|
19640
|
+
// ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_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.
|
|
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
|
|
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.
|
|
20971
|
+
// ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_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,6 +21009,9 @@ 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
|
+
}
|
|
21012
21015
|
if (this._taskMessageQueue) {
|
|
21013
21016
|
let queuedMessage;
|
|
21014
21017
|
while (queuedMessage = await this._taskMessageQueue.dequeue(taskId, extra.sessionId)) {
|
|
@@ -21039,12 +21042,12 @@ var Protocol = class {
|
|
|
21039
21042
|
throw new McpError(ErrorCode.InvalidParams, `Task not found: ${taskId}`);
|
|
21040
21043
|
}
|
|
21041
21044
|
if (!isTerminal(task.status)) {
|
|
21042
|
-
await this._waitForTaskUpdate(taskId, extra.signal);
|
|
21045
|
+
await this._waitForTaskUpdate(taskId, extra.signal, extra.sessionId);
|
|
21043
21046
|
return await handleTaskResult();
|
|
21044
21047
|
}
|
|
21045
21048
|
if (isTerminal(task.status)) {
|
|
21046
21049
|
const result = await this._taskStore.getTaskResult(taskId, extra.sessionId);
|
|
21047
|
-
this._clearTaskQueue(taskId);
|
|
21050
|
+
this._clearTaskQueue(taskId, extra.sessionId);
|
|
21048
21051
|
return {
|
|
21049
21052
|
...result,
|
|
21050
21053
|
_meta: {
|
|
@@ -21081,7 +21084,7 @@ var Protocol = class {
|
|
|
21081
21084
|
throw new McpError(ErrorCode.InvalidParams, `Cannot cancel task in terminal status: ${task.status}`);
|
|
21082
21085
|
}
|
|
21083
21086
|
await this._taskStore.updateTaskStatus(request.params.taskId, "cancelled", "Client cancelled task execution.", extra.sessionId);
|
|
21084
|
-
this._clearTaskQueue(request.params.taskId);
|
|
21087
|
+
this._clearTaskQueue(request.params.taskId, extra.sessionId);
|
|
21085
21088
|
const cancelledTask = await this._taskStore.getTask(request.params.taskId, extra.sessionId);
|
|
21086
21089
|
if (!cancelledTask) {
|
|
21087
21090
|
throw new McpError(ErrorCode.InvalidParams, `Task not found after cancellation: ${request.params.taskId}`);
|
|
@@ -21209,6 +21212,19 @@ var Protocol = class {
|
|
|
21209
21212
|
const handler = this._requestHandlers.get(request.method) ?? this.fallbackRequestHandler;
|
|
21210
21213
|
const capturedTransport = this._transport;
|
|
21211
21214
|
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
|
+
}
|
|
21212
21228
|
if (handler === void 0) {
|
|
21213
21229
|
const errorResponse = {
|
|
21214
21230
|
jsonrpc: "2.0",
|
|
@@ -21218,7 +21234,10 @@ var Protocol = class {
|
|
|
21218
21234
|
message: "Method not found"
|
|
21219
21235
|
}
|
|
21220
21236
|
};
|
|
21221
|
-
if (relatedTaskId &&
|
|
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) {
|
|
21222
21241
|
this._enqueueTaskMessage(relatedTaskId, {
|
|
21223
21242
|
type: "error",
|
|
21224
21243
|
message: errorResponse,
|
|
@@ -21269,7 +21288,10 @@ var Protocol = class {
|
|
|
21269
21288
|
closeSSEStream: extra?.closeSSEStream,
|
|
21270
21289
|
closeStandaloneSSEStream: extra?.closeStandaloneSSEStream
|
|
21271
21290
|
};
|
|
21272
|
-
Promise.resolve().then(() => {
|
|
21291
|
+
(relatedTaskLookup ?? Promise.resolve()).then(() => {
|
|
21292
|
+
if (relatedTaskLookup && abortController.signal.aborted) {
|
|
21293
|
+
throw new McpError(ErrorCode.ConnectionClosed, "Request was cancelled");
|
|
21294
|
+
}
|
|
21273
21295
|
if (taskCreationParams) {
|
|
21274
21296
|
this.assertTaskHandlerCapability(request.method);
|
|
21275
21297
|
}
|
|
@@ -21304,7 +21326,7 @@ var Protocol = class {
|
|
|
21304
21326
|
...error2["data"] !== void 0 && { data: error2["data"] }
|
|
21305
21327
|
}
|
|
21306
21328
|
};
|
|
21307
|
-
if (relatedTaskId && this._taskMessageQueue) {
|
|
21329
|
+
if (relatedTaskId && this._taskMessageQueue && relatedTaskFound) {
|
|
21308
21330
|
await this._enqueueTaskMessage(relatedTaskId, {
|
|
21309
21331
|
type: "error",
|
|
21310
21332
|
message: errorResponse,
|
|
@@ -21784,7 +21806,7 @@ var Protocol = class {
|
|
|
21784
21806
|
throw new Error("Cannot enqueue task message: taskStore and taskMessageQueue are not configured");
|
|
21785
21807
|
}
|
|
21786
21808
|
const maxQueueSize = this._options?.maxTaskQueueSize;
|
|
21787
|
-
await this._taskMessageQueue.enqueue(taskId, message, sessionId, maxQueueSize);
|
|
21809
|
+
await this._taskMessageQueue.enqueue(taskId, message, sessionId ?? this._transport?.sessionId, maxQueueSize);
|
|
21788
21810
|
}
|
|
21789
21811
|
/**
|
|
21790
21812
|
* Clears the message queue for a task and rejects any pending request resolvers.
|
|
@@ -21813,12 +21835,13 @@ var Protocol = class {
|
|
|
21813
21835
|
* Uses polling to check for updates at the task's configured poll interval.
|
|
21814
21836
|
* @param taskId The task ID to wait for
|
|
21815
21837
|
* @param signal Abort signal to cancel the wait
|
|
21838
|
+
* @param sessionId Session of the request that waits, passed to the task store
|
|
21816
21839
|
* @returns Promise that resolves when an update occurs or rejects if aborted
|
|
21817
21840
|
*/
|
|
21818
|
-
async _waitForTaskUpdate(taskId, signal) {
|
|
21841
|
+
async _waitForTaskUpdate(taskId, signal, sessionId) {
|
|
21819
21842
|
let interval = this._options?.defaultTaskPollInterval ?? 1e3;
|
|
21820
21843
|
try {
|
|
21821
|
-
const task = await this._taskStore?.getTask(taskId);
|
|
21844
|
+
const task = await this._taskStore?.getTask(taskId, sessionId);
|
|
21822
21845
|
if (task?.pollInterval) {
|
|
21823
21846
|
interval = task.pollInterval;
|
|
21824
21847
|
}
|
|
@@ -21922,7 +21945,7 @@ function mergeCapabilities(base, additional) {
|
|
|
21922
21945
|
return result;
|
|
21923
21946
|
}
|
|
21924
21947
|
|
|
21925
|
-
// ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.
|
|
21948
|
+
// ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/validation/ajv-provider.js
|
|
21926
21949
|
var import_ajv = __toESM(require_ajv(), 1);
|
|
21927
21950
|
var import_ajv_formats = __toESM(require_dist(), 1);
|
|
21928
21951
|
function createDefaultAjvInstance() {
|
|
@@ -21990,7 +22013,7 @@ var AjvJsonSchemaValidator = class {
|
|
|
21990
22013
|
}
|
|
21991
22014
|
};
|
|
21992
22015
|
|
|
21993
|
-
// ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.
|
|
22016
|
+
// ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/server.js
|
|
21994
22017
|
var ExperimentalServerTasks = class {
|
|
21995
22018
|
constructor(_server) {
|
|
21996
22019
|
this._server = _server;
|
|
@@ -22203,7 +22226,7 @@ var ExperimentalServerTasks = class {
|
|
|
22203
22226
|
}
|
|
22204
22227
|
};
|
|
22205
22228
|
|
|
22206
|
-
// ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.
|
|
22229
|
+
// ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/helpers.js
|
|
22207
22230
|
function assertToolsCallTaskCapability(requests, method, entityName) {
|
|
22208
22231
|
if (!requests) {
|
|
22209
22232
|
throw new Error(`${entityName} does not support task creation (required for ${method})`);
|
|
@@ -22238,7 +22261,7 @@ function assertClientRequestTaskCapability(requests, method, entityName) {
|
|
|
22238
22261
|
}
|
|
22239
22262
|
}
|
|
22240
22263
|
|
|
22241
|
-
// ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.
|
|
22264
|
+
// ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/server/index.js
|
|
22242
22265
|
var Server = class extends Protocol {
|
|
22243
22266
|
/**
|
|
22244
22267
|
* Initializes this server with the given name and version information.
|
|
@@ -22609,7 +22632,7 @@ var Server = class extends Protocol {
|
|
|
22609
22632
|
}
|
|
22610
22633
|
};
|
|
22611
22634
|
|
|
22612
|
-
// ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.
|
|
22635
|
+
// ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/server/completable.js
|
|
22613
22636
|
var COMPLETABLE_SYMBOL = Symbol.for("mcp.completable");
|
|
22614
22637
|
function isCompletable(schema) {
|
|
22615
22638
|
return !!schema && typeof schema === "object" && COMPLETABLE_SYMBOL in schema;
|
|
@@ -22623,7 +22646,7 @@ var McpZodTypeKind;
|
|
|
22623
22646
|
McpZodTypeKind2["Completable"] = "McpCompletable";
|
|
22624
22647
|
})(McpZodTypeKind || (McpZodTypeKind = {}));
|
|
22625
22648
|
|
|
22626
|
-
// ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.
|
|
22649
|
+
// ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/shared/toolNameValidation.js
|
|
22627
22650
|
var TOOL_NAME_REGEX = /^[A-Za-z0-9._-]{1,128}$/;
|
|
22628
22651
|
function validateToolName(name) {
|
|
22629
22652
|
const warnings = [];
|
|
@@ -22681,7 +22704,7 @@ function validateAndWarnToolName(name) {
|
|
|
22681
22704
|
return result.isValid;
|
|
22682
22705
|
}
|
|
22683
22706
|
|
|
22684
|
-
// ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.
|
|
22707
|
+
// ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.32.1_zod@3.25.76/node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/mcp-server.js
|
|
22685
22708
|
var ExperimentalMcpServerTasks = class {
|
|
22686
22709
|
constructor(_mcpServer) {
|
|
22687
22710
|
this._mcpServer = _mcpServer;
|
|
@@ -22696,7 +22719,43 @@ var ExperimentalMcpServerTasks = class {
|
|
|
22696
22719
|
}
|
|
22697
22720
|
};
|
|
22698
22721
|
|
|
22699
|
-
// ../../node_modules/.pnpm/@modelcontextprotocol+sdk@1.
|
|
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
|
+
}
|
|
22700
22759
|
var McpServer = class {
|
|
22701
22760
|
constructor(serverInfo, options) {
|
|
22702
22761
|
this._registeredResources = {};
|
|
@@ -22708,6 +22767,7 @@ var McpServer = class {
|
|
|
22708
22767
|
this._resourceHandlersInitialized = false;
|
|
22709
22768
|
this._promptHandlersInitialized = false;
|
|
22710
22769
|
this.server = new Server(serverInfo, options);
|
|
22770
|
+
this._maxToolInputElements = resolveMaxToolInputElements(options?.maxToolInputElements);
|
|
22711
22771
|
}
|
|
22712
22772
|
/**
|
|
22713
22773
|
* Access experimental features.
|
|
@@ -22838,12 +22898,15 @@ var McpServer = class {
|
|
|
22838
22898
|
* Validates tool input arguments against the tool's input schema.
|
|
22839
22899
|
*/
|
|
22840
22900
|
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
|
+
}
|
|
22841
22904
|
if (!tool.inputSchema) {
|
|
22842
22905
|
return void 0;
|
|
22843
22906
|
}
|
|
22844
22907
|
const inputObj = normalizeObjectSchema(tool.inputSchema);
|
|
22845
22908
|
const schemaToParse = inputObj ?? tool.inputSchema;
|
|
22846
|
-
const parseResult = await safeParseAsync3(schemaToParse, args);
|
|
22909
|
+
const parseResult = await safeParseAsync3(schemaToParse, args ?? {});
|
|
22847
22910
|
if (!parseResult.success) {
|
|
22848
22911
|
const error2 = "error" in parseResult ? parseResult.error : "Unknown error";
|
|
22849
22912
|
const errorMessage = getParseErrorMessage(error2);
|
|
@@ -23081,7 +23144,7 @@ var McpServer = class {
|
|
|
23081
23144
|
}
|
|
23082
23145
|
if (prompt.argsSchema) {
|
|
23083
23146
|
const argsObj = normalizeObjectSchema(prompt.argsSchema);
|
|
23084
|
-
const parseResult = await safeParseAsync3(argsObj, request.params.arguments);
|
|
23147
|
+
const parseResult = await safeParseAsync3(argsObj, request.params.arguments ?? {});
|
|
23085
23148
|
if (!parseResult.success) {
|
|
23086
23149
|
const error2 = "error" in parseResult ? parseResult.error : "Unknown error";
|
|
23087
23150
|
const errorMessage = getParseErrorMessage(error2);
|
|
@@ -23877,7 +23940,105 @@ function defineTool(tool) {
|
|
|
23877
23940
|
var text = (body) => ({
|
|
23878
23941
|
content: [{ type: "text", text: body }]
|
|
23879
23942
|
});
|
|
23880
|
-
var json = (value) =>
|
|
23943
|
+
var json = (value) => {
|
|
23944
|
+
const body = JSON.stringify(value);
|
|
23945
|
+
const plain = JSON.parse(body);
|
|
23946
|
+
return {
|
|
23947
|
+
...text(body),
|
|
23948
|
+
structuredContent: plain !== null && typeof plain === "object" && !Array.isArray(plain) ? plain : { items: plain }
|
|
23949
|
+
};
|
|
23950
|
+
};
|
|
23951
|
+
var TASK_PATH = (key) => `/t/${key}`;
|
|
23952
|
+
var APPROVALS_PATH = "/review";
|
|
23953
|
+
var LINKS_SCHEMA = external_exports.record(external_exports.string());
|
|
23954
|
+
var WRITE_OUTPUT = external_exports.object({
|
|
23955
|
+
status: external_exports.enum(["executed", "pending_approval", "unchanged"]),
|
|
23956
|
+
message: external_exports.string(),
|
|
23957
|
+
proposalId: external_exports.string().optional(),
|
|
23958
|
+
links: LINKS_SCHEMA.optional()
|
|
23959
|
+
}).passthrough();
|
|
23960
|
+
var STEP_SCHEMA = external_exports.object({ status: external_exports.enum(["executed", "pending_approval", "failed", "skipped"]), message: external_exports.string() }).passthrough();
|
|
23961
|
+
var FINISH_OUTPUT = external_exports.object({
|
|
23962
|
+
status: external_exports.enum(["executed", "pending_approval", "partial"]),
|
|
23963
|
+
message: external_exports.string(),
|
|
23964
|
+
steps: external_exports.record(STEP_SCHEMA),
|
|
23965
|
+
links: LINKS_SCHEMA.optional()
|
|
23966
|
+
}).passthrough();
|
|
23967
|
+
var TASK_FIELDS = { key: external_exports.string(), title: external_exports.string() };
|
|
23968
|
+
var CONTEXT_SCHEMA = external_exports.object({
|
|
23969
|
+
...TASK_FIELDS,
|
|
23970
|
+
status: external_exports.object({ name: external_exports.string(), category: external_exports.string() }).passthrough(),
|
|
23971
|
+
links: LINKS_SCHEMA.optional()
|
|
23972
|
+
}).passthrough();
|
|
23973
|
+
var BEGIN_OUTPUT = external_exports.object({
|
|
23974
|
+
status: external_exports.enum(["executed", "pending_approval"]),
|
|
23975
|
+
runId: external_exports.string().optional(),
|
|
23976
|
+
claim: external_exports.object({ status: external_exports.string() }).passthrough().optional(),
|
|
23977
|
+
context: CONTEXT_SCHEMA.optional(),
|
|
23978
|
+
proposalId: external_exports.string().optional()
|
|
23979
|
+
}).passthrough();
|
|
23980
|
+
var PAGE_OUTPUT = external_exports.object({ items: external_exports.array(external_exports.unknown()) }).passthrough();
|
|
23981
|
+
var TASKS_OUTPUT = external_exports.object({ items: external_exports.array(external_exports.object(TASK_FIELDS).passthrough()) }).passthrough();
|
|
23982
|
+
var BROWSE_OUTCOME = external_exports.enum(["ok", "no_projects", "no_match", "project_unavailable", "failed"]);
|
|
23983
|
+
var BROWSE_OUTPUT = external_exports.object({
|
|
23984
|
+
outcome: BROWSE_OUTCOME,
|
|
23985
|
+
message: external_exports.string(),
|
|
23986
|
+
items: external_exports.array(external_exports.unknown()),
|
|
23987
|
+
nextOffset: external_exports.number().nullable()
|
|
23988
|
+
}).passthrough();
|
|
23989
|
+
var READ = { readOnlyHint: true, openWorldHint: false };
|
|
23990
|
+
var write = (destructiveHint, idempotentHint) => ({
|
|
23991
|
+
readOnlyHint: false,
|
|
23992
|
+
destructiveHint,
|
|
23993
|
+
idempotentHint
|
|
23994
|
+
});
|
|
23995
|
+
var TOOL_META = {
|
|
23996
|
+
// 只读查询 —— 客户端不该为它们弹确认
|
|
23997
|
+
get_task_context: { annotations: READ, outputSchema: CONTEXT_SCHEMA },
|
|
23998
|
+
get_task: { annotations: READ, outputSchema: CONTEXT_SCHEMA },
|
|
23999
|
+
get_task_spec: { annotations: READ },
|
|
24000
|
+
list_tasks: { annotations: READ, outputSchema: TASKS_OUTPUT },
|
|
24001
|
+
list_task_templates: { annotations: READ },
|
|
24002
|
+
list_recycled_tasks: { annotations: READ, outputSchema: PAGE_OUTPUT },
|
|
24003
|
+
delete_task: { annotations: write(true, false) },
|
|
24004
|
+
restore_task: { annotations: write(false, false) },
|
|
24005
|
+
purge_task: { annotations: write(true, false) },
|
|
24006
|
+
browse_tasks: { annotations: READ, outputSchema: BROWSE_OUTPUT },
|
|
24007
|
+
list_ready_tasks: { annotations: READ, outputSchema: TASKS_OUTPUT },
|
|
24008
|
+
list_projects: { annotations: READ, outputSchema: PAGE_OUTPUT },
|
|
24009
|
+
list_task_comments: { annotations: READ, outputSchema: PAGE_OUTPUT },
|
|
24010
|
+
list_task_deliveries: { annotations: READ, outputSchema: PAGE_OUTPUT },
|
|
24011
|
+
poll_events: { annotations: READ, outputSchema: PAGE_OUTPUT },
|
|
24012
|
+
current_cycle: { annotations: READ },
|
|
24013
|
+
whoami: { annotations: READ },
|
|
24014
|
+
// 开工 / 收尾:重复调用沿用同一次运行、交付按 idempotency_key 去重
|
|
24015
|
+
begin_task: { annotations: write(false, true), outputSchema: BEGIN_OUTPUT },
|
|
24016
|
+
finish_task_work: { annotations: write(false, true), outputSchema: FINISH_OUTPUT },
|
|
24017
|
+
// 追加型的写
|
|
24018
|
+
create_task: { annotations: write(false, false), outputSchema: WRITE_OUTPUT },
|
|
24019
|
+
comment_on_task: { annotations: write(false, false) },
|
|
24020
|
+
ask_question: { annotations: write(false, false) },
|
|
24021
|
+
answer_question: { annotations: write(false, false) },
|
|
24022
|
+
add_task_relation: { annotations: write(false, false) },
|
|
24023
|
+
update_task: { annotations: write(false, false) },
|
|
24024
|
+
propose_digest: { annotations: write(false, false) },
|
|
24025
|
+
submit_delivery: { annotations: write(false, true), outputSchema: WRITE_OUTPUT },
|
|
24026
|
+
review_delivery: { annotations: write(false, false), outputSchema: WRITE_OUTPUT },
|
|
24027
|
+
confirm_delivery: { annotations: write(false, false) },
|
|
24028
|
+
start_run: { annotations: write(false, false) },
|
|
24029
|
+
finish_run: { annotations: write(false, false) },
|
|
24030
|
+
heartbeat_run: { annotations: write(false, true) },
|
|
24031
|
+
claim_task: { annotations: write(false, true), outputSchema: WRITE_OUTPUT },
|
|
24032
|
+
claim_next_task: { annotations: write(false, false), outputSchema: WRITE_OUTPUT },
|
|
24033
|
+
// 改状态、挪位置、放手:改的是当前值,历史在事件流里留着
|
|
24034
|
+
update_task_status: { annotations: write(false, true), outputSchema: WRITE_OUTPUT },
|
|
24035
|
+
release_task: { annotations: write(false, false), outputSchema: WRITE_OUTPUT },
|
|
24036
|
+
set_task_parent: { annotations: write(false, true) },
|
|
24037
|
+
plan_task: { annotations: write(false, true) },
|
|
24038
|
+
// 覆盖或删除已有内容:notes / refs 整份替换,关系直接移除
|
|
24039
|
+
update_task_plan: { annotations: write(true, true) },
|
|
24040
|
+
remove_task_relation: { annotations: write(true, false) }
|
|
24041
|
+
};
|
|
23881
24042
|
var RECEIPT_KEYS = [
|
|
23882
24043
|
"id",
|
|
23883
24044
|
"key",
|
|
@@ -23915,30 +24076,32 @@ function compactReceipt(value) {
|
|
|
23915
24076
|
);
|
|
23916
24077
|
return Object.keys(receipt).length > 0 ? receipt : { ok: true };
|
|
23917
24078
|
}
|
|
23918
|
-
|
|
23919
|
-
|
|
23920
|
-
|
|
23921
|
-
|
|
23922
|
-
`\u23F8 \u8FD9\u4E2A\u52A8\u4F5C\u9700\u8981\u4EBA\u5DE5\u6279\u51C6\uFF0C**\u5C1A\u672A\u751F\u6548**\u3002`,
|
|
23923
|
-
`\u5DF2\u63D0\u4EA4\u63D0\u6848 ${res.proposalId}\uFF1A${res.summary}`,
|
|
23924
|
-
`\u56E2\u961F\u6210\u5458\u5728 Momentum \u7684\u8BC4\u5BA1\u961F\u5217\u91CC\u63A5\u53D7\u4E4B\u540E\u624D\u4F1A\u771F\u6B63\u6267\u884C\u3002\u522B\u5047\u8BBE\u5B83\u5DF2\u7ECF\u5B8C\u6210\u3002`
|
|
23925
|
-
].join("\n")
|
|
23926
|
-
);
|
|
23927
|
-
}
|
|
23928
|
-
return text(`\u2713 ${done}
|
|
23929
|
-
|
|
23930
|
-
${JSON.stringify(compactReceipt(res.result))}`);
|
|
23931
|
-
}
|
|
24079
|
+
var unchanged = (message) => ({
|
|
24080
|
+
...text(message),
|
|
24081
|
+
structuredContent: { status: "unchanged", message }
|
|
24082
|
+
});
|
|
23932
24083
|
var RELATION_KIND = external_exports.enum(["blocks", "blocked_by", "relates", "duplicates"]);
|
|
23933
24084
|
var UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
23934
24085
|
function matchStatus(candidates, wanted) {
|
|
23935
24086
|
const needle = wanted.trim().toLowerCase();
|
|
23936
24087
|
return candidates.find((s) => s.id === wanted) ?? candidates.find((s) => s.name.toLowerCase() === needle) ?? candidates.find((s) => s.category === needle) ?? candidates.find((s) => s.name.toLowerCase().includes(needle));
|
|
23937
24088
|
}
|
|
24089
|
+
var NO_PROJECTS_MESSAGE = "\u8FD9\u4E2A Agent \u4E00\u4E2A\u9879\u76EE\u90FD\u8BBF\u95EE\u4E0D\u5230\u3002\u8BA9\u7BA1\u7406\u5458\u5728 Momentum \u7684 Agents \u9875\u52FE\u4E0A\u300C\u53EF\u8BBF\u95EE\u9879\u76EE\u300D\u6216\u6574\u4E2A Sector\uFF1B\u7528 whoami \u53EF\u4EE5\u770B\u5230\u5F53\u524D\u7684 grants.projects / grants.sectors\u3002";
|
|
24090
|
+
var BROWSE_DEFAULT_LIMIT = 20;
|
|
24091
|
+
var BROWSE_MAX_LIMIT = 50;
|
|
24092
|
+
var BROWSE_MAX_PROJECTS = 50;
|
|
24093
|
+
var STATUS_CATEGORIES = ["backlog", "unstarted", "started", "blocked", "review", "done", "canceled"];
|
|
23938
24094
|
var WORK_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
23939
24095
|
"begin_task",
|
|
24096
|
+
"list_recycled_tasks",
|
|
24097
|
+
"delete_task",
|
|
24098
|
+
"restore_task",
|
|
24099
|
+
"purge_task",
|
|
23940
24100
|
"finish_task_work",
|
|
23941
24101
|
"get_task_context",
|
|
24102
|
+
// 不知道任务编号时找活的入口(IMMO-221):只读、有界、只回摘要。list_projects / list_tasks
|
|
24103
|
+
// 仍在 full 档 —— 它们的 schema 更大,项目列表还带整段描述和冲刺配置
|
|
24104
|
+
"browse_tasks",
|
|
23942
24105
|
"get_task_spec",
|
|
23943
24106
|
"list_task_comments",
|
|
23944
24107
|
"list_task_deliveries",
|
|
@@ -23968,6 +24131,41 @@ function createTools(client, profile = "full", options = {}) {
|
|
|
23968
24131
|
const meters = new RunMeters();
|
|
23969
24132
|
const reported = options.hostReports ?? new HostReports(options.log);
|
|
23970
24133
|
const readUsage = options.readUsage ?? hostUsageReader(process.env, { log: options.log, reported });
|
|
24134
|
+
const appUrl = (options.appUrl ?? "").replace(/\/+$/, "");
|
|
24135
|
+
function linksFor(taskKey, pending = false) {
|
|
24136
|
+
return {
|
|
24137
|
+
...taskKey ? { task: `${appUrl}${TASK_PATH(taskKey)}` } : {},
|
|
24138
|
+
...pending ? { approvals: `${appUrl}${APPROVALS_PATH}` } : {}
|
|
24139
|
+
};
|
|
24140
|
+
}
|
|
24141
|
+
function reportWrite(done, res, taskKey) {
|
|
24142
|
+
if (res.status === "proposed") {
|
|
24143
|
+
const links = linksFor(taskKey, true);
|
|
24144
|
+
const message = [
|
|
24145
|
+
`\u23F8 \u8FD9\u4E2A\u52A8\u4F5C\u9700\u8981\u4EBA\u5DE5\u6279\u51C6\uFF0C**\u5C1A\u672A\u751F\u6548**\u3002`,
|
|
24146
|
+
`\u5DF2\u63D0\u4EA4\u63D0\u6848 ${res.proposalId}\uFF1A${res.summary}`,
|
|
24147
|
+
`\u56E2\u961F\u6210\u5458\u5728 Momentum \u7684\u8BC4\u5BA1\u961F\u5217\u91CC\u63A5\u53D7\u4E4B\u540E\u624D\u4F1A\u771F\u6B63\u6267\u884C\u3002\u522B\u5047\u8BBE\u5B83\u5DF2\u7ECF\u5B8C\u6210\u3002`,
|
|
24148
|
+
`\u6279\u51C6\u5165\u53E3\uFF1A${links.approvals}`
|
|
24149
|
+
].join("\n");
|
|
24150
|
+
return {
|
|
24151
|
+
...text(message),
|
|
24152
|
+
structuredContent: { status: "pending_approval", message, proposalId: res.proposalId, summary: res.summary, links }
|
|
24153
|
+
};
|
|
24154
|
+
}
|
|
24155
|
+
const result = compactReceipt(res.result);
|
|
24156
|
+
const key = taskKey ?? result?.key;
|
|
24157
|
+
return {
|
|
24158
|
+
...text(`\u2713 ${done}
|
|
24159
|
+
|
|
24160
|
+
${JSON.stringify(result)}`),
|
|
24161
|
+
structuredContent: {
|
|
24162
|
+
status: "executed",
|
|
24163
|
+
message: done,
|
|
24164
|
+
result: JSON.parse(JSON.stringify(result)),
|
|
24165
|
+
links: linksFor(typeof key === "string" ? key : null)
|
|
24166
|
+
}
|
|
24167
|
+
};
|
|
24168
|
+
}
|
|
23971
24169
|
async function measured(runId) {
|
|
23972
24170
|
const meter = meters.get(runId);
|
|
23973
24171
|
if (!meter) return {};
|
|
@@ -23991,9 +24189,7 @@ function createTools(client, profile = "full", options = {}) {
|
|
|
23991
24189
|
const only = projects[0];
|
|
23992
24190
|
if (projects.length === 1 && only) return only;
|
|
23993
24191
|
if (projects.length === 0) {
|
|
23994
|
-
throw new Error(
|
|
23995
|
-
"\u8FD9\u4E2A Agent \u4E00\u4E2A\u9879\u76EE\u90FD\u8BBF\u95EE\u4E0D\u5230\u3002\u8BA9\u7BA1\u7406\u5458\u5728 Momentum \u7684 Agents \u9875\u52FE\u4E0A\u300C\u53EF\u8BBF\u95EE\u9879\u76EE\u300D\u6216\u6574\u4E2A Sector\uFF1B\u7528 whoami \u53EF\u4EE5\u770B\u5230\u5F53\u524D\u7684 grants.projects / grants.sectors\u3002"
|
|
23996
|
-
);
|
|
24192
|
+
throw new Error(NO_PROJECTS_MESSAGE);
|
|
23997
24193
|
}
|
|
23998
24194
|
throw new Error(
|
|
23999
24195
|
`\u6709 ${projects.length} \u4E2A\u9879\u76EE\uFF0C\u8BF7\u7528 project \u53C2\u6570\u6307\u5B9A\uFF1A${projects.map((p) => p.key).join(", ")}`
|
|
@@ -24127,13 +24323,22 @@ ${options2}`
|
|
|
24127
24323
|
const statuses = await client.project.statuses.query({ projectId: task.projectId });
|
|
24128
24324
|
const target = matchStatus(statuses, wanted);
|
|
24129
24325
|
if (!target) {
|
|
24130
|
-
return
|
|
24326
|
+
return {
|
|
24327
|
+
status: "failed",
|
|
24328
|
+
message: `\u26A0 \u72B6\u6001\u672A\u6539\uFF1A\u6CA1\u6709\u5339\u914D\u300C${wanted}\u300D\u7684\u5217\uFF08\u6709\uFF1A${statuses.map((s) => `${s.name}(${s.category})`).join(", ")}\uFF09`
|
|
24329
|
+
};
|
|
24131
24330
|
}
|
|
24331
|
+
const column = { statusId: target.id, statusName: target.name, statusCategory: target.category };
|
|
24132
24332
|
try {
|
|
24133
24333
|
const res = await client.task.transition.mutate({ taskId: task.id, statusId: target.id });
|
|
24134
24334
|
if (res.status === "proposed") {
|
|
24135
24335
|
receipt.statusProposalId = res.proposalId;
|
|
24136
|
-
return
|
|
24336
|
+
return {
|
|
24337
|
+
status: "pending_approval",
|
|
24338
|
+
message: `\u23F8 \u79FB\u5230\u300C${target.name}\u300D\u9700\u8981\u4EBA\u5DE5\u6279\u51C6\uFF0C\u5C1A\u672A\u751F\u6548`,
|
|
24339
|
+
proposalId: res.proposalId,
|
|
24340
|
+
...column
|
|
24341
|
+
};
|
|
24137
24342
|
}
|
|
24138
24343
|
} catch (err) {
|
|
24139
24344
|
if (!(errorCode(err) === "CONFLICT" && err instanceof Error && err.message.includes("\u72B6\u6001\u672A\u53D1\u751F\u53D8\u5316"))) {
|
|
@@ -24141,27 +24346,41 @@ ${options2}`
|
|
|
24141
24346
|
}
|
|
24142
24347
|
}
|
|
24143
24348
|
receipt.status = target.name;
|
|
24144
|
-
return `\u2713 \u4EFB\u52A1\u5728\u300C${target.name}\u300D
|
|
24349
|
+
return { status: "executed", message: `\u2713 \u4EFB\u52A1\u5728\u300C${target.name}\u300D`, ...column };
|
|
24145
24350
|
} catch (err) {
|
|
24146
|
-
return `\u26A0 \u72B6\u6001\u672A\u6539\u3002${explain(err)}
|
|
24351
|
+
return { status: "failed", message: `\u26A0 \u72B6\u6001\u672A\u6539\u3002${explain(err)}` };
|
|
24147
24352
|
}
|
|
24148
24353
|
}
|
|
24149
24354
|
async function finishRunAfterDelivery(runId, input, receipt) {
|
|
24150
|
-
if (!runId)
|
|
24355
|
+
if (!runId) {
|
|
24356
|
+
return { status: "skipped", message: "\xB7 \u6CA1\u6709\u7ED3\u675F\u8FD0\u884C\uFF1A\u672C\u8FDB\u7A0B\u6CA1\u4E3A\u8FD9\u4EF6\u4EFB\u52A1\u5F00\u8FC7\u8FD0\u884C\uFF0C\u4E5F\u6CA1\u4F20 run_id" };
|
|
24357
|
+
}
|
|
24151
24358
|
try {
|
|
24152
24359
|
const res = await client.run.finish.mutate({ runId, ...input, ...await measured(runId) });
|
|
24153
|
-
if (res.status === "proposed")
|
|
24360
|
+
if (res.status === "proposed") {
|
|
24361
|
+
return {
|
|
24362
|
+
status: "pending_approval",
|
|
24363
|
+
message: "\u23F8 \u7ED3\u675F\u8FD0\u884C\u9700\u8981\u4EBA\u5DE5\u6279\u51C6\uFF0C\u5C1A\u672A\u751F\u6548\uFF1B\u672C\u8FDB\u7A0B\u4F1A\u7EE7\u7EED\u4E3A\u5B83\u5FC3\u8DF3",
|
|
24364
|
+
proposalId: res.proposalId,
|
|
24365
|
+
runId
|
|
24366
|
+
};
|
|
24367
|
+
}
|
|
24154
24368
|
forgetRun(runId);
|
|
24155
24369
|
Object.assign(receipt, { runId, runState: input.state });
|
|
24156
24370
|
const { releasedClaimOn } = res.result;
|
|
24157
|
-
return
|
|
24371
|
+
return {
|
|
24372
|
+
status: "executed",
|
|
24373
|
+
message: `\u2713 \u8FD0\u884C\u5DF2\u7ED3\u675F\uFF08${input.state}\uFF09${releasedClaimOn ? "\uFF0C\u9886\u53D6\u5DF2\u653E\u624B" : ""}`,
|
|
24374
|
+
runId,
|
|
24375
|
+
runState: input.state
|
|
24376
|
+
};
|
|
24158
24377
|
} catch (err) {
|
|
24159
24378
|
if (errorCode(err) === "CONFLICT") {
|
|
24160
24379
|
forgetRun(runId);
|
|
24161
24380
|
receipt.runId = runId;
|
|
24162
|
-
return "\u2713 \u8FD0\u884C\u6B64\u524D\u5DF2\u7ED3\u675F";
|
|
24381
|
+
return { status: "executed", message: "\u2713 \u8FD0\u884C\u6B64\u524D\u5DF2\u7ED3\u675F", runId };
|
|
24163
24382
|
}
|
|
24164
|
-
return `\u26A0 \u8FD0\u884C\u672A\u7ED3\u675F\uFF0C\u53EF\u7A0D\u540E\u7528 finish_run \u5355\u72EC\u7ED3\u675F\u3002${explain(err)}
|
|
24383
|
+
return { status: "failed", message: `\u26A0 \u8FD0\u884C\u672A\u7ED3\u675F\uFF0C\u53EF\u7A0D\u540E\u7528 finish_run \u5355\u72EC\u7ED3\u675F\u3002${explain(err)}`, runId };
|
|
24165
24384
|
}
|
|
24166
24385
|
}
|
|
24167
24386
|
const cursorSchema = external_exports.object({ createdAt: external_exports.string().datetime(), id: external_exports.string().uuid() });
|
|
@@ -24182,13 +24401,19 @@ ${options2}`
|
|
|
24182
24401
|
taskId: task.id,
|
|
24183
24402
|
trigger: { source: "mcp", tool: "begin_task", note: args.note ?? null }
|
|
24184
24403
|
});
|
|
24185
|
-
if (started.status === "proposed") return reportWrite("", started);
|
|
24404
|
+
if (started.status === "proposed") return reportWrite("", started, task.key);
|
|
24186
24405
|
runId = started.result.runId;
|
|
24187
24406
|
trackRun(runId, task.id);
|
|
24188
24407
|
}
|
|
24189
24408
|
const claim = await claimForRun(task.id, runId);
|
|
24190
24409
|
const context = await client.task.context.query({ taskId: task.id });
|
|
24191
|
-
return json({
|
|
24410
|
+
return json({
|
|
24411
|
+
status: "executed",
|
|
24412
|
+
runId,
|
|
24413
|
+
claim,
|
|
24414
|
+
context,
|
|
24415
|
+
links: linksFor(task.key, claim.status === "pending_approval")
|
|
24416
|
+
});
|
|
24192
24417
|
}
|
|
24193
24418
|
}),
|
|
24194
24419
|
defineTool({
|
|
@@ -24213,7 +24438,7 @@ ${options2}`
|
|
|
24213
24438
|
const task = await resolveTaskRef(args.task);
|
|
24214
24439
|
const runId = args.run_id ?? heartbeats.runFor(task.id);
|
|
24215
24440
|
const receipt = { key: task.key };
|
|
24216
|
-
|
|
24441
|
+
let delivery;
|
|
24217
24442
|
const delivered = await client.task.submitDelivery.mutate({
|
|
24218
24443
|
taskId: task.id,
|
|
24219
24444
|
basedOnSpecVersion: args.based_on_spec_version,
|
|
@@ -24227,30 +24452,47 @@ ${options2}`
|
|
|
24227
24452
|
});
|
|
24228
24453
|
if (delivered.status === "proposed") {
|
|
24229
24454
|
receipt.deliveryProposalId = delivered.proposalId;
|
|
24230
|
-
|
|
24455
|
+
delivery = {
|
|
24456
|
+
status: "pending_approval",
|
|
24457
|
+
message: `\u23F8 \u4EA4\u4ED8\u9700\u8981\u4EBA\u5DE5\u6279\u51C6\uFF0C\u5C1A\u672A\u751F\u6548\uFF08\u63D0\u6848 ${delivered.proposalId}\uFF09`,
|
|
24458
|
+
proposalId: delivered.proposalId
|
|
24459
|
+
};
|
|
24231
24460
|
} else {
|
|
24232
24461
|
const d = delivered.result;
|
|
24233
24462
|
Object.assign(receipt, { deliveryId: d.id, deliveryState: d.state }, d.outdated ? { outdated: true } : {});
|
|
24234
|
-
|
|
24235
|
-
|
|
24236
|
-
|
|
24237
|
-
|
|
24463
|
+
delivery = {
|
|
24464
|
+
status: "executed",
|
|
24465
|
+
message: (d.replayed ? "\u2713 \u4EA4\u4ED8\u6B64\u524D\u5DF2\u63D0\u4EA4\uFF08\u6309 idempotency_key \u91CD\u653E\uFF0C\u6CA1\u6709\u91CD\u590D\u521B\u5EFA\uFF09" : "\u2713 \u4EA4\u4ED8\u5DF2\u63D0\u4EA4\uFF0C\u7B49\u5F85\u8BC4\u5BA1\uFF1B\u4EFB\u52A1\u4E0D\u4F1A\u56E0\u6B64\u5B8C\u6210") + (d.outdated ? "\n\u26A0 \u4EA4\u4ED8\u4F9D\u636E\u7684\u4E0D\u662F\u5F53\u524D\u8BF4\u660E\u7248\u672C\uFF0C\u5DF2\u6807\u8BB0 outdated" : ""),
|
|
24466
|
+
deliveryId: d.id,
|
|
24467
|
+
deliveryState: d.state,
|
|
24468
|
+
replayed: d.replayed,
|
|
24469
|
+
outdated: d.outdated
|
|
24470
|
+
};
|
|
24238
24471
|
}
|
|
24239
|
-
|
|
24240
|
-
|
|
24241
|
-
|
|
24242
|
-
|
|
24243
|
-
|
|
24244
|
-
|
|
24245
|
-
|
|
24246
|
-
|
|
24247
|
-
|
|
24248
|
-
receipt
|
|
24249
|
-
)
|
|
24472
|
+
const transition = await moveAfterDelivery(task, args.status ?? "review", receipt);
|
|
24473
|
+
const run2 = await finishRunAfterDelivery(
|
|
24474
|
+
runId,
|
|
24475
|
+
{
|
|
24476
|
+
state: args.run_state ?? "succeeded",
|
|
24477
|
+
costUsd: args.cost_usd,
|
|
24478
|
+
transcriptUrl: args.transcript_url
|
|
24479
|
+
},
|
|
24480
|
+
receipt
|
|
24250
24481
|
);
|
|
24251
|
-
|
|
24482
|
+
const steps = [delivery, transition, run2];
|
|
24483
|
+
const pending = steps.some((s) => s.status === "pending_approval");
|
|
24484
|
+
const status = steps.some((s) => s.status === "failed" || s.status === "skipped") ? "partial" : pending ? "pending_approval" : "executed";
|
|
24485
|
+
const links = linksFor(task.key, pending);
|
|
24486
|
+
const message = [
|
|
24487
|
+
...steps.map((s) => s.message),
|
|
24488
|
+
...links.approvals ? [`\u6279\u51C6\u5165\u53E3\uFF1A${links.approvals}`] : []
|
|
24489
|
+
].join("\n");
|
|
24490
|
+
return {
|
|
24491
|
+
...text(`${message}
|
|
24252
24492
|
|
|
24253
|
-
${JSON.stringify(receipt)}`)
|
|
24493
|
+
${JSON.stringify(receipt)}`),
|
|
24494
|
+
structuredContent: { status, message, steps: { delivery, transition, run: run2 }, result: { ...receipt }, links }
|
|
24495
|
+
};
|
|
24254
24496
|
}
|
|
24255
24497
|
}),
|
|
24256
24498
|
defineTool({
|
|
@@ -24269,7 +24511,10 @@ ${JSON.stringify(receipt)}`);
|
|
|
24269
24511
|
limit: args.limit
|
|
24270
24512
|
});
|
|
24271
24513
|
if (items.length === 0) {
|
|
24272
|
-
return
|
|
24514
|
+
return {
|
|
24515
|
+
...text("\u73B0\u5728\u6CA1\u6709\u53EF\u4EE5\u63A5\u7684\u6D3B\u3002\u53EF\u80FD\u662F\u90FD\u88AB\u9886\u8D70\u4E86\u3001\u4F9D\u8D56\u8FD8\u6CA1\u5B8C\u6210\uFF0C\u6216\u8005\u6709\u963B\u788D\u5F00\u5DE5\u7684\u95EE\u9898\u5728\u7B49\u4EBA\u56DE\u7B54\u3002"),
|
|
24516
|
+
structuredContent: { items: [] }
|
|
24517
|
+
};
|
|
24273
24518
|
}
|
|
24274
24519
|
return json(items);
|
|
24275
24520
|
}
|
|
@@ -24301,7 +24546,7 @@ ${JSON.stringify(receipt)}`);
|
|
|
24301
24546
|
);
|
|
24302
24547
|
} catch (err) {
|
|
24303
24548
|
if (err instanceof Error && err.message.includes("\u6CA1\u6709\u53EF\u63A5\u7684\u6D3B")) {
|
|
24304
|
-
return
|
|
24549
|
+
return unchanged("\u73B0\u5728\u6CA1\u6709\u53EF\u4EE5\u63A5\u7684\u6D3B\uFF1A\u90FD\u88AB\u9886\u8D70\u4E86\u3001\u4F9D\u8D56\u6CA1\u7ED3\u6E05\uFF0C\u6216\u8005\u5728\u7B49\u4EBA\u56DE\u7B54\u963B\u788D\u5F00\u5DE5\u7684\u95EE\u9898\u3002");
|
|
24305
24550
|
}
|
|
24306
24551
|
if (err instanceof Error && err.message.includes("\u4E0D\u5C5E\u4E8E\u4EFB\u4F55\u9879\u76EE") && projects) {
|
|
24307
24552
|
throw new Error(
|
|
@@ -24330,7 +24575,7 @@ ${JSON.stringify(receipt)}`);
|
|
|
24330
24575
|
if (res.status === "executed" && args.run_id && heartbeats.has(args.run_id)) {
|
|
24331
24576
|
heartbeats.track(args.run_id, task.id, true);
|
|
24332
24577
|
}
|
|
24333
|
-
return reportWrite(args.run_id ? `\u5DF2\u9886\u53D6 ${task.key}\uFF1B\u79DF\u7EA6\u968F\u8FD0\u884C\u81EA\u52A8\u7EED\u7EA6` : `\u5DF2\u9886\u53D6 ${task.key}`, res);
|
|
24578
|
+
return reportWrite(args.run_id ? `\u5DF2\u9886\u53D6 ${task.key}\uFF1B\u79DF\u7EA6\u968F\u8FD0\u884C\u81EA\u52A8\u7EED\u7EA6` : `\u5DF2\u9886\u53D6 ${task.key}`, res, task.key);
|
|
24334
24579
|
}
|
|
24335
24580
|
}),
|
|
24336
24581
|
defineTool({
|
|
@@ -24341,7 +24586,8 @@ ${JSON.stringify(receipt)}`);
|
|
|
24341
24586
|
const task = await resolveTaskRef(args.task);
|
|
24342
24587
|
return reportWrite(
|
|
24343
24588
|
`\u5DF2\u91CA\u653E ${task.key}`,
|
|
24344
|
-
await client.task.release.mutate({ taskId: task.id, reason: args.reason })
|
|
24589
|
+
await client.task.release.mutate({ taskId: task.id, reason: args.reason }),
|
|
24590
|
+
task.key
|
|
24345
24591
|
);
|
|
24346
24592
|
}
|
|
24347
24593
|
}),
|
|
@@ -24394,7 +24640,7 @@ ${JSON.stringify(receipt)}`);
|
|
|
24394
24640
|
inputSchema: { task: external_exports.string() },
|
|
24395
24641
|
async handler(args) {
|
|
24396
24642
|
const task = await resolveTaskRef(args.task);
|
|
24397
|
-
return json(await client.task.context.query({ taskId: task.id }));
|
|
24643
|
+
return json({ ...await client.task.context.query({ taskId: task.id }), links: linksFor(task.key) });
|
|
24398
24644
|
}
|
|
24399
24645
|
}),
|
|
24400
24646
|
defineTool({
|
|
@@ -24413,7 +24659,7 @@ ${JSON.stringify(receipt)}`);
|
|
|
24413
24659
|
notesMd: args.notes,
|
|
24414
24660
|
verification: args.verification,
|
|
24415
24661
|
refs: args.refs
|
|
24416
|
-
}));
|
|
24662
|
+
}), task.key);
|
|
24417
24663
|
}
|
|
24418
24664
|
}),
|
|
24419
24665
|
defineTool({
|
|
@@ -24436,7 +24682,7 @@ ${JSON.stringify(receipt)}`);
|
|
|
24436
24682
|
descriptionMd: args.description,
|
|
24437
24683
|
acceptance: args.acceptance,
|
|
24438
24684
|
changeSummary: args.change_summary
|
|
24439
|
-
}));
|
|
24685
|
+
}), task.key);
|
|
24440
24686
|
}
|
|
24441
24687
|
}),
|
|
24442
24688
|
defineTool({
|
|
@@ -24500,7 +24746,7 @@ ${JSON.stringify(receipt)}`);
|
|
|
24500
24746
|
results: args.results,
|
|
24501
24747
|
remainingWork: args.remaining_work,
|
|
24502
24748
|
handoff: args.handoff
|
|
24503
|
-
}));
|
|
24749
|
+
}), task.key);
|
|
24504
24750
|
}
|
|
24505
24751
|
}),
|
|
24506
24752
|
defineTool({
|
|
@@ -24543,7 +24789,7 @@ ${JSON.stringify(receipt)}`);
|
|
|
24543
24789
|
taskId: task.id,
|
|
24544
24790
|
body: args.question,
|
|
24545
24791
|
blocking: args.blocking ?? false
|
|
24546
|
-
}));
|
|
24792
|
+
}), task.key);
|
|
24547
24793
|
}
|
|
24548
24794
|
}),
|
|
24549
24795
|
defineTool({
|
|
@@ -24594,7 +24840,7 @@ ${JSON.stringify(receipt)}`);
|
|
|
24594
24840
|
acceptance: spec.acceptance,
|
|
24595
24841
|
changeSummary: spec.change_summary
|
|
24596
24842
|
} : void 0
|
|
24597
|
-
}));
|
|
24843
|
+
}), task.key);
|
|
24598
24844
|
}
|
|
24599
24845
|
}),
|
|
24600
24846
|
defineTool({
|
|
@@ -24616,6 +24862,84 @@ ${JSON.stringify(receipt)}`);
|
|
|
24616
24862
|
});
|
|
24617
24863
|
}
|
|
24618
24864
|
}),
|
|
24865
|
+
defineTool({
|
|
24866
|
+
name: "browse_tasks",
|
|
24867
|
+
description: "\u4E0D\u77E5\u9053\u7F16\u53F7\u65F6\u627E\u4EFB\u52A1\uFF1A\u53EA\u8BFB\u5217\u51FA\u53EF\u8BBF\u95EE\u4EFB\u52A1\u7684\u6458\u8981\uFF0C\u4E0D\u9886\u53D6\u3001\u4E0D\u5F00\u8FD0\u884C\uFF1B\u9009\u5B9A\u540E begin_task\u3002outcome\uFF1Ano_projects \u8981\u7BA1\u7406\u5458\u6388\u6743\u9879\u76EE\uFF0Cno_match \u653E\u5BBD\u6761\u4EF6\uFF0Cfailed \u53EF\u91CD\u8BD5\u3002nextOffset \u975E\u7A7A = \u6709\u4E0B\u4E00\u9875\u3002",
|
|
24868
|
+
inputSchema: {
|
|
24869
|
+
project: external_exports.string().optional().describe("key \u6216\u540D\u5B57\uFF0C\u4E0D\u4F20 = \u5168\u90E8"),
|
|
24870
|
+
mine: external_exports.boolean().optional().describe("\u53EA\u770B\u6307\u6D3E\u7ED9\u6211\u7684"),
|
|
24871
|
+
status: external_exports.array(external_exports.enum(STATUS_CATEGORIES)).optional().describe("\u72B6\u6001\u5927\u7C7B"),
|
|
24872
|
+
query: external_exports.string().max(200).optional().describe("\u5173\u952E\u8BCD"),
|
|
24873
|
+
// 上限写在这里而不是 describe 里:schema 的 maximum 模型看得见,也真的拦得住
|
|
24874
|
+
limit: external_exports.number().int().min(1).max(BROWSE_MAX_LIMIT).optional(),
|
|
24875
|
+
offset: external_exports.number().int().min(0).optional()
|
|
24876
|
+
},
|
|
24877
|
+
async handler(args) {
|
|
24878
|
+
const limit = args.limit ?? BROWSE_DEFAULT_LIMIT;
|
|
24879
|
+
const offset = args.offset ?? 0;
|
|
24880
|
+
const stop = (outcome, message, isError2) => ({
|
|
24881
|
+
...text(message),
|
|
24882
|
+
structuredContent: { outcome, message, items: [], nextOffset: null },
|
|
24883
|
+
...isError2 ? { isError: isError2 } : {}
|
|
24884
|
+
});
|
|
24885
|
+
const failed = (err) => stop("failed", `${explain(err)}
|
|
24886
|
+
|
|
24887
|
+
\u8FD9\u662F\u8BFB\u53D6\u5931\u8D25\uFF0C\u4E0D\u4EE3\u8868\u6CA1\u6709\u4EFB\u52A1 \u2014\u2014 \u7A0D\u540E\u91CD\u8BD5\uFF1B\u53CD\u590D\u5931\u8D25\u518D\u68C0\u67E5\u7F51\u7EDC\u548C\u4EE4\u724C\u3002`, true);
|
|
24888
|
+
let projects;
|
|
24889
|
+
try {
|
|
24890
|
+
projects = await client.project.list.query();
|
|
24891
|
+
} catch (err) {
|
|
24892
|
+
return failed(err);
|
|
24893
|
+
}
|
|
24894
|
+
if (projects.length === 0) return stop("no_projects", NO_PROJECTS_MESSAGE, false);
|
|
24895
|
+
let project;
|
|
24896
|
+
if (args.project) {
|
|
24897
|
+
const ref = args.project;
|
|
24898
|
+
project = projects.find(
|
|
24899
|
+
(p) => p.id === ref || p.key.toLowerCase() === ref.toLowerCase() || p.name === ref
|
|
24900
|
+
);
|
|
24901
|
+
if (!project) {
|
|
24902
|
+
return stop("project_unavailable", `\u5931\u8D25\uFF1A${(await missingProjectError(ref, projects)).message}`, true);
|
|
24903
|
+
}
|
|
24904
|
+
}
|
|
24905
|
+
let rows;
|
|
24906
|
+
try {
|
|
24907
|
+
const assigneeId = args.mine ? (await client.viewer.me.query())?.actorId ?? void 0 : void 0;
|
|
24908
|
+
rows = await client.task.list.query({
|
|
24909
|
+
projectId: project?.id,
|
|
24910
|
+
categories: args.status,
|
|
24911
|
+
assigneeId,
|
|
24912
|
+
query: args.query,
|
|
24913
|
+
limit: limit + 1,
|
|
24914
|
+
offset
|
|
24915
|
+
});
|
|
24916
|
+
} catch (err) {
|
|
24917
|
+
return failed(err);
|
|
24918
|
+
}
|
|
24919
|
+
const page = rows.slice(0, limit);
|
|
24920
|
+
const items = page.map((t) => ({
|
|
24921
|
+
key: t.key,
|
|
24922
|
+
title: t.title,
|
|
24923
|
+
type: t.type,
|
|
24924
|
+
priority: t.priority,
|
|
24925
|
+
status: { name: t.status.name, category: t.status.category },
|
|
24926
|
+
assignee: t.assignee ? { name: t.assignee.name, kind: t.assignee.kind } : null,
|
|
24927
|
+
updatedAt: t.updatedAt
|
|
24928
|
+
}));
|
|
24929
|
+
const empty = items.length === 0;
|
|
24930
|
+
return json({
|
|
24931
|
+
outcome: empty ? "no_match" : "ok",
|
|
24932
|
+
message: empty ? offset > 0 ? "\u8FD9\u4E00\u9875\u6CA1\u6709\u66F4\u591A\u4EFB\u52A1\u4E86\u3002" : "\u6CA1\u6709\u7B26\u5408\u6761\u4EF6\u7684\u4EFB\u52A1\u3002\u53EF\u4EE5\u53BB\u6389 mine / status / query / project \u4E2D\u7684\u6761\u4EF6\u518D\u8BD5\u3002" : `${items.length} \u6761\u4EFB\u52A1${rows.length > limit ? "\uFF0C\u8FD8\u6709\u4E0B\u4E00\u9875" : ""}\u3002`,
|
|
24933
|
+
items,
|
|
24934
|
+
nextOffset: rows.length > limit ? offset + limit : null,
|
|
24935
|
+
// 第一页带上可选项目,客户端好做项目筛选;翻页时不重复
|
|
24936
|
+
...offset === 0 ? {
|
|
24937
|
+
projects: projects.slice(0, BROWSE_MAX_PROJECTS).map((p) => ({ key: p.key, name: p.name })),
|
|
24938
|
+
...projects.length > BROWSE_MAX_PROJECTS ? { projectsTruncated: true } : {}
|
|
24939
|
+
} : {}
|
|
24940
|
+
});
|
|
24941
|
+
}
|
|
24942
|
+
}),
|
|
24619
24943
|
defineTool({
|
|
24620
24944
|
name: "list_projects",
|
|
24621
24945
|
description: "\u5217\u51FA\u5F53\u524D\u7EC4\u7EC7\u91CC\u6211\u80FD\u8BBF\u95EE\u7684\u9879\u76EE\u3002\u8FD9\u91CC\u53EA\u6709\u6388\u6743\u7ED9\u672C Agent \u7684\u9879\u76EE \u2014\u2014 \u5C11\u4E86\u9884\u671F\u4E2D\u7684\u9879\u76EE\u5C31\u7528 whoami \u770B grants.projects / grants.sectors\uFF0C\u591A\u534A\u662F\u6CA1\u52FE\u4E0A\uFF08\u6216\u9879\u76EE\u5DF2\u79FB\u51FA\u6388\u6743\u7684 Sector\uFF09\uFF0C\u800C\u4E0D\u662F\u9879\u76EE\u4E0D\u5B58\u5728\u3002",
|
|
@@ -24681,6 +25005,52 @@ ${JSON.stringify(receipt)}`);
|
|
|
24681
25005
|
);
|
|
24682
25006
|
}
|
|
24683
25007
|
}),
|
|
25008
|
+
defineTool({
|
|
25009
|
+
name: "delete_task",
|
|
25010
|
+
description: "\u5C06\u4EFB\u52A1\u79FB\u5165\u9879\u76EE\u56DE\u6536\u7AD9\uFF0C\u91CA\u653E\u7F16\u53F7\u4F9B\u65B0\u4EFB\u52A1\u590D\u7528\u3002\u5B50\u4EFB\u52A1\u4FDD\u7559\u5E76\u63D0\u5347\u4E3A\u6839\u4EFB\u52A1\uFF0C\u4F9D\u8D56\u5173\u7CFB\u79FB\u9664\uFF1B\u8BC4\u8BBA\u3001\u8BF4\u660E\u7248\u672C\u548C\u4EA4\u4ED8\u4FDD\u7559\u3002\u4ECD\u88AB\u9886\u53D6\u65F6\u987B\u5148\u91CA\u653E\u3002\u6309\u6388\u6743\u76F4\u63A5\u6267\u884C\u6216\u63D0\u4EA4\u5BA1\u6279\u3002",
|
|
25011
|
+
inputSchema: { task: external_exports.string().describe("\u4EFB\u52A1\u7F16\u53F7\u6216 UUID") },
|
|
25012
|
+
async handler(args) {
|
|
25013
|
+
const task = await resolveTaskRef(args.task);
|
|
25014
|
+
return reportWrite("\u4EFB\u52A1\u5DF2\u79FB\u5165\u9879\u76EE\u56DE\u6536\u7AD9", await client.task.delete.mutate({ taskId: task.id }));
|
|
25015
|
+
}
|
|
25016
|
+
}),
|
|
25017
|
+
defineTool({
|
|
25018
|
+
name: "list_recycled_tasks",
|
|
25019
|
+
description: "\u5206\u9875\u67E5\u770B\u9879\u76EE\u56DE\u6536\u7AD9\u3002formerKey \u4EC5\u4E3A\u5386\u53F2\u7F16\u53F7\uFF0C\u53EF\u80FD\u5DF2\u88AB\u590D\u7528\uFF1B\u6062\u590D\u3001\u5F7B\u5E95\u5220\u9664\u5FC5\u987B\u4F7F\u7528\u8FD4\u56DE\u7684\u4EFB\u52A1 UUID\u3002",
|
|
25020
|
+
inputSchema: { project: external_exports.string(), limit: external_exports.number().int().min(1).max(100).optional(), offset: external_exports.number().int().min(0).optional() },
|
|
25021
|
+
async handler(args) {
|
|
25022
|
+
const project = await resolveProject(args.project);
|
|
25023
|
+
const offset = args.offset ?? 0;
|
|
25024
|
+
const limit = args.limit ?? 50;
|
|
25025
|
+
const items = await client.task.recycle.query({ projectId: project.id, offset, limit });
|
|
25026
|
+
return json({ items, nextOffset: items.length === limit ? offset + limit : null });
|
|
25027
|
+
}
|
|
25028
|
+
}),
|
|
25029
|
+
defineTool({
|
|
25030
|
+
name: "restore_task",
|
|
25031
|
+
description: "\u6062\u590D\u56DE\u6536\u7AD9\u4EFB\u52A1\uFF0CUUID \u548C\u5386\u53F2\u5185\u5BB9\u4E0D\u53D8\uFF0C\u4F46\u5206\u914D\u6700\u65B0\u9012\u589E\u7F16\u53F7\u3002\u4E0D\u4F1A\u6062\u590D\u7236\u5B50\u5173\u7CFB\u6216\u4F9D\u8D56\u8FB9\u3002\u6309\u6388\u6743\u76F4\u63A5\u6267\u884C\u6216\u63D0\u4EA4\u5BA1\u6279\u3002",
|
|
25032
|
+
inputSchema: { task_id: external_exports.string().uuid().describe("\u56DE\u6536\u7AD9\u91CC\u7684 UUID\uFF0C\u4E0D\u53EF\u4F7F\u7528\u5DF2\u91CA\u653E\u7684\u65E7\u7F16\u53F7") },
|
|
25033
|
+
async handler(args) {
|
|
25034
|
+
return reportWrite("\u4EFB\u52A1\u5DF2\u6062\u590D\u5E76\u5206\u914D\u65B0\u7F16\u53F7", await client.task.restore.mutate({ taskId: args.task_id }));
|
|
25035
|
+
}
|
|
25036
|
+
}),
|
|
25037
|
+
defineTool({
|
|
25038
|
+
name: "purge_task",
|
|
25039
|
+
description: "\u4E0D\u53EF\u9006\u5730\u5F7B\u5E95\u5220\u9664\u56DE\u6536\u7AD9\u4EFB\u52A1\u53CA\u8BC4\u8BBA\u3001\u8BF4\u660E\u7248\u672C\u548C\u4EA4\u4ED8\u3002\u4EC5\u7BA1\u7406\u5458\u6216\u7ECF\u5176\u660E\u786E\u6388\u6743\u7684 Agent \u53EF\u7528\uFF1B\u4FDD\u7559\u5BA1\u8BA1\u4E8B\u4EF6\u53CA\u8FD0\u884C\u6210\u672C\u8BB0\u5F55\u3002\u5FC5\u987B\u660E\u786E\u786E\u8BA4\u3002",
|
|
25040
|
+
inputSchema: { task_id: external_exports.string().uuid(), confirm: external_exports.literal(true).describe("\u660E\u786E\u786E\u8BA4\u4E0D\u53EF\u6062\u590D") },
|
|
25041
|
+
async handler(args) {
|
|
25042
|
+
return reportWrite("\u56DE\u6536\u7AD9\u4EFB\u52A1\u5DF2\u5F7B\u5E95\u5220\u9664\uFF0C\u4E0D\u53EF\u6062\u590D", await client.task.purge.mutate({ taskId: args.task_id, confirm: args.confirm }));
|
|
25043
|
+
}
|
|
25044
|
+
}),
|
|
25045
|
+
defineTool({
|
|
25046
|
+
name: "list_task_templates",
|
|
25047
|
+
description: "\u5217\u51FA\u9879\u76EE\u53EF\u7528\u7684\u4EFB\u52A1\u6A21\u677F\uFF0C\u8FD4\u56DE\u6A21\u677F ID\u3001\u8BF4\u660E\u3001\u9A8C\u6536\u6807\u51C6\u548C\u9ED8\u8BA4\u5C5E\u6027\uFF1Bcreate_task \u4F7F\u7528 template_id \u5E94\u7528\u6A21\u677F\u3002",
|
|
25048
|
+
inputSchema: { project: external_exports.string().describe("\u9879\u76EE key\u3001uuid \u6216\u540D\u5B57") },
|
|
25049
|
+
async handler(args) {
|
|
25050
|
+
const project = await resolveProject(args.project);
|
|
25051
|
+
return json(await client.taskTemplate.list.query({ projectId: project.id }));
|
|
25052
|
+
}
|
|
25053
|
+
}),
|
|
24684
25054
|
defineTool({
|
|
24685
25055
|
name: "get_task",
|
|
24686
25056
|
description: "\u5B8C\u6574\u8BCA\u65AD\u8BFB\u53D6\uFF08full profile\uFF09\uFF1A\u63CF\u8FF0\u3001\u9A8C\u6536\u6807\u51C6\u3001\u72B6\u6001\u3001\u6307\u6D3E\u4EBA\u3001\u8BC4\u8BBA\u3001\u7236\u5B50\u5C42\u7EA7\u3001\u4F9D\u8D56\u5173\u7CFB\u3001\u6240\u5728\u51B2\u523A\uFF08\u542B\u8FD9\u4E00\u8F6E\u7684\u76EE\u6807\u548C\u622A\u6B62\uFF09\u3001\u5386\u53F2\u4E8B\u4EF6\u3001\u72B6\u6001\u53D8\u66F4\u8BB0\u5F55\uFF08statusHistory\uFF1A\u8C01\u3001\u4EC0\u4E48\u65F6\u5019\u3001\u4ECE\u4EC0\u4E48\u72B6\u6001\u6539\u6210\u4EC0\u4E48\u72B6\u6001\uFF0C\u4EBA\u548C Agent \u90FD\u5728\uFF09\u3001\u4EE5\u53CA\u5DF2\u7ECF\u5728\u5B83\u4E0A\u9762\u8DD1\u8FC7\u7684 Agent \u8FD0\u884C\u3002\u65E5\u5E38\u6267\u884C\u4F18\u5148\u7528 get_task_context\u3002",
|
|
@@ -24688,7 +25058,8 @@ ${JSON.stringify(receipt)}`);
|
|
|
24688
25058
|
task: external_exports.string().describe("\u4EFB\u52A1\u7F16\u53F7\uFF08\u5982 MOM-12\uFF09\u6216 uuid")
|
|
24689
25059
|
},
|
|
24690
25060
|
async handler(args) {
|
|
24691
|
-
|
|
25061
|
+
const task = await resolveTask(args.task);
|
|
25062
|
+
return json({ ...task, links: linksFor(task.key) });
|
|
24692
25063
|
}
|
|
24693
25064
|
}),
|
|
24694
25065
|
defineTool({
|
|
@@ -24697,6 +25068,7 @@ ${JSON.stringify(receipt)}`);
|
|
|
24697
25068
|
inputSchema: {
|
|
24698
25069
|
title: external_exports.string().min(1).max(500),
|
|
24699
25070
|
project: external_exports.string().optional().describe("\u9879\u76EE key\u3001uuid \u6216\u540D\u5B57"),
|
|
25071
|
+
template_id: external_exports.string().uuid().optional().describe("\u9879\u76EE\u4EFB\u52A1\u6A21\u677F ID\uFF0C\u53EF\u901A\u8FC7 list_task_templates \u9009\u62E9"),
|
|
24700
25072
|
description: markdownSchema.optional(),
|
|
24701
25073
|
acceptance: acceptanceSchema.optional(),
|
|
24702
25074
|
plan: external_exports.object({
|
|
@@ -24720,6 +25092,7 @@ ${JSON.stringify(receipt)}`);
|
|
|
24720
25092
|
title: args.title,
|
|
24721
25093
|
descriptionMd: args.description,
|
|
24722
25094
|
acceptance: args.acceptance,
|
|
25095
|
+
templateId: args.template_id,
|
|
24723
25096
|
agentPlan: args.plan ? { notesMd: args.plan.notes, verification: args.plan.verification, refs: args.plan.refs } : void 0,
|
|
24724
25097
|
type: args.type ?? "task",
|
|
24725
25098
|
priority: args.priority ?? 0,
|
|
@@ -24740,7 +25113,7 @@ ${JSON.stringify(receipt)}`);
|
|
|
24740
25113
|
const task = await resolveTask(args.task);
|
|
24741
25114
|
const parent = args.parent ? await resolveTask(args.parent) : null;
|
|
24742
25115
|
if (task.parentId === parent?.id || !task.parentId && !parent) {
|
|
24743
|
-
return
|
|
25116
|
+
return unchanged(`${task.key} \u5DF2\u7ECF\u5904\u4E8E\u8FD9\u4E2A\u5C42\u7EA7\uFF0C\u65E0\u9700\u6539\u52A8\u3002`);
|
|
24744
25117
|
}
|
|
24745
25118
|
const res = await client.task.reparent.mutate({
|
|
24746
25119
|
taskId: task.id,
|
|
@@ -24748,7 +25121,8 @@ ${JSON.stringify(receipt)}`);
|
|
|
24748
25121
|
});
|
|
24749
25122
|
return reportWrite(
|
|
24750
25123
|
parent ? `\u5DF2\u628A ${task.key} \u6302\u5230 ${parent.key} \u4E0B` : `\u5DF2\u628A ${task.key} \u63D0\u5347\u4E3A\u6839\u4EFB\u52A1`,
|
|
24751
|
-
res
|
|
25124
|
+
res,
|
|
25125
|
+
task.key
|
|
24752
25126
|
);
|
|
24753
25127
|
}
|
|
24754
25128
|
}),
|
|
@@ -24762,7 +25136,7 @@ ${JSON.stringify(receipt)}`);
|
|
|
24762
25136
|
},
|
|
24763
25137
|
async handler(args) {
|
|
24764
25138
|
const { task, related, res } = await changeRelation("add", args);
|
|
24765
|
-
return reportWrite(`\u5DF2\u4E3A ${task.key} \u548C ${related.key} \u6DFB\u52A0 ${args.kind} \u5173\u7CFB`, res);
|
|
25139
|
+
return reportWrite(`\u5DF2\u4E3A ${task.key} \u548C ${related.key} \u6DFB\u52A0 ${args.kind} \u5173\u7CFB`, res, task.key);
|
|
24766
25140
|
}
|
|
24767
25141
|
}),
|
|
24768
25142
|
defineTool({
|
|
@@ -24771,7 +25145,7 @@ ${JSON.stringify(receipt)}`);
|
|
|
24771
25145
|
inputSchema: { task: external_exports.string(), related: external_exports.string(), kind: RELATION_KIND },
|
|
24772
25146
|
async handler(args) {
|
|
24773
25147
|
const { task, related, res } = await changeRelation("remove", args);
|
|
24774
|
-
return reportWrite(`\u5DF2\u79FB\u9664 ${task.key} \u548C ${related.key} \u7684 ${args.kind} \u5173\u7CFB`, res);
|
|
25148
|
+
return reportWrite(`\u5DF2\u79FB\u9664 ${task.key} \u548C ${related.key} \u7684 ${args.kind} \u5173\u7CFB`, res, task.key);
|
|
24775
25149
|
}
|
|
24776
25150
|
}),
|
|
24777
25151
|
defineTool({
|
|
@@ -24793,7 +25167,7 @@ ${JSON.stringify(receipt)}`);
|
|
|
24793
25167
|
);
|
|
24794
25168
|
}
|
|
24795
25169
|
if (target.id === task.status.id) {
|
|
24796
|
-
return
|
|
25170
|
+
return unchanged(`\u4EFB\u52A1 ${task.key} \u5DF2\u7ECF\u5728\u300C${target.name}\u300D\uFF0C\u65E0\u9700\u6539\u52A8\u3002`);
|
|
24797
25171
|
}
|
|
24798
25172
|
const res = await client.task.transition.mutate({
|
|
24799
25173
|
taskId: task.id,
|
|
@@ -24801,7 +25175,8 @@ ${JSON.stringify(receipt)}`);
|
|
|
24801
25175
|
});
|
|
24802
25176
|
return reportWrite(
|
|
24803
25177
|
`${task.key} \u5DF2\u4ECE\u300C${task.status.name}\u300D\u79FB\u5230\u300C${target.name}\u300D`,
|
|
24804
|
-
res
|
|
25178
|
+
res,
|
|
25179
|
+
task.key
|
|
24805
25180
|
);
|
|
24806
25181
|
}
|
|
24807
25182
|
}),
|
|
@@ -24818,7 +25193,7 @@ ${JSON.stringify(receipt)}`);
|
|
|
24818
25193
|
taskId: task.id,
|
|
24819
25194
|
body: { type: "text", text: args.body }
|
|
24820
25195
|
});
|
|
24821
|
-
return reportWrite(`\u5DF2\u5728 ${task.key} \u4E0B\u7559\u8A00`, res);
|
|
25196
|
+
return reportWrite(`\u5DF2\u5728 ${task.key} \u4E0B\u7559\u8A00`, res, task.key);
|
|
24822
25197
|
}
|
|
24823
25198
|
}),
|
|
24824
25199
|
defineTool({
|
|
@@ -24908,7 +25283,7 @@ ${JSON.stringify(receipt)}`);
|
|
|
24908
25283
|
if (res.status === "executed") {
|
|
24909
25284
|
trackRun(res.result.runId, task?.id ?? null);
|
|
24910
25285
|
}
|
|
24911
|
-
return reportWrite("\u5DF2\u5F00\u59CB\u8BB0\u5F55\u672C\u6B21\u8FD0\u884C\uFF1B\u672C\u8FDB\u7A0B\u4F1A\u81EA\u52A8\u5FC3\u8DF3\u7EED\u7EA6", res);
|
|
25286
|
+
return reportWrite("\u5DF2\u5F00\u59CB\u8BB0\u5F55\u672C\u6B21\u8FD0\u884C\uFF1B\u672C\u8FDB\u7A0B\u4F1A\u81EA\u52A8\u5FC3\u8DF3\u7EED\u7EA6", res, task?.key);
|
|
24912
25287
|
}
|
|
24913
25288
|
}),
|
|
24914
25289
|
defineTool({
|
|
@@ -24944,24 +25319,31 @@ ${JSON.stringify(receipt)}`);
|
|
|
24944
25319
|
})
|
|
24945
25320
|
];
|
|
24946
25321
|
const selected = profile === "work" ? tools.filter((tool) => WORK_TOOL_NAMES.has(tool.name)) : tools;
|
|
24947
|
-
return selected.map((tool) =>
|
|
24948
|
-
|
|
24949
|
-
|
|
24950
|
-
|
|
24951
|
-
|
|
24952
|
-
|
|
24953
|
-
|
|
24954
|
-
|
|
24955
|
-
|
|
24956
|
-
|
|
24957
|
-
|
|
25322
|
+
return selected.map((tool) => {
|
|
25323
|
+
const meta = TOOL_META[tool.name];
|
|
25324
|
+
if (!meta) throw new Error(`\u5DE5\u5177 ${tool.name} \u6CA1\u6709\u767B\u8BB0\u8BFB\u5199\u6CE8\u89E3\uFF08TOOL_META\uFF09`);
|
|
25325
|
+
return wrap({ ...tool, ...meta });
|
|
25326
|
+
});
|
|
25327
|
+
function wrap(tool) {
|
|
25328
|
+
return {
|
|
25329
|
+
...tool,
|
|
25330
|
+
handler: async (args, meta) => {
|
|
25331
|
+
reported.record(meta);
|
|
25332
|
+
const argBytes = byteLength(JSON.stringify(args ?? {}));
|
|
25333
|
+
const charged = meters.beginCall(argBytes);
|
|
25334
|
+
let result;
|
|
25335
|
+
try {
|
|
25336
|
+
result = await tool.handler(args);
|
|
25337
|
+
} catch (err) {
|
|
25338
|
+
result = { content: [{ type: "text", text: explain(err) }], isError: true };
|
|
25339
|
+
}
|
|
25340
|
+
const notices = heartbeats.drainNotices();
|
|
25341
|
+
const final = notices.length === 0 ? result : { ...result, content: [...result.content, { type: "text", text: notices.join("\n") }] };
|
|
25342
|
+
meters.endCall(charged, argBytes, final.content.reduce((n, c) => n + byteLength(c.text), 0));
|
|
25343
|
+
return final;
|
|
24958
25344
|
}
|
|
24959
|
-
|
|
24960
|
-
|
|
24961
|
-
meters.endCall(charged, argBytes, final.content.reduce((n, c) => n + byteLength(c.text), 0));
|
|
24962
|
-
return final;
|
|
24963
|
-
}
|
|
24964
|
-
}));
|
|
25345
|
+
};
|
|
25346
|
+
}
|
|
24965
25347
|
}
|
|
24966
25348
|
function planLimitOf(err) {
|
|
24967
25349
|
const data = err?.data;
|
|
@@ -25008,6 +25390,7 @@ var SERVER_INSTRUCTIONS = [
|
|
|
25008
25390
|
"Momentum \u662F\u8FD9\u4E2A\u56E2\u961F\u7684\u9879\u76EE\u7BA1\u7406\u7CFB\u7EDF\uFF0C\u4EBA\u548C Agent \u7684\u5DE5\u4F5C\u90FD\u8BB0\u5728\u8FD9\u91CC\u3002",
|
|
25009
25391
|
"\u62FF\u5230\u4EFB\u52A1\u7F16\u53F7\u5C31\u76F4\u63A5 begin_task\uFF1A\u89E3\u6790\u3001\u5F00\u8FD0\u884C\u3001\u9886\u53D6\u3001\u8BFB\u7D27\u51D1\u4E0A\u4E0B\u6587\u4E00\u6B65\u5B8C\u6210\uFF0C",
|
|
25010
25392
|
"\u4E0D\u5FC5\u5148 whoami / list_tasks / get_task\u3002\u5FC3\u8DF3\u7531\u672C\u8FDB\u7A0B\u81EA\u52A8\u5B8C\u6210\uFF0C\u4E0D\u7528\u624B\u52A8\u7EED\u7EA6\u3002",
|
|
25393
|
+
"\u4E0D\u77E5\u9053\u7F16\u53F7\u65F6\u7528 browse_tasks \u627E\uFF08\u53EA\u8BFB\uFF0C\u4E0D\u9886\u53D6\uFF09\uFF1B\u9009\u5B9A\u540E\u518D begin_task\u3002",
|
|
25011
25394
|
"\u505A\u5B8C\u8C03 finish_task_work\uFF1A\u4E00\u6B21\u63D0\u4EA4\u4EA4\u4ED8\u3001\u79FB\u5230\u8BC4\u5BA1\u3001\u7ED3\u675F\u8FD0\u884C\u5E76\u5982\u5B9E\u4E0A\u62A5\u6210\u672C\u3002",
|
|
25012
25395
|
"\u8FDB\u5C55\u548C\u5361\u70B9\u7528 comment_on_task \u5199\u4E0B\u6765\uFF0C\u5199\u77ED\uFF1A\u5148\u7ED3\u8BBA\u3001\u518D\u8981\u70B9\uFF0C\u5173\u952E\u8282\u70B9\u4E00\u6761\u5C31\u591F\u3002",
|
|
25013
25396
|
"\u7F3A\u4FE1\u606F\u5148\u770B\u7528\u6237\u5728\u4E0D\u5728\uFF1A\u6B63\u548C\u4F60\u5BF9\u8BDD\u5C31\u76F4\u63A5\u95EE\u7528\u6237\uFF1B\u7528\u6237\u7B54\u4E0D\u4E86\u3001\u8981\u56E2\u961F\u62CD\u677F\u7684\u624D\u7528 ask_question\u3002",
|
|
@@ -25030,7 +25413,14 @@ function createMcpServer(client, profile = "work", options = {}) {
|
|
|
25030
25413
|
for (const tool of createTools(client, profile, options)) {
|
|
25031
25414
|
server.registerTool(
|
|
25032
25415
|
tool.name,
|
|
25033
|
-
{
|
|
25416
|
+
{
|
|
25417
|
+
description: tool.description,
|
|
25418
|
+
inputSchema: tool.inputSchema,
|
|
25419
|
+
// 注解让客户端知道哪些是只读查询(不必弹确认);outputSchema 让它能校验并渲染
|
|
25420
|
+
// structuredContent,而不是从文本里猜(IMMO-222)
|
|
25421
|
+
annotations: tool.annotations,
|
|
25422
|
+
...tool.outputSchema ? { outputSchema: tool.outputSchema } : {}
|
|
25423
|
+
},
|
|
25034
25424
|
// SDK 会先按 inputSchema 校验再调进来,这里的形状转换是安全的。
|
|
25035
25425
|
// extra._meta 是请求 params._meta,宿主可以在里面上报用量(IMMO-215)
|
|
25036
25426
|
(args, extra) => tool.handler(args, extra._meta)
|
|
@@ -25087,7 +25477,8 @@ async function main() {
|
|
|
25087
25477
|
log(` \u26A0 MOMENTUM_TOOL_PROFILE=${configuredProfile} \u65E0\u6548\uFF0C\u4F7F\u7528 work\uFF08\u53EF\u9009\uFF1Awork / full\uFF09`);
|
|
25088
25478
|
}
|
|
25089
25479
|
const profile = configuredProfile === "full" ? "full" : "work";
|
|
25090
|
-
const
|
|
25480
|
+
const appUrl = process.env.MOMENTUM_APP_URL || url;
|
|
25481
|
+
const server = createMcpServer(client, profile, { log, appUrl });
|
|
25091
25482
|
await server.connect(new StdioServerTransport());
|
|
25092
25483
|
await greet(url);
|
|
25093
25484
|
}
|