@costgate/momentum-mcp 0.1.35 → 0.1.37
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 +358 -87
- 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.1.
|
|
12
|
+
默认用 `@latest`,发新版不用改配置;想固定某一版时把 latest 换成版本号(当前是 0.1.37)。
|
|
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.1.
|
|
21
|
+
版本 0.1.37。客户端和服务端版本不一致时,启动日志(stderr)会明确警告。
|
package/momentum-mcp.mjs
CHANGED
|
@@ -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.1.
|
|
15342
|
+
var MCP_VERSION = true ? "0.1.37" : versionFromRepo();
|
|
15343
15343
|
var CLIENT_HEADER = `momentum-mcp/${MCP_VERSION}`;
|
|
15344
15344
|
function compareVersions(a, b) {
|
|
15345
15345
|
const parse4 = (v) => {
|
|
@@ -23877,7 +23877,100 @@ function defineTool(tool) {
|
|
|
23877
23877
|
var text = (body) => ({
|
|
23878
23878
|
content: [{ type: "text", text: body }]
|
|
23879
23879
|
});
|
|
23880
|
-
var json = (value) =>
|
|
23880
|
+
var json = (value) => {
|
|
23881
|
+
const body = JSON.stringify(value);
|
|
23882
|
+
const plain = JSON.parse(body);
|
|
23883
|
+
return {
|
|
23884
|
+
...text(body),
|
|
23885
|
+
structuredContent: plain !== null && typeof plain === "object" && !Array.isArray(plain) ? plain : { items: plain }
|
|
23886
|
+
};
|
|
23887
|
+
};
|
|
23888
|
+
var TASK_PATH = (key) => `/t/${key}`;
|
|
23889
|
+
var APPROVALS_PATH = "/review";
|
|
23890
|
+
var LINKS_SCHEMA = external_exports.record(external_exports.string());
|
|
23891
|
+
var WRITE_OUTPUT = external_exports.object({
|
|
23892
|
+
status: external_exports.enum(["executed", "pending_approval", "unchanged"]),
|
|
23893
|
+
message: external_exports.string(),
|
|
23894
|
+
proposalId: external_exports.string().optional(),
|
|
23895
|
+
links: LINKS_SCHEMA.optional()
|
|
23896
|
+
}).passthrough();
|
|
23897
|
+
var STEP_SCHEMA = external_exports.object({ status: external_exports.enum(["executed", "pending_approval", "failed", "skipped"]), message: external_exports.string() }).passthrough();
|
|
23898
|
+
var FINISH_OUTPUT = external_exports.object({
|
|
23899
|
+
status: external_exports.enum(["executed", "pending_approval", "partial"]),
|
|
23900
|
+
message: external_exports.string(),
|
|
23901
|
+
steps: external_exports.record(STEP_SCHEMA),
|
|
23902
|
+
links: LINKS_SCHEMA.optional()
|
|
23903
|
+
}).passthrough();
|
|
23904
|
+
var TASK_FIELDS = { key: external_exports.string(), title: external_exports.string() };
|
|
23905
|
+
var CONTEXT_SCHEMA = external_exports.object({
|
|
23906
|
+
...TASK_FIELDS,
|
|
23907
|
+
status: external_exports.object({ name: external_exports.string(), category: external_exports.string() }).passthrough(),
|
|
23908
|
+
links: LINKS_SCHEMA.optional()
|
|
23909
|
+
}).passthrough();
|
|
23910
|
+
var BEGIN_OUTPUT = external_exports.object({
|
|
23911
|
+
status: external_exports.enum(["executed", "pending_approval"]),
|
|
23912
|
+
runId: external_exports.string().optional(),
|
|
23913
|
+
claim: external_exports.object({ status: external_exports.string() }).passthrough().optional(),
|
|
23914
|
+
context: CONTEXT_SCHEMA.optional(),
|
|
23915
|
+
proposalId: external_exports.string().optional()
|
|
23916
|
+
}).passthrough();
|
|
23917
|
+
var PAGE_OUTPUT = external_exports.object({ items: external_exports.array(external_exports.unknown()) }).passthrough();
|
|
23918
|
+
var TASKS_OUTPUT = external_exports.object({ items: external_exports.array(external_exports.object(TASK_FIELDS).passthrough()) }).passthrough();
|
|
23919
|
+
var BROWSE_OUTCOME = external_exports.enum(["ok", "no_projects", "no_match", "project_unavailable", "failed"]);
|
|
23920
|
+
var BROWSE_OUTPUT = external_exports.object({
|
|
23921
|
+
outcome: BROWSE_OUTCOME,
|
|
23922
|
+
message: external_exports.string(),
|
|
23923
|
+
items: external_exports.array(external_exports.unknown()),
|
|
23924
|
+
nextOffset: external_exports.number().nullable()
|
|
23925
|
+
}).passthrough();
|
|
23926
|
+
var READ = { readOnlyHint: true, openWorldHint: false };
|
|
23927
|
+
var write = (destructiveHint, idempotentHint) => ({
|
|
23928
|
+
readOnlyHint: false,
|
|
23929
|
+
destructiveHint,
|
|
23930
|
+
idempotentHint
|
|
23931
|
+
});
|
|
23932
|
+
var TOOL_META = {
|
|
23933
|
+
// 只读查询 —— 客户端不该为它们弹确认
|
|
23934
|
+
get_task_context: { annotations: READ, outputSchema: CONTEXT_SCHEMA },
|
|
23935
|
+
get_task: { annotations: READ, outputSchema: CONTEXT_SCHEMA },
|
|
23936
|
+
get_task_spec: { annotations: READ },
|
|
23937
|
+
list_tasks: { annotations: READ, outputSchema: TASKS_OUTPUT },
|
|
23938
|
+
browse_tasks: { annotations: READ, outputSchema: BROWSE_OUTPUT },
|
|
23939
|
+
list_ready_tasks: { annotations: READ, outputSchema: TASKS_OUTPUT },
|
|
23940
|
+
list_projects: { annotations: READ, outputSchema: PAGE_OUTPUT },
|
|
23941
|
+
list_task_comments: { annotations: READ, outputSchema: PAGE_OUTPUT },
|
|
23942
|
+
list_task_deliveries: { annotations: READ, outputSchema: PAGE_OUTPUT },
|
|
23943
|
+
poll_events: { annotations: READ, outputSchema: PAGE_OUTPUT },
|
|
23944
|
+
current_cycle: { annotations: READ },
|
|
23945
|
+
whoami: { annotations: READ },
|
|
23946
|
+
// 开工 / 收尾:重复调用沿用同一次运行、交付按 idempotency_key 去重
|
|
23947
|
+
begin_task: { annotations: write(false, true), outputSchema: BEGIN_OUTPUT },
|
|
23948
|
+
finish_task_work: { annotations: write(false, true), outputSchema: FINISH_OUTPUT },
|
|
23949
|
+
// 追加型的写
|
|
23950
|
+
create_task: { annotations: write(false, false), outputSchema: WRITE_OUTPUT },
|
|
23951
|
+
comment_on_task: { annotations: write(false, false) },
|
|
23952
|
+
ask_question: { annotations: write(false, false) },
|
|
23953
|
+
answer_question: { annotations: write(false, false) },
|
|
23954
|
+
add_task_relation: { annotations: write(false, false) },
|
|
23955
|
+
update_task: { annotations: write(false, false) },
|
|
23956
|
+
propose_digest: { annotations: write(false, false) },
|
|
23957
|
+
submit_delivery: { annotations: write(false, true), outputSchema: WRITE_OUTPUT },
|
|
23958
|
+
review_delivery: { annotations: write(false, false), outputSchema: WRITE_OUTPUT },
|
|
23959
|
+
confirm_delivery: { annotations: write(false, false) },
|
|
23960
|
+
start_run: { annotations: write(false, false) },
|
|
23961
|
+
finish_run: { annotations: write(false, false) },
|
|
23962
|
+
heartbeat_run: { annotations: write(false, true) },
|
|
23963
|
+
claim_task: { annotations: write(false, true), outputSchema: WRITE_OUTPUT },
|
|
23964
|
+
claim_next_task: { annotations: write(false, false), outputSchema: WRITE_OUTPUT },
|
|
23965
|
+
// 改状态、挪位置、放手:改的是当前值,历史在事件流里留着
|
|
23966
|
+
update_task_status: { annotations: write(false, true), outputSchema: WRITE_OUTPUT },
|
|
23967
|
+
release_task: { annotations: write(false, false), outputSchema: WRITE_OUTPUT },
|
|
23968
|
+
set_task_parent: { annotations: write(false, true) },
|
|
23969
|
+
plan_task: { annotations: write(false, true) },
|
|
23970
|
+
// 覆盖或删除已有内容:notes / refs 整份替换,关系直接移除
|
|
23971
|
+
update_task_plan: { annotations: write(true, true) },
|
|
23972
|
+
remove_task_relation: { annotations: write(true, false) }
|
|
23973
|
+
};
|
|
23881
23974
|
var RECEIPT_KEYS = [
|
|
23882
23975
|
"id",
|
|
23883
23976
|
"key",
|
|
@@ -23915,30 +24008,28 @@ function compactReceipt(value) {
|
|
|
23915
24008
|
);
|
|
23916
24009
|
return Object.keys(receipt).length > 0 ? receipt : { ok: true };
|
|
23917
24010
|
}
|
|
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
|
-
}
|
|
24011
|
+
var unchanged = (message) => ({
|
|
24012
|
+
...text(message),
|
|
24013
|
+
structuredContent: { status: "unchanged", message }
|
|
24014
|
+
});
|
|
23932
24015
|
var RELATION_KIND = external_exports.enum(["blocks", "blocked_by", "relates", "duplicates"]);
|
|
23933
24016
|
var UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
23934
24017
|
function matchStatus(candidates, wanted) {
|
|
23935
24018
|
const needle = wanted.trim().toLowerCase();
|
|
23936
24019
|
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
24020
|
}
|
|
24021
|
+
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";
|
|
24022
|
+
var BROWSE_DEFAULT_LIMIT = 20;
|
|
24023
|
+
var BROWSE_MAX_LIMIT = 50;
|
|
24024
|
+
var BROWSE_MAX_PROJECTS = 50;
|
|
24025
|
+
var STATUS_CATEGORIES = ["backlog", "unstarted", "started", "blocked", "review", "done", "canceled"];
|
|
23938
24026
|
var WORK_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
23939
24027
|
"begin_task",
|
|
23940
24028
|
"finish_task_work",
|
|
23941
24029
|
"get_task_context",
|
|
24030
|
+
// 不知道任务编号时找活的入口(IMMO-221):只读、有界、只回摘要。list_projects / list_tasks
|
|
24031
|
+
// 仍在 full 档 —— 它们的 schema 更大,项目列表还带整段描述和冲刺配置
|
|
24032
|
+
"browse_tasks",
|
|
23942
24033
|
"get_task_spec",
|
|
23943
24034
|
"list_task_comments",
|
|
23944
24035
|
"list_task_deliveries",
|
|
@@ -23968,6 +24059,41 @@ function createTools(client, profile = "full", options = {}) {
|
|
|
23968
24059
|
const meters = new RunMeters();
|
|
23969
24060
|
const reported = options.hostReports ?? new HostReports(options.log);
|
|
23970
24061
|
const readUsage = options.readUsage ?? hostUsageReader(process.env, { log: options.log, reported });
|
|
24062
|
+
const appUrl = (options.appUrl ?? "").replace(/\/+$/, "");
|
|
24063
|
+
function linksFor(taskKey, pending = false) {
|
|
24064
|
+
return {
|
|
24065
|
+
...taskKey ? { task: `${appUrl}${TASK_PATH(taskKey)}` } : {},
|
|
24066
|
+
...pending ? { approvals: `${appUrl}${APPROVALS_PATH}` } : {}
|
|
24067
|
+
};
|
|
24068
|
+
}
|
|
24069
|
+
function reportWrite(done, res, taskKey) {
|
|
24070
|
+
if (res.status === "proposed") {
|
|
24071
|
+
const links = linksFor(taskKey, true);
|
|
24072
|
+
const message = [
|
|
24073
|
+
`\u23F8 \u8FD9\u4E2A\u52A8\u4F5C\u9700\u8981\u4EBA\u5DE5\u6279\u51C6\uFF0C**\u5C1A\u672A\u751F\u6548**\u3002`,
|
|
24074
|
+
`\u5DF2\u63D0\u4EA4\u63D0\u6848 ${res.proposalId}\uFF1A${res.summary}`,
|
|
24075
|
+
`\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`,
|
|
24076
|
+
`\u6279\u51C6\u5165\u53E3\uFF1A${links.approvals}`
|
|
24077
|
+
].join("\n");
|
|
24078
|
+
return {
|
|
24079
|
+
...text(message),
|
|
24080
|
+
structuredContent: { status: "pending_approval", message, proposalId: res.proposalId, summary: res.summary, links }
|
|
24081
|
+
};
|
|
24082
|
+
}
|
|
24083
|
+
const result = compactReceipt(res.result);
|
|
24084
|
+
const key = taskKey ?? result?.key;
|
|
24085
|
+
return {
|
|
24086
|
+
...text(`\u2713 ${done}
|
|
24087
|
+
|
|
24088
|
+
${JSON.stringify(result)}`),
|
|
24089
|
+
structuredContent: {
|
|
24090
|
+
status: "executed",
|
|
24091
|
+
message: done,
|
|
24092
|
+
result: JSON.parse(JSON.stringify(result)),
|
|
24093
|
+
links: linksFor(typeof key === "string" ? key : null)
|
|
24094
|
+
}
|
|
24095
|
+
};
|
|
24096
|
+
}
|
|
23971
24097
|
async function measured(runId) {
|
|
23972
24098
|
const meter = meters.get(runId);
|
|
23973
24099
|
if (!meter) return {};
|
|
@@ -23991,9 +24117,7 @@ function createTools(client, profile = "full", options = {}) {
|
|
|
23991
24117
|
const only = projects[0];
|
|
23992
24118
|
if (projects.length === 1 && only) return only;
|
|
23993
24119
|
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
|
-
);
|
|
24120
|
+
throw new Error(NO_PROJECTS_MESSAGE);
|
|
23997
24121
|
}
|
|
23998
24122
|
throw new Error(
|
|
23999
24123
|
`\u6709 ${projects.length} \u4E2A\u9879\u76EE\uFF0C\u8BF7\u7528 project \u53C2\u6570\u6307\u5B9A\uFF1A${projects.map((p) => p.key).join(", ")}`
|
|
@@ -24127,13 +24251,22 @@ ${options2}`
|
|
|
24127
24251
|
const statuses = await client.project.statuses.query({ projectId: task.projectId });
|
|
24128
24252
|
const target = matchStatus(statuses, wanted);
|
|
24129
24253
|
if (!target) {
|
|
24130
|
-
return
|
|
24254
|
+
return {
|
|
24255
|
+
status: "failed",
|
|
24256
|
+
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`
|
|
24257
|
+
};
|
|
24131
24258
|
}
|
|
24259
|
+
const column = { statusId: target.id, statusName: target.name, statusCategory: target.category };
|
|
24132
24260
|
try {
|
|
24133
24261
|
const res = await client.task.transition.mutate({ taskId: task.id, statusId: target.id });
|
|
24134
24262
|
if (res.status === "proposed") {
|
|
24135
24263
|
receipt.statusProposalId = res.proposalId;
|
|
24136
|
-
return
|
|
24264
|
+
return {
|
|
24265
|
+
status: "pending_approval",
|
|
24266
|
+
message: `\u23F8 \u79FB\u5230\u300C${target.name}\u300D\u9700\u8981\u4EBA\u5DE5\u6279\u51C6\uFF0C\u5C1A\u672A\u751F\u6548`,
|
|
24267
|
+
proposalId: res.proposalId,
|
|
24268
|
+
...column
|
|
24269
|
+
};
|
|
24137
24270
|
}
|
|
24138
24271
|
} catch (err) {
|
|
24139
24272
|
if (!(errorCode(err) === "CONFLICT" && err instanceof Error && err.message.includes("\u72B6\u6001\u672A\u53D1\u751F\u53D8\u5316"))) {
|
|
@@ -24141,27 +24274,41 @@ ${options2}`
|
|
|
24141
24274
|
}
|
|
24142
24275
|
}
|
|
24143
24276
|
receipt.status = target.name;
|
|
24144
|
-
return `\u2713 \u4EFB\u52A1\u5728\u300C${target.name}\u300D
|
|
24277
|
+
return { status: "executed", message: `\u2713 \u4EFB\u52A1\u5728\u300C${target.name}\u300D`, ...column };
|
|
24145
24278
|
} catch (err) {
|
|
24146
|
-
return `\u26A0 \u72B6\u6001\u672A\u6539\u3002${explain(err)}
|
|
24279
|
+
return { status: "failed", message: `\u26A0 \u72B6\u6001\u672A\u6539\u3002${explain(err)}` };
|
|
24147
24280
|
}
|
|
24148
24281
|
}
|
|
24149
24282
|
async function finishRunAfterDelivery(runId, input, receipt) {
|
|
24150
|
-
if (!runId)
|
|
24283
|
+
if (!runId) {
|
|
24284
|
+
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" };
|
|
24285
|
+
}
|
|
24151
24286
|
try {
|
|
24152
24287
|
const res = await client.run.finish.mutate({ runId, ...input, ...await measured(runId) });
|
|
24153
|
-
if (res.status === "proposed")
|
|
24288
|
+
if (res.status === "proposed") {
|
|
24289
|
+
return {
|
|
24290
|
+
status: "pending_approval",
|
|
24291
|
+
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",
|
|
24292
|
+
proposalId: res.proposalId,
|
|
24293
|
+
runId
|
|
24294
|
+
};
|
|
24295
|
+
}
|
|
24154
24296
|
forgetRun(runId);
|
|
24155
24297
|
Object.assign(receipt, { runId, runState: input.state });
|
|
24156
24298
|
const { releasedClaimOn } = res.result;
|
|
24157
|
-
return
|
|
24299
|
+
return {
|
|
24300
|
+
status: "executed",
|
|
24301
|
+
message: `\u2713 \u8FD0\u884C\u5DF2\u7ED3\u675F\uFF08${input.state}\uFF09${releasedClaimOn ? "\uFF0C\u9886\u53D6\u5DF2\u653E\u624B" : ""}`,
|
|
24302
|
+
runId,
|
|
24303
|
+
runState: input.state
|
|
24304
|
+
};
|
|
24158
24305
|
} catch (err) {
|
|
24159
24306
|
if (errorCode(err) === "CONFLICT") {
|
|
24160
24307
|
forgetRun(runId);
|
|
24161
24308
|
receipt.runId = runId;
|
|
24162
|
-
return "\u2713 \u8FD0\u884C\u6B64\u524D\u5DF2\u7ED3\u675F";
|
|
24309
|
+
return { status: "executed", message: "\u2713 \u8FD0\u884C\u6B64\u524D\u5DF2\u7ED3\u675F", runId };
|
|
24163
24310
|
}
|
|
24164
|
-
return `\u26A0 \u8FD0\u884C\u672A\u7ED3\u675F\uFF0C\u53EF\u7A0D\u540E\u7528 finish_run \u5355\u72EC\u7ED3\u675F\u3002${explain(err)}
|
|
24311
|
+
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
24312
|
}
|
|
24166
24313
|
}
|
|
24167
24314
|
const cursorSchema = external_exports.object({ createdAt: external_exports.string().datetime(), id: external_exports.string().uuid() });
|
|
@@ -24182,13 +24329,19 @@ ${options2}`
|
|
|
24182
24329
|
taskId: task.id,
|
|
24183
24330
|
trigger: { source: "mcp", tool: "begin_task", note: args.note ?? null }
|
|
24184
24331
|
});
|
|
24185
|
-
if (started.status === "proposed") return reportWrite("", started);
|
|
24332
|
+
if (started.status === "proposed") return reportWrite("", started, task.key);
|
|
24186
24333
|
runId = started.result.runId;
|
|
24187
24334
|
trackRun(runId, task.id);
|
|
24188
24335
|
}
|
|
24189
24336
|
const claim = await claimForRun(task.id, runId);
|
|
24190
24337
|
const context = await client.task.context.query({ taskId: task.id });
|
|
24191
|
-
return json({
|
|
24338
|
+
return json({
|
|
24339
|
+
status: "executed",
|
|
24340
|
+
runId,
|
|
24341
|
+
claim,
|
|
24342
|
+
context,
|
|
24343
|
+
links: linksFor(task.key, claim.status === "pending_approval")
|
|
24344
|
+
});
|
|
24192
24345
|
}
|
|
24193
24346
|
}),
|
|
24194
24347
|
defineTool({
|
|
@@ -24213,7 +24366,7 @@ ${options2}`
|
|
|
24213
24366
|
const task = await resolveTaskRef(args.task);
|
|
24214
24367
|
const runId = args.run_id ?? heartbeats.runFor(task.id);
|
|
24215
24368
|
const receipt = { key: task.key };
|
|
24216
|
-
|
|
24369
|
+
let delivery;
|
|
24217
24370
|
const delivered = await client.task.submitDelivery.mutate({
|
|
24218
24371
|
taskId: task.id,
|
|
24219
24372
|
basedOnSpecVersion: args.based_on_spec_version,
|
|
@@ -24227,30 +24380,47 @@ ${options2}`
|
|
|
24227
24380
|
});
|
|
24228
24381
|
if (delivered.status === "proposed") {
|
|
24229
24382
|
receipt.deliveryProposalId = delivered.proposalId;
|
|
24230
|
-
|
|
24383
|
+
delivery = {
|
|
24384
|
+
status: "pending_approval",
|
|
24385
|
+
message: `\u23F8 \u4EA4\u4ED8\u9700\u8981\u4EBA\u5DE5\u6279\u51C6\uFF0C\u5C1A\u672A\u751F\u6548\uFF08\u63D0\u6848 ${delivered.proposalId}\uFF09`,
|
|
24386
|
+
proposalId: delivered.proposalId
|
|
24387
|
+
};
|
|
24231
24388
|
} else {
|
|
24232
24389
|
const d = delivered.result;
|
|
24233
24390
|
Object.assign(receipt, { deliveryId: d.id, deliveryState: d.state }, d.outdated ? { outdated: true } : {});
|
|
24234
|
-
|
|
24235
|
-
|
|
24236
|
-
|
|
24237
|
-
|
|
24391
|
+
delivery = {
|
|
24392
|
+
status: "executed",
|
|
24393
|
+
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" : ""),
|
|
24394
|
+
deliveryId: d.id,
|
|
24395
|
+
deliveryState: d.state,
|
|
24396
|
+
replayed: d.replayed,
|
|
24397
|
+
outdated: d.outdated
|
|
24398
|
+
};
|
|
24238
24399
|
}
|
|
24239
|
-
|
|
24240
|
-
|
|
24241
|
-
|
|
24242
|
-
|
|
24243
|
-
|
|
24244
|
-
|
|
24245
|
-
|
|
24246
|
-
|
|
24247
|
-
|
|
24248
|
-
receipt
|
|
24249
|
-
)
|
|
24400
|
+
const transition = await moveAfterDelivery(task, args.status ?? "review", receipt);
|
|
24401
|
+
const run2 = await finishRunAfterDelivery(
|
|
24402
|
+
runId,
|
|
24403
|
+
{
|
|
24404
|
+
state: args.run_state ?? "succeeded",
|
|
24405
|
+
costUsd: args.cost_usd,
|
|
24406
|
+
transcriptUrl: args.transcript_url
|
|
24407
|
+
},
|
|
24408
|
+
receipt
|
|
24250
24409
|
);
|
|
24251
|
-
|
|
24410
|
+
const steps = [delivery, transition, run2];
|
|
24411
|
+
const pending = steps.some((s) => s.status === "pending_approval");
|
|
24412
|
+
const status = steps.some((s) => s.status === "failed" || s.status === "skipped") ? "partial" : pending ? "pending_approval" : "executed";
|
|
24413
|
+
const links = linksFor(task.key, pending);
|
|
24414
|
+
const message = [
|
|
24415
|
+
...steps.map((s) => s.message),
|
|
24416
|
+
...links.approvals ? [`\u6279\u51C6\u5165\u53E3\uFF1A${links.approvals}`] : []
|
|
24417
|
+
].join("\n");
|
|
24418
|
+
return {
|
|
24419
|
+
...text(`${message}
|
|
24252
24420
|
|
|
24253
|
-
${JSON.stringify(receipt)}`)
|
|
24421
|
+
${JSON.stringify(receipt)}`),
|
|
24422
|
+
structuredContent: { status, message, steps: { delivery, transition, run: run2 }, result: { ...receipt }, links }
|
|
24423
|
+
};
|
|
24254
24424
|
}
|
|
24255
24425
|
}),
|
|
24256
24426
|
defineTool({
|
|
@@ -24269,7 +24439,10 @@ ${JSON.stringify(receipt)}`);
|
|
|
24269
24439
|
limit: args.limit
|
|
24270
24440
|
});
|
|
24271
24441
|
if (items.length === 0) {
|
|
24272
|
-
return
|
|
24442
|
+
return {
|
|
24443
|
+
...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"),
|
|
24444
|
+
structuredContent: { items: [] }
|
|
24445
|
+
};
|
|
24273
24446
|
}
|
|
24274
24447
|
return json(items);
|
|
24275
24448
|
}
|
|
@@ -24301,7 +24474,7 @@ ${JSON.stringify(receipt)}`);
|
|
|
24301
24474
|
);
|
|
24302
24475
|
} catch (err) {
|
|
24303
24476
|
if (err instanceof Error && err.message.includes("\u6CA1\u6709\u53EF\u63A5\u7684\u6D3B")) {
|
|
24304
|
-
return
|
|
24477
|
+
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
24478
|
}
|
|
24306
24479
|
if (err instanceof Error && err.message.includes("\u4E0D\u5C5E\u4E8E\u4EFB\u4F55\u9879\u76EE") && projects) {
|
|
24307
24480
|
throw new Error(
|
|
@@ -24330,7 +24503,7 @@ ${JSON.stringify(receipt)}`);
|
|
|
24330
24503
|
if (res.status === "executed" && args.run_id && heartbeats.has(args.run_id)) {
|
|
24331
24504
|
heartbeats.track(args.run_id, task.id, true);
|
|
24332
24505
|
}
|
|
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);
|
|
24506
|
+
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
24507
|
}
|
|
24335
24508
|
}),
|
|
24336
24509
|
defineTool({
|
|
@@ -24341,7 +24514,8 @@ ${JSON.stringify(receipt)}`);
|
|
|
24341
24514
|
const task = await resolveTaskRef(args.task);
|
|
24342
24515
|
return reportWrite(
|
|
24343
24516
|
`\u5DF2\u91CA\u653E ${task.key}`,
|
|
24344
|
-
await client.task.release.mutate({ taskId: task.id, reason: args.reason })
|
|
24517
|
+
await client.task.release.mutate({ taskId: task.id, reason: args.reason }),
|
|
24518
|
+
task.key
|
|
24345
24519
|
);
|
|
24346
24520
|
}
|
|
24347
24521
|
}),
|
|
@@ -24394,7 +24568,7 @@ ${JSON.stringify(receipt)}`);
|
|
|
24394
24568
|
inputSchema: { task: external_exports.string() },
|
|
24395
24569
|
async handler(args) {
|
|
24396
24570
|
const task = await resolveTaskRef(args.task);
|
|
24397
|
-
return json(await client.task.context.query({ taskId: task.id }));
|
|
24571
|
+
return json({ ...await client.task.context.query({ taskId: task.id }), links: linksFor(task.key) });
|
|
24398
24572
|
}
|
|
24399
24573
|
}),
|
|
24400
24574
|
defineTool({
|
|
@@ -24413,7 +24587,7 @@ ${JSON.stringify(receipt)}`);
|
|
|
24413
24587
|
notesMd: args.notes,
|
|
24414
24588
|
verification: args.verification,
|
|
24415
24589
|
refs: args.refs
|
|
24416
|
-
}));
|
|
24590
|
+
}), task.key);
|
|
24417
24591
|
}
|
|
24418
24592
|
}),
|
|
24419
24593
|
defineTool({
|
|
@@ -24436,7 +24610,7 @@ ${JSON.stringify(receipt)}`);
|
|
|
24436
24610
|
descriptionMd: args.description,
|
|
24437
24611
|
acceptance: args.acceptance,
|
|
24438
24612
|
changeSummary: args.change_summary
|
|
24439
|
-
}));
|
|
24613
|
+
}), task.key);
|
|
24440
24614
|
}
|
|
24441
24615
|
}),
|
|
24442
24616
|
defineTool({
|
|
@@ -24500,7 +24674,7 @@ ${JSON.stringify(receipt)}`);
|
|
|
24500
24674
|
results: args.results,
|
|
24501
24675
|
remainingWork: args.remaining_work,
|
|
24502
24676
|
handoff: args.handoff
|
|
24503
|
-
}));
|
|
24677
|
+
}), task.key);
|
|
24504
24678
|
}
|
|
24505
24679
|
}),
|
|
24506
24680
|
defineTool({
|
|
@@ -24543,7 +24717,7 @@ ${JSON.stringify(receipt)}`);
|
|
|
24543
24717
|
taskId: task.id,
|
|
24544
24718
|
body: args.question,
|
|
24545
24719
|
blocking: args.blocking ?? false
|
|
24546
|
-
}));
|
|
24720
|
+
}), task.key);
|
|
24547
24721
|
}
|
|
24548
24722
|
}),
|
|
24549
24723
|
defineTool({
|
|
@@ -24594,7 +24768,7 @@ ${JSON.stringify(receipt)}`);
|
|
|
24594
24768
|
acceptance: spec.acceptance,
|
|
24595
24769
|
changeSummary: spec.change_summary
|
|
24596
24770
|
} : void 0
|
|
24597
|
-
}));
|
|
24771
|
+
}), task.key);
|
|
24598
24772
|
}
|
|
24599
24773
|
}),
|
|
24600
24774
|
defineTool({
|
|
@@ -24616,6 +24790,84 @@ ${JSON.stringify(receipt)}`);
|
|
|
24616
24790
|
});
|
|
24617
24791
|
}
|
|
24618
24792
|
}),
|
|
24793
|
+
defineTool({
|
|
24794
|
+
name: "browse_tasks",
|
|
24795
|
+
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",
|
|
24796
|
+
inputSchema: {
|
|
24797
|
+
project: external_exports.string().optional().describe("key \u6216\u540D\u5B57\uFF0C\u4E0D\u4F20 = \u5168\u90E8"),
|
|
24798
|
+
mine: external_exports.boolean().optional().describe("\u53EA\u770B\u6307\u6D3E\u7ED9\u6211\u7684"),
|
|
24799
|
+
status: external_exports.array(external_exports.enum(STATUS_CATEGORIES)).optional().describe("\u72B6\u6001\u5927\u7C7B"),
|
|
24800
|
+
query: external_exports.string().max(200).optional().describe("\u5173\u952E\u8BCD"),
|
|
24801
|
+
// 上限写在这里而不是 describe 里:schema 的 maximum 模型看得见,也真的拦得住
|
|
24802
|
+
limit: external_exports.number().int().min(1).max(BROWSE_MAX_LIMIT).optional(),
|
|
24803
|
+
offset: external_exports.number().int().min(0).optional()
|
|
24804
|
+
},
|
|
24805
|
+
async handler(args) {
|
|
24806
|
+
const limit = args.limit ?? BROWSE_DEFAULT_LIMIT;
|
|
24807
|
+
const offset = args.offset ?? 0;
|
|
24808
|
+
const stop = (outcome, message, isError2) => ({
|
|
24809
|
+
...text(message),
|
|
24810
|
+
structuredContent: { outcome, message, items: [], nextOffset: null },
|
|
24811
|
+
...isError2 ? { isError: isError2 } : {}
|
|
24812
|
+
});
|
|
24813
|
+
const failed = (err) => stop("failed", `${explain(err)}
|
|
24814
|
+
|
|
24815
|
+
\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);
|
|
24816
|
+
let projects;
|
|
24817
|
+
try {
|
|
24818
|
+
projects = await client.project.list.query();
|
|
24819
|
+
} catch (err) {
|
|
24820
|
+
return failed(err);
|
|
24821
|
+
}
|
|
24822
|
+
if (projects.length === 0) return stop("no_projects", NO_PROJECTS_MESSAGE, false);
|
|
24823
|
+
let project;
|
|
24824
|
+
if (args.project) {
|
|
24825
|
+
const ref = args.project;
|
|
24826
|
+
project = projects.find(
|
|
24827
|
+
(p) => p.id === ref || p.key.toLowerCase() === ref.toLowerCase() || p.name === ref
|
|
24828
|
+
);
|
|
24829
|
+
if (!project) {
|
|
24830
|
+
return stop("project_unavailable", `\u5931\u8D25\uFF1A${(await missingProjectError(ref, projects)).message}`, true);
|
|
24831
|
+
}
|
|
24832
|
+
}
|
|
24833
|
+
let rows;
|
|
24834
|
+
try {
|
|
24835
|
+
const assigneeId = args.mine ? (await client.viewer.me.query())?.actorId ?? void 0 : void 0;
|
|
24836
|
+
rows = await client.task.list.query({
|
|
24837
|
+
projectId: project?.id,
|
|
24838
|
+
categories: args.status,
|
|
24839
|
+
assigneeId,
|
|
24840
|
+
query: args.query,
|
|
24841
|
+
limit: limit + 1,
|
|
24842
|
+
offset
|
|
24843
|
+
});
|
|
24844
|
+
} catch (err) {
|
|
24845
|
+
return failed(err);
|
|
24846
|
+
}
|
|
24847
|
+
const page = rows.slice(0, limit);
|
|
24848
|
+
const items = page.map((t) => ({
|
|
24849
|
+
key: t.key,
|
|
24850
|
+
title: t.title,
|
|
24851
|
+
type: t.type,
|
|
24852
|
+
priority: t.priority,
|
|
24853
|
+
status: { name: t.status.name, category: t.status.category },
|
|
24854
|
+
assignee: t.assignee ? { name: t.assignee.name, kind: t.assignee.kind } : null,
|
|
24855
|
+
updatedAt: t.updatedAt
|
|
24856
|
+
}));
|
|
24857
|
+
const empty = items.length === 0;
|
|
24858
|
+
return json({
|
|
24859
|
+
outcome: empty ? "no_match" : "ok",
|
|
24860
|
+
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`,
|
|
24861
|
+
items,
|
|
24862
|
+
nextOffset: rows.length > limit ? offset + limit : null,
|
|
24863
|
+
// 第一页带上可选项目,客户端好做项目筛选;翻页时不重复
|
|
24864
|
+
...offset === 0 ? {
|
|
24865
|
+
projects: projects.slice(0, BROWSE_MAX_PROJECTS).map((p) => ({ key: p.key, name: p.name })),
|
|
24866
|
+
...projects.length > BROWSE_MAX_PROJECTS ? { projectsTruncated: true } : {}
|
|
24867
|
+
} : {}
|
|
24868
|
+
});
|
|
24869
|
+
}
|
|
24870
|
+
}),
|
|
24619
24871
|
defineTool({
|
|
24620
24872
|
name: "list_projects",
|
|
24621
24873
|
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",
|
|
@@ -24688,7 +24940,8 @@ ${JSON.stringify(receipt)}`);
|
|
|
24688
24940
|
task: external_exports.string().describe("\u4EFB\u52A1\u7F16\u53F7\uFF08\u5982 MOM-12\uFF09\u6216 uuid")
|
|
24689
24941
|
},
|
|
24690
24942
|
async handler(args) {
|
|
24691
|
-
|
|
24943
|
+
const task = await resolveTask(args.task);
|
|
24944
|
+
return json({ ...task, links: linksFor(task.key) });
|
|
24692
24945
|
}
|
|
24693
24946
|
}),
|
|
24694
24947
|
defineTool({
|
|
@@ -24740,7 +24993,7 @@ ${JSON.stringify(receipt)}`);
|
|
|
24740
24993
|
const task = await resolveTask(args.task);
|
|
24741
24994
|
const parent = args.parent ? await resolveTask(args.parent) : null;
|
|
24742
24995
|
if (task.parentId === parent?.id || !task.parentId && !parent) {
|
|
24743
|
-
return
|
|
24996
|
+
return unchanged(`${task.key} \u5DF2\u7ECF\u5904\u4E8E\u8FD9\u4E2A\u5C42\u7EA7\uFF0C\u65E0\u9700\u6539\u52A8\u3002`);
|
|
24744
24997
|
}
|
|
24745
24998
|
const res = await client.task.reparent.mutate({
|
|
24746
24999
|
taskId: task.id,
|
|
@@ -24748,7 +25001,8 @@ ${JSON.stringify(receipt)}`);
|
|
|
24748
25001
|
});
|
|
24749
25002
|
return reportWrite(
|
|
24750
25003
|
parent ? `\u5DF2\u628A ${task.key} \u6302\u5230 ${parent.key} \u4E0B` : `\u5DF2\u628A ${task.key} \u63D0\u5347\u4E3A\u6839\u4EFB\u52A1`,
|
|
24751
|
-
res
|
|
25004
|
+
res,
|
|
25005
|
+
task.key
|
|
24752
25006
|
);
|
|
24753
25007
|
}
|
|
24754
25008
|
}),
|
|
@@ -24762,7 +25016,7 @@ ${JSON.stringify(receipt)}`);
|
|
|
24762
25016
|
},
|
|
24763
25017
|
async handler(args) {
|
|
24764
25018
|
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);
|
|
25019
|
+
return reportWrite(`\u5DF2\u4E3A ${task.key} \u548C ${related.key} \u6DFB\u52A0 ${args.kind} \u5173\u7CFB`, res, task.key);
|
|
24766
25020
|
}
|
|
24767
25021
|
}),
|
|
24768
25022
|
defineTool({
|
|
@@ -24771,7 +25025,7 @@ ${JSON.stringify(receipt)}`);
|
|
|
24771
25025
|
inputSchema: { task: external_exports.string(), related: external_exports.string(), kind: RELATION_KIND },
|
|
24772
25026
|
async handler(args) {
|
|
24773
25027
|
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);
|
|
25028
|
+
return reportWrite(`\u5DF2\u79FB\u9664 ${task.key} \u548C ${related.key} \u7684 ${args.kind} \u5173\u7CFB`, res, task.key);
|
|
24775
25029
|
}
|
|
24776
25030
|
}),
|
|
24777
25031
|
defineTool({
|
|
@@ -24793,7 +25047,7 @@ ${JSON.stringify(receipt)}`);
|
|
|
24793
25047
|
);
|
|
24794
25048
|
}
|
|
24795
25049
|
if (target.id === task.status.id) {
|
|
24796
|
-
return
|
|
25050
|
+
return unchanged(`\u4EFB\u52A1 ${task.key} \u5DF2\u7ECF\u5728\u300C${target.name}\u300D\uFF0C\u65E0\u9700\u6539\u52A8\u3002`);
|
|
24797
25051
|
}
|
|
24798
25052
|
const res = await client.task.transition.mutate({
|
|
24799
25053
|
taskId: task.id,
|
|
@@ -24801,7 +25055,8 @@ ${JSON.stringify(receipt)}`);
|
|
|
24801
25055
|
});
|
|
24802
25056
|
return reportWrite(
|
|
24803
25057
|
`${task.key} \u5DF2\u4ECE\u300C${task.status.name}\u300D\u79FB\u5230\u300C${target.name}\u300D`,
|
|
24804
|
-
res
|
|
25058
|
+
res,
|
|
25059
|
+
task.key
|
|
24805
25060
|
);
|
|
24806
25061
|
}
|
|
24807
25062
|
}),
|
|
@@ -24818,7 +25073,7 @@ ${JSON.stringify(receipt)}`);
|
|
|
24818
25073
|
taskId: task.id,
|
|
24819
25074
|
body: { type: "text", text: args.body }
|
|
24820
25075
|
});
|
|
24821
|
-
return reportWrite(`\u5DF2\u5728 ${task.key} \u4E0B\u7559\u8A00`, res);
|
|
25076
|
+
return reportWrite(`\u5DF2\u5728 ${task.key} \u4E0B\u7559\u8A00`, res, task.key);
|
|
24822
25077
|
}
|
|
24823
25078
|
}),
|
|
24824
25079
|
defineTool({
|
|
@@ -24908,7 +25163,7 @@ ${JSON.stringify(receipt)}`);
|
|
|
24908
25163
|
if (res.status === "executed") {
|
|
24909
25164
|
trackRun(res.result.runId, task?.id ?? null);
|
|
24910
25165
|
}
|
|
24911
|
-
return reportWrite("\u5DF2\u5F00\u59CB\u8BB0\u5F55\u672C\u6B21\u8FD0\u884C\uFF1B\u672C\u8FDB\u7A0B\u4F1A\u81EA\u52A8\u5FC3\u8DF3\u7EED\u7EA6", res);
|
|
25166
|
+
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
25167
|
}
|
|
24913
25168
|
}),
|
|
24914
25169
|
defineTool({
|
|
@@ -24944,24 +25199,31 @@ ${JSON.stringify(receipt)}`);
|
|
|
24944
25199
|
})
|
|
24945
25200
|
];
|
|
24946
25201
|
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
|
-
|
|
25202
|
+
return selected.map((tool) => {
|
|
25203
|
+
const meta = TOOL_META[tool.name];
|
|
25204
|
+
if (!meta) throw new Error(`\u5DE5\u5177 ${tool.name} \u6CA1\u6709\u767B\u8BB0\u8BFB\u5199\u6CE8\u89E3\uFF08TOOL_META\uFF09`);
|
|
25205
|
+
return wrap({ ...tool, ...meta });
|
|
25206
|
+
});
|
|
25207
|
+
function wrap(tool) {
|
|
25208
|
+
return {
|
|
25209
|
+
...tool,
|
|
25210
|
+
handler: async (args, meta) => {
|
|
25211
|
+
reported.record(meta);
|
|
25212
|
+
const argBytes = byteLength(JSON.stringify(args ?? {}));
|
|
25213
|
+
const charged = meters.beginCall(argBytes);
|
|
25214
|
+
let result;
|
|
25215
|
+
try {
|
|
25216
|
+
result = await tool.handler(args);
|
|
25217
|
+
} catch (err) {
|
|
25218
|
+
result = { content: [{ type: "text", text: explain(err) }], isError: true };
|
|
25219
|
+
}
|
|
25220
|
+
const notices = heartbeats.drainNotices();
|
|
25221
|
+
const final = notices.length === 0 ? result : { ...result, content: [...result.content, { type: "text", text: notices.join("\n") }] };
|
|
25222
|
+
meters.endCall(charged, argBytes, final.content.reduce((n, c) => n + byteLength(c.text), 0));
|
|
25223
|
+
return final;
|
|
24958
25224
|
}
|
|
24959
|
-
|
|
24960
|
-
|
|
24961
|
-
meters.endCall(charged, argBytes, final.content.reduce((n, c) => n + byteLength(c.text), 0));
|
|
24962
|
-
return final;
|
|
24963
|
-
}
|
|
24964
|
-
}));
|
|
25225
|
+
};
|
|
25226
|
+
}
|
|
24965
25227
|
}
|
|
24966
25228
|
function planLimitOf(err) {
|
|
24967
25229
|
const data = err?.data;
|
|
@@ -25008,6 +25270,7 @@ var SERVER_INSTRUCTIONS = [
|
|
|
25008
25270
|
"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
25271
|
"\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
25272
|
"\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",
|
|
25273
|
+
"\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
25274
|
"\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
25275
|
"\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
25276
|
"\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 +25293,14 @@ function createMcpServer(client, profile = "work", options = {}) {
|
|
|
25030
25293
|
for (const tool of createTools(client, profile, options)) {
|
|
25031
25294
|
server.registerTool(
|
|
25032
25295
|
tool.name,
|
|
25033
|
-
{
|
|
25296
|
+
{
|
|
25297
|
+
description: tool.description,
|
|
25298
|
+
inputSchema: tool.inputSchema,
|
|
25299
|
+
// 注解让客户端知道哪些是只读查询(不必弹确认);outputSchema 让它能校验并渲染
|
|
25300
|
+
// structuredContent,而不是从文本里猜(IMMO-222)
|
|
25301
|
+
annotations: tool.annotations,
|
|
25302
|
+
...tool.outputSchema ? { outputSchema: tool.outputSchema } : {}
|
|
25303
|
+
},
|
|
25034
25304
|
// SDK 会先按 inputSchema 校验再调进来,这里的形状转换是安全的。
|
|
25035
25305
|
// extra._meta 是请求 params._meta,宿主可以在里面上报用量(IMMO-215)
|
|
25036
25306
|
(args, extra) => tool.handler(args, extra._meta)
|
|
@@ -25087,7 +25357,8 @@ async function main() {
|
|
|
25087
25357
|
log(` \u26A0 MOMENTUM_TOOL_PROFILE=${configuredProfile} \u65E0\u6548\uFF0C\u4F7F\u7528 work\uFF08\u53EF\u9009\uFF1Awork / full\uFF09`);
|
|
25088
25358
|
}
|
|
25089
25359
|
const profile = configuredProfile === "full" ? "full" : "work";
|
|
25090
|
-
const
|
|
25360
|
+
const appUrl = process.env.MOMENTUM_APP_URL || url;
|
|
25361
|
+
const server = createMcpServer(client, profile, { log, appUrl });
|
|
25091
25362
|
await server.connect(new StdioServerTransport());
|
|
25092
25363
|
await greet(url);
|
|
25093
25364
|
}
|