@shaohui_jin/git-cockpit-mcp-server 0.1.15 → 0.1.17
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 +25 -2
- package/dist/{chunk-4LUNMJTB.js → chunk-I7QFIFI2.js} +195 -8
- package/dist/chunk-I7QFIFI2.js.map +1 -0
- package/dist/{chunk-Q3ZIYY54.js → chunk-NSG4PZRX.js} +3 -3
- package/dist/{chunk-7ZLJEU2E.js → chunk-XNW2ZKY3.js} +21 -6
- package/dist/chunk-XNW2ZKY3.js.map +1 -0
- package/dist/cli-entry.js +3 -3
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +3 -3
- package/dist/index.d.ts +29 -3
- package/dist/index.js +5 -3
- package/dist/mcpServer.d.ts +1 -1
- package/dist/mcpServer.js +1 -1
- package/dist/{runtime-B0PyJ-YT.d.ts → runtime-CtZr-J1V.d.ts} +3 -2
- package/dist/web/assets/index-CcuMDi_Q.js +345 -0
- package/dist/web/assets/{index-CcBjvlvI.css → index-DcQxEG_7.css} +1 -1
- package/dist/web/index.html +2 -2
- package/dist/webServer.d.ts +1 -1
- package/dist/webServer.js +2 -2
- package/package.json +2 -2
- package/dist/chunk-4LUNMJTB.js.map +0 -1
- package/dist/chunk-7ZLJEU2E.js.map +0 -1
- package/dist/web/assets/index-BUkraY9q.js +0 -344
- /package/dist/{chunk-Q3ZIYY54.js.map → chunk-NSG4PZRX.js.map} +0 -0
package/README.md
CHANGED
|
@@ -42,6 +42,29 @@ git-cockpit version # 输出版本号
|
|
|
42
42
|
}
|
|
43
43
|
```
|
|
44
44
|
|
|
45
|
+
网页和聊天窗口要一起用时,改跑 `git-cockpit start`,客户端连 `http://localhost:3000/mcp`。不要再开一个 `git-cockpit mcp` 抢同一仓。
|
|
46
|
+
|
|
47
|
+
**不要**和 Git Insight(或其它会直接改同一仓的 Git MCP)同时用于同一个仓库。
|
|
48
|
+
|
|
49
|
+
### Agent 该怎么用
|
|
50
|
+
|
|
51
|
+
和仓库根 [README.md](../../README.md) 同一套,这里再写一遍(npm 包装的人看不到仓库根文档):
|
|
52
|
+
|
|
53
|
+
**1. 提交** — 先看改了什么,再暂存、再提交。写之前先 `dry_run=true`。
|
|
54
|
+
`git_status` → `git_diff` → 按需 `git_add` → `git_commit`。
|
|
55
|
+
|
|
56
|
+
**2. 合不合得进去,以及写进仓库** — 先看工作区是不是已经卡在 merge / rebase 里(卡住了走第 3 条)。问能不能合时只做预演,不要在当前目录 merge。`into` 是线上目标,`from` 是你的分支。人选边,模型不要自动选。写进仓库用独立目录落盘(`git_apply_resolve`),不要用 `git_merge` 冒充预演。
|
|
57
|
+
|
|
58
|
+
**3. 工作区已经卡在 merge 或 rebase 里** — 看状态,然后继续或放弃。不要用第 2 条的落盘去收尾。
|
|
59
|
+
`git_status` → `git_merge_continue` / `git_rebase_continue` 或 abort。禁止 `git_apply_resolve`。
|
|
60
|
+
|
|
61
|
+
**4. 开 Pull Request / Merge Request** — 先准备信息再创建。Token 在网页设置里,不要塞进工具参数。
|
|
62
|
+
`git_mr_prepare` → `git_mr_create`。
|
|
63
|
+
|
|
64
|
+
宿主可插入这四条 Prompt(`safe_commit` / `merge_preview_apply` / `workspace_continue` / `open_mr`),正文即上面四段。只读状态也可读 Resource:`git-cockpit://repos`、`git-cockpit://repo/current`、`git-cockpit://jobs`、`git-cockpit://jobs/{id}`。
|
|
65
|
+
|
|
66
|
+
默认只给摘要;要某文件正文加 `path` 或 `detail=true`。
|
|
67
|
+
|
|
45
68
|
### 环境变量
|
|
46
69
|
|
|
47
70
|
| 变量 | 说明 | 默认 |
|
|
@@ -55,13 +78,13 @@ git-cockpit version # 输出版本号
|
|
|
55
78
|
- **多仓库管理**:统一打开/移除仓库,跨仓库操作
|
|
56
79
|
- **安全机制**:工具按风险分级(readonly / write / dangerous),写操作 dry-run 预览 → 确认 → 执行;高危操作可配置人工审批
|
|
57
80
|
- **MCP 默认摘要**:`git_diff` / `git_show` / `git_merge_rehearse` 默认不回完整正文;要正文请加 `path` 或 `detail=true`(网页 GET 仍是全文)
|
|
58
|
-
- **内置 Web UI**:工作台 / 状态 /
|
|
81
|
+
- **内置 Web UI**:工作台 / 状态 / 合并 / 任务 / 操作日志 / 设置,支持提交、分支、stash、pull/push、硬重置等操作
|
|
59
82
|
- **审计日志**:所有工具调用记录落库,可回溯
|
|
60
83
|
- **备份**:高危操作前自动备份分支引用与 stash 快照
|
|
61
84
|
|
|
62
85
|
## 发布说明(维护者)
|
|
63
86
|
|
|
64
|
-
版本号维护在 `packages/mcp-server/package.json`,发布由仓库根目录 `.github/workflows/release-mcp-server.yml
|
|
87
|
+
版本号维护在 `packages/mcp-server/package.json`,发布由仓库根目录 `.github/workflows/release.yml` 的 `release-mcp-server` job 负责(不是历史上的 `release-mcp-server.yml`):
|
|
65
88
|
|
|
66
89
|
- **判据**:远程不存在 `mcp-server-v{version}` tag 才发布
|
|
67
90
|
- **流程**:构建 web → 构建 mcp-server(`prepublishOnly` 自动把 web/dist 内嵌进 `dist/web`)→ `pnpm publish` → 成功后才推送 tag `mcp-server-v{version}`
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
// src/mcpServer.ts
|
|
4
4
|
import { randomUUID } from "crypto";
|
|
5
|
-
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
5
|
+
import { McpServer as McpServer2 } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
6
6
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
7
7
|
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
8
8
|
|
|
9
9
|
// package.json
|
|
10
|
-
var version = "0.1.
|
|
10
|
+
var version = "0.1.17";
|
|
11
11
|
|
|
12
12
|
// src/tools/handlers.ts
|
|
13
13
|
import { z } from "zod";
|
|
@@ -72,6 +72,20 @@ function summarizeForAgent(tool, result, args = {}) {
|
|
|
72
72
|
if (detail2 || pathSet) return result;
|
|
73
73
|
return stripRehearseBodies(result);
|
|
74
74
|
}
|
|
75
|
+
if (tool === "git_repo_overview") {
|
|
76
|
+
if (detail2) return result;
|
|
77
|
+
const row = asRecord(result);
|
|
78
|
+
const repos = Array.isArray(row?.repos) ? row.repos : [];
|
|
79
|
+
return {
|
|
80
|
+
...row,
|
|
81
|
+
repos: repos.map((item) => {
|
|
82
|
+
const rec = asRecord(item);
|
|
83
|
+
if (!rec) return item;
|
|
84
|
+
const { activity: _days, ...rest } = rec;
|
|
85
|
+
return rest;
|
|
86
|
+
})
|
|
87
|
+
};
|
|
88
|
+
}
|
|
75
89
|
if (tool === "git_file_content") {
|
|
76
90
|
if (detail2) return result;
|
|
77
91
|
const row = asRecord(result);
|
|
@@ -219,6 +233,7 @@ import {
|
|
|
219
233
|
} from "@shaohui_jin/git-cockpit-core";
|
|
220
234
|
|
|
221
235
|
// src/overview.ts
|
|
236
|
+
import { emptyActivity } from "@shaohui_jin/git-cockpit-core";
|
|
222
237
|
var CONCURRENCY = 4;
|
|
223
238
|
function unavailableOverview(path, extra = {}) {
|
|
224
239
|
const name = path.replace(/[\\/]+$/, "").split(/[\\/]/).pop() || path;
|
|
@@ -234,6 +249,7 @@ function unavailableOverview(path, extra = {}) {
|
|
|
234
249
|
conflictCount: 0,
|
|
235
250
|
operation: "none",
|
|
236
251
|
tempMergeBranchCount: 0,
|
|
252
|
+
...emptyActivity(),
|
|
237
253
|
...extra
|
|
238
254
|
};
|
|
239
255
|
}
|
|
@@ -437,7 +453,7 @@ var GitStashShowSchema = z2.object({
|
|
|
437
453
|
maxPatchBytes: z2.number().int().positive().optional().describe("diff \u6B63\u6587\u6700\u5927\u5B57\u8282\u6570\uFF0C\u8D85\u51FA\u622A\u65AD"),
|
|
438
454
|
detail
|
|
439
455
|
});
|
|
440
|
-
var GitRepoOverviewSchema = z2.object({ ...readonlyBase });
|
|
456
|
+
var GitRepoOverviewSchema = z2.object({ ...readonlyBase, detail });
|
|
441
457
|
var GitJobListSchema = z2.object({ ...readonlyBase });
|
|
442
458
|
var GitJobGetSchema = z2.object({
|
|
443
459
|
...readonlyBase,
|
|
@@ -726,7 +742,7 @@ var TOOL_DEFS = [
|
|
|
726
742
|
},
|
|
727
743
|
{
|
|
728
744
|
name: "git_repo_overview",
|
|
729
|
-
description: "\u5DF2\u6253\u5F00\u4ED3\u5E93\u8109\u640F\uFF1A\u5206\u652F\u3001\u810F\u6587\u4EF6\u6570\u3001ahead/behind\u3001\u5DE5\u4F5C\u533A operation\u3001\u672C\u5730 merge/* \u6570\u3002\u4E0D\u56DE diff\u3002",
|
|
745
|
+
description: "\u5DF2\u6253\u5F00\u4ED3\u5E93\u8109\u640F\uFF1A\u5206\u652F\u3001\u810F\u6587\u4EF6\u6570\u3001ahead/behind\u3001\u5DE5\u4F5C\u533A operation\u3001\u672C\u5730 merge/* \u6570\u3001\u8FD1 12 \u5468\u63D0\u4EA4\u603B\u6570\u3002\u9ED8\u8BA4\u4E0D\u542B\u6BCF\u65E5\u683C\u5B50\uFF1Bdetail=true \u624D\u56DE activity[]\u3002\u4E0D\u56DE diff\u3002",
|
|
730
746
|
risk: "readonly",
|
|
731
747
|
needsRepo: false,
|
|
732
748
|
schema: GitRepoOverviewSchema,
|
|
@@ -1044,13 +1060,179 @@ function toolSummaries() {
|
|
|
1044
1060
|
return TOOL_DEFS.map((d) => ({ name: d.name, description: d.description }));
|
|
1045
1061
|
}
|
|
1046
1062
|
|
|
1063
|
+
// src/tools/prompts.ts
|
|
1064
|
+
var PREAMBLE = [
|
|
1065
|
+
"\u4E0D\u8981\u7528\u7EC8\u7AEF git \u4EE3\u66FF\u300C\u9884\u6F14\u3001\u843D\u76D8\u3001\u5F00 PR\u300D\u3002",
|
|
1066
|
+
"\u9ED8\u8BA4\u53EA\u7ED9\u6458\u8981\uFF1B\u8981\u770B\u67D0\u6587\u4EF6\u6B63\u6587\u65F6\u518D\u8BF4\u8DEF\u5F84\uFF0C\u6216\u52A0 `detail=true`\u3002\u5199\u64CD\u4F5C\u5148\u5E72\u8DD1\uFF08`dry_run=true`\uFF09\u3002\u9AD8\u98CE\u9669\u64CD\u4F5C\u9ED8\u8BA4\u5173\u7740\u3002"
|
|
1067
|
+
].join("\n");
|
|
1068
|
+
var MCP_PROMPTS = [
|
|
1069
|
+
{
|
|
1070
|
+
name: "safe_commit",
|
|
1071
|
+
title: "\u63D0\u4EA4",
|
|
1072
|
+
description: "\u5148\u770B\u6539\u4E86\u4EC0\u4E48\uFF0C\u518D\u6682\u5B58\u3001\u518D\u63D0\u4EA4\u3002\u4E0D\u8981\u4E00\u4E0A\u6765\u5C31\u63D0\u4EA4\u3002",
|
|
1073
|
+
text: [
|
|
1074
|
+
PREAMBLE,
|
|
1075
|
+
"",
|
|
1076
|
+
"1. \u63D0\u4EA4",
|
|
1077
|
+
"\u5148\u770B\u5DE5\u4F5C\u533A\u6709\u6CA1\u6709\u6539\u3001\u6539\u4E86\u4EC0\u4E48\uFF0C\u518D\u6682\u5B58\uFF0C\u518D\u63D0\u4EA4\u3002\u4E0D\u8981\u4E00\u4E0A\u6765\u5C31\u63D0\u4EA4\u3002",
|
|
1078
|
+
"",
|
|
1079
|
+
"\u5BF9\u5E94\u5DE5\u5177\uFF1A`git_status` \u2192 `git_diff` \u2192 \u6309\u9700 `git_add` \u2192 `git_commit`\u3002"
|
|
1080
|
+
].join("\n")
|
|
1081
|
+
},
|
|
1082
|
+
{
|
|
1083
|
+
name: "merge_preview_apply",
|
|
1084
|
+
title: "\u5408\u4E0D\u5408\u5F97\u8FDB\u53BB\uFF0C\u4EE5\u53CA\u5199\u8FDB\u4ED3\u5E93",
|
|
1085
|
+
description: "\u53EA\u505A\u9884\u6F14\uFF0C\u4EBA\u9009\u8FB9\uFF0C\u72EC\u7ACB\u76EE\u5F55\u843D\u76D8\u3002\u5DE5\u4F5C\u533A\u5DF2\u7ECF\u5361\u4F4F\u65F6\u4E0D\u8981\u8D70\u8FD9\u6761\u3002",
|
|
1086
|
+
text: [
|
|
1087
|
+
PREAMBLE,
|
|
1088
|
+
"",
|
|
1089
|
+
"2. \u5408\u4E0D\u5408\u5F97\u8FDB\u53BB\uFF0C\u4EE5\u53CA\u5199\u8FDB\u4ED3\u5E93",
|
|
1090
|
+
"\u5148\u770B\u5DE5\u4F5C\u533A\u662F\u4E0D\u662F\u5DF2\u7ECF\u5361\u5728 merge / rebase \u91CC\u3002\u5361\u4F4F\u4E86\u8D70\u300C\u5DE5\u4F5C\u533A\u5DF2\u7ECF\u5361\u5728 merge \u6216 rebase \u91CC\u300D\uFF0C\u4E0D\u8981\u8D70\u8FD9\u6761\u3002",
|
|
1091
|
+
"",
|
|
1092
|
+
"\u95EE\u80FD\u4E0D\u80FD\u5408\u8FDB\u53BB\u65F6\uFF0C\u53EA\u505A\u9884\u6F14\uFF0C\u4E0D\u8981\u5728\u5F53\u524D\u5DE5\u4F5C\u533A\u6267\u884C merge\u3002`into` \u662F\u8981\u5408\u8FDB\u53BB\u7684\u76EE\u6807\uFF08\u7EBF\u4E0A\uFF09\uFF0C`from` \u662F\u4F60\u7684\u5206\u652F\u3002\u6709\u51B2\u7A81\u65F6\u628A\u6B63\u6587\u7ED9\u4EBA\u770B\u3001\u4EBA\u9009\u8FB9\uFF0C\u4E0D\u8981\u8BA9\u6A21\u578B\u81EA\u52A8\u9009\u3002",
|
|
1093
|
+
"",
|
|
1094
|
+
"\u770B\u5B8C\u8981\u5199\u8FDB\u4ED3\u5E93\uFF1A\u7528\u72EC\u7ACB\u76EE\u5F55\u843D\u76D8\uFF0C\u4E0D\u8981\u5207\u8D70\u4F60\u6B63\u5728\u5E72\u6D3B\u7684\u5206\u652F\u3002",
|
|
1095
|
+
"",
|
|
1096
|
+
"\u5BF9\u5E94\u5DE5\u5177\uFF1A`git_merge_preview` / `git_merge_rehearse`\uFF08\u51B2\u7A81\u884C\u662F\u8C01\u6539\u7684\u7528 `git_merge_blame`\uFF09\u2192 `git_apply_resolve`\u3002\u7981\u6B62\u7528 `git_merge` \u5192\u5145\u9884\u6F14\u3002"
|
|
1097
|
+
].join("\n")
|
|
1098
|
+
},
|
|
1099
|
+
{
|
|
1100
|
+
name: "workspace_continue",
|
|
1101
|
+
title: "\u5DE5\u4F5C\u533A\u5DF2\u7ECF\u5361\u5728 merge \u6216 rebase \u91CC",
|
|
1102
|
+
description: "\u770B\u72B6\u6001\uFF0C\u7136\u540E\u7EE7\u7EED\u6216\u653E\u5F03\u3002\u4E0D\u8981\u7528\u9884\u6F14\u843D\u76D8\u53BB\u6536\u5C3E\u3002",
|
|
1103
|
+
text: [
|
|
1104
|
+
PREAMBLE,
|
|
1105
|
+
"",
|
|
1106
|
+
"3. \u5DE5\u4F5C\u533A\u5DF2\u7ECF\u5361\u5728 merge \u6216 rebase \u91CC",
|
|
1107
|
+
"\u8FD9\u662F\u53E6\u4E00\u56DE\u4E8B\uFF1A\u51B2\u7A81\u5DF2\u7ECF\u53D1\u751F\u5728\u5F53\u524D\u76EE\u5F55\u4E86\u3002\u770B\u72B6\u6001\uFF0C\u7136\u540E\u7EE7\u7EED\u6216\u653E\u5F03\u3002\u4E0D\u8981\u7528\u300C\u5408\u4E0D\u5408\u5F97\u8FDB\u53BB\uFF0C\u4EE5\u53CA\u5199\u8FDB\u4ED3\u5E93\u300D\u7684\u843D\u76D8\u53BB\u6536\u5C3E\u3002",
|
|
1108
|
+
"",
|
|
1109
|
+
"\u5BF9\u5E94\u5DE5\u5177\uFF1A`git_status`\uFF08\u770B `operation`\uFF09\u2192 `git_merge_continue` / `git_rebase_continue` \u6216 abort\u3002\u7981\u6B62\u7528 `git_apply_resolve`\u3002"
|
|
1110
|
+
].join("\n")
|
|
1111
|
+
},
|
|
1112
|
+
{
|
|
1113
|
+
name: "open_mr",
|
|
1114
|
+
title: "\u5F00 Pull Request / Merge Request",
|
|
1115
|
+
description: "\u5148\u51C6\u5907\u6807\u9898\u548C\u76EE\u6807\u5206\u652F\uFF0C\u518D\u521B\u5EFA\u3002Token \u5728\u7F51\u9875\u8BBE\u7F6E\u91CC\uFF0C\u4E0D\u8981\u585E\u8FDB\u5DE5\u5177\u53C2\u6570\u3002",
|
|
1116
|
+
text: [
|
|
1117
|
+
PREAMBLE,
|
|
1118
|
+
"",
|
|
1119
|
+
"4. \u5F00 Pull Request / Merge Request",
|
|
1120
|
+
"\u5148\u51C6\u5907\u6807\u9898\u548C\u76EE\u6807\u5206\u652F\u7B49\u4FE1\u606F\uFF0C\u518D\u521B\u5EFA\u3002\u767B\u5F55\u7528\u7684 Token \u5199\u5728\u7F51\u9875\u8BBE\u7F6E\u91CC\uFF0C\u4E0D\u8981\u585E\u8FDB\u5DE5\u5177\u53C2\u6570\u3002",
|
|
1121
|
+
"",
|
|
1122
|
+
"\u5BF9\u5E94\u5DE5\u5177\uFF1A`git_mr_prepare` \u2192 `git_mr_create`\u3002"
|
|
1123
|
+
].join("\n")
|
|
1124
|
+
}
|
|
1125
|
+
];
|
|
1126
|
+
function registerMcpPrompts(server) {
|
|
1127
|
+
const register = server.registerPrompt.bind(server);
|
|
1128
|
+
for (const p of MCP_PROMPTS) {
|
|
1129
|
+
register(p.name, { title: p.title, description: p.description }, () => ({
|
|
1130
|
+
description: p.description,
|
|
1131
|
+
messages: [{ role: "user", content: { type: "text", text: p.text } }]
|
|
1132
|
+
}));
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
// src/tools/resources.ts
|
|
1137
|
+
import { ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
1138
|
+
var MIME = "application/json";
|
|
1139
|
+
function jsonContents(uri, data) {
|
|
1140
|
+
return {
|
|
1141
|
+
contents: [
|
|
1142
|
+
{
|
|
1143
|
+
uri,
|
|
1144
|
+
mimeType: MIME,
|
|
1145
|
+
text: JSON.stringify(data)
|
|
1146
|
+
}
|
|
1147
|
+
]
|
|
1148
|
+
};
|
|
1149
|
+
}
|
|
1150
|
+
function overviewWithoutDays(runtime) {
|
|
1151
|
+
return collectRepoOverviews(runtime).then(
|
|
1152
|
+
(repos) => repos.map((row) => {
|
|
1153
|
+
const { activity: _days, ...rest } = row;
|
|
1154
|
+
return rest;
|
|
1155
|
+
})
|
|
1156
|
+
);
|
|
1157
|
+
}
|
|
1158
|
+
function registerMcpResources(server, runtime) {
|
|
1159
|
+
const register = server.registerResource.bind(server);
|
|
1160
|
+
register(
|
|
1161
|
+
"repos",
|
|
1162
|
+
"git-cockpit://repos",
|
|
1163
|
+
{ title: "\u5DF2\u6253\u5F00\u4ED3\u5E93\u8109\u640F", description: "\u4E0E git_repo_overview \u540C\u6458\u8981\uFF0C\u4E0D\u542B\u6BCF\u65E5\u683C\u5B50", mimeType: MIME },
|
|
1164
|
+
async (uri) => jsonContents(uri.href, { repos: await overviewWithoutDays(runtime) })
|
|
1165
|
+
);
|
|
1166
|
+
register(
|
|
1167
|
+
"repo-current",
|
|
1168
|
+
"git-cockpit://repo/current",
|
|
1169
|
+
{ title: "\u6700\u8FD1\u6253\u5F00\u4ED3", description: "\u6700\u8FD1\u6253\u5F00\u4ED3\u5E93\u7684\u5DE5\u4F5C\u533A\u6458\u8981\uFF0C\u4E0D\u542B\u6587\u4EF6\u5217\u8868\u6B63\u6587", mimeType: MIME },
|
|
1170
|
+
async (uri) => {
|
|
1171
|
+
const handle = await runtime.repoManager.getCurrent();
|
|
1172
|
+
if (!handle) {
|
|
1173
|
+
return jsonContents(uri.href, { available: false, hint: "\u6CA1\u6709\u5DF2\u6253\u5F00\u7684\u4ED3\u5E93" });
|
|
1174
|
+
}
|
|
1175
|
+
const s = await handle.service.getStatus();
|
|
1176
|
+
return jsonContents(uri.href, {
|
|
1177
|
+
available: true,
|
|
1178
|
+
path: handle.record.path,
|
|
1179
|
+
current: s.current,
|
|
1180
|
+
tracking: s.tracking,
|
|
1181
|
+
ahead: s.ahead,
|
|
1182
|
+
behind: s.behind,
|
|
1183
|
+
operation: s.operation,
|
|
1184
|
+
isClean: s.isClean,
|
|
1185
|
+
stagedCount: s.staged.length,
|
|
1186
|
+
unstagedCount: s.unstaged.length,
|
|
1187
|
+
untrackedCount: s.untracked.length,
|
|
1188
|
+
conflictCount: s.conflicted.length,
|
|
1189
|
+
conflicted: s.conflicted.slice(0, 20)
|
|
1190
|
+
});
|
|
1191
|
+
}
|
|
1192
|
+
);
|
|
1193
|
+
register(
|
|
1194
|
+
"jobs",
|
|
1195
|
+
"git-cockpit://jobs",
|
|
1196
|
+
{ title: "\u540E\u53F0\u4EFB\u52A1\u5217\u8868", description: "\u4E0E git_job_list \u540C\u6458\u8981", mimeType: MIME },
|
|
1197
|
+
async (uri) => jsonContents(uri.href, {
|
|
1198
|
+
jobs: runtime.jobs.list().map((j) => runtime.jobs.summary(j))
|
|
1199
|
+
})
|
|
1200
|
+
);
|
|
1201
|
+
register(
|
|
1202
|
+
"job",
|
|
1203
|
+
new ResourceTemplate("git-cockpit://jobs/{id}", {
|
|
1204
|
+
list: async () => ({
|
|
1205
|
+
resources: runtime.jobs.list().map((j) => ({
|
|
1206
|
+
uri: `git-cockpit://jobs/${j.id}`,
|
|
1207
|
+
name: j.title,
|
|
1208
|
+
description: `${j.kind} ${j.status}`,
|
|
1209
|
+
mimeType: MIME
|
|
1210
|
+
}))
|
|
1211
|
+
})
|
|
1212
|
+
}),
|
|
1213
|
+
{ title: "\u5355\u6761\u540E\u53F0\u4EFB\u52A1", description: "\u72B6\u6001 + \u65E5\u5FD7\u5C3E + result \u6458\u8981", mimeType: MIME },
|
|
1214
|
+
async (uri, variables) => {
|
|
1215
|
+
const id = String(variables.id ?? "");
|
|
1216
|
+
const job = runtime.jobs.get(id);
|
|
1217
|
+
if (!job) {
|
|
1218
|
+
return jsonContents(uri.href, { error: "\u4EFB\u52A1\u4E0D\u5B58\u5728", id });
|
|
1219
|
+
}
|
|
1220
|
+
const summary = runtime.jobs.summary(job);
|
|
1221
|
+
return jsonContents(uri.href, {
|
|
1222
|
+
...summary,
|
|
1223
|
+
logs: job.logs.slice(-20)
|
|
1224
|
+
});
|
|
1225
|
+
}
|
|
1226
|
+
);
|
|
1227
|
+
}
|
|
1228
|
+
|
|
1047
1229
|
// src/mcpServer.ts
|
|
1048
1230
|
var MCP_SERVER_INFO = { name: "git-cockpit-mcp-server", version };
|
|
1049
1231
|
function createMcpServer(runtime) {
|
|
1050
|
-
const server = new
|
|
1232
|
+
const server = new McpServer2(
|
|
1051
1233
|
{ name: MCP_SERVER_INFO.name, version: MCP_SERVER_INFO.version },
|
|
1052
1234
|
{
|
|
1053
|
-
capabilities: { tools: {} },
|
|
1235
|
+
capabilities: { tools: {}, prompts: {}, resources: {} },
|
|
1054
1236
|
instructions: [
|
|
1055
1237
|
"Git Cockpit MCP Server\uFF1A\u53EF\u89C6\u5316\u7684 Git \u64CD\u4F5C\u5DE5\u5177\u3002",
|
|
1056
1238
|
"\u4F7F\u7528\u89C4\u5219\uFF1A",
|
|
@@ -1068,7 +1250,9 @@ function createMcpServer(runtime) {
|
|
|
1068
1250
|
"8. \u66F4\u65B0\u8FDC\u7A0B\u8DDF\u8E2A\u5206\u652F\u7528 git_fetch\u3002\u4E24\u5206\u652F\u5206\u53C9\u5BF9\u6BD4\u7528 git_branch_graph \u5E76\u4F20 into/from\u3002",
|
|
1069
1251
|
"9. \u5F00 PR/MR \u7528 git_mr_prepare / git_mr_create\u3002\u65B9\u5F0F\u4E0E Token \u5728\u8BBE\u7F6E MR \u914D\u7F6E\uFF08\u4E0D\u8FDB\u5DE5\u5177\u53C2\u6570\uFF09\uFF1A\u672C\u673A gh\xB7glab / Token / \u6D4F\u89C8\u5668\u9875\u3002\u627E\u4E0D\u5230 CLI \u65F6\u7ED3\u679C\u542B\u5B98\u65B9\u5B89\u88C5\u5730\u5740\u3002",
|
|
1070
1252
|
"10. \u5927\u7ED3\u679C\u9ED8\u8BA4\u6458\u8981\uFF1Agit_diff / git_show / git_merge_rehearse \u8981\u6B63\u6587\u8BF7\u52A0 path \u6216 detail=true\u3002",
|
|
1071
|
-
"11. \u5DF2\u6253\u5F00\u4ED3\u5E93\u8109\u640F\u7528 git_repo_overview\u3002\u957F\u4EFB\u52A1\u7528 git_job_list / git_job_get / git_job_cancel\u3002"
|
|
1253
|
+
"11. \u5DF2\u6253\u5F00\u4ED3\u5E93\u8109\u640F\u7528 git_repo_overview\u3002\u957F\u4EFB\u52A1\u7528 git_job_list / git_job_get / git_job_cancel\u3002",
|
|
1254
|
+
"12. \u63D0\u4EA4 / \u9884\u6F14\u843D\u76D8 / \u5DE5\u4F5C\u533A\u6536\u5C3E / \u5F00 PR \u7528 Prompt\uFF1Asafe_commit\u3001merge_preview_apply\u3001workspace_continue\u3001open_mr\uFF08\u6B63\u6587\u4E0E README\u300CAgent \u8BE5\u600E\u4E48\u7528\u300D\u76F8\u540C\uFF09\u3002",
|
|
1255
|
+
"13. \u53EA\u8BFB\u5217\u8868\u53EF\u8BFB Resource\uFF1Agit-cockpit://repos\u3001git-cockpit://repo/current\u3001git-cockpit://jobs\u3001git-cockpit://jobs/{id}\u3002"
|
|
1072
1256
|
].join("\n")
|
|
1073
1257
|
}
|
|
1074
1258
|
);
|
|
@@ -1089,6 +1273,8 @@ function createMcpServer(runtime) {
|
|
|
1089
1273
|
}
|
|
1090
1274
|
);
|
|
1091
1275
|
}
|
|
1276
|
+
registerMcpPrompts(server);
|
|
1277
|
+
registerMcpResources(server, runtime);
|
|
1092
1278
|
return server;
|
|
1093
1279
|
}
|
|
1094
1280
|
async function startMcpStdio(runtime) {
|
|
@@ -1147,9 +1333,10 @@ export {
|
|
|
1147
1333
|
TOOL_DEFS,
|
|
1148
1334
|
TOOL_DEF_MAP,
|
|
1149
1335
|
toolSummaries,
|
|
1336
|
+
MCP_PROMPTS,
|
|
1150
1337
|
MCP_SERVER_INFO,
|
|
1151
1338
|
createMcpServer,
|
|
1152
1339
|
startMcpStdio,
|
|
1153
1340
|
McpHttpHandler
|
|
1154
1341
|
};
|
|
1155
|
-
//# sourceMappingURL=chunk-
|
|
1342
|
+
//# sourceMappingURL=chunk-I7QFIFI2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/mcpServer.ts","../package.json","../src/tools/handlers.ts","../src/tools/format.ts","../src/tools/index.ts","../src/overview.ts","../src/tools/schemas.ts","../src/tools/prompts.ts","../src/tools/resources.ts"],"sourcesContent":["/**\n * MCP Server 装配:\n * - 基于官方 SDK 的 McpServer(tools 能力),注册全部工具;\n * - 支持 stdio(独立子进程模式)与 Streamable HTTP(daemon 转发模式)两种传输。\n *\n * 所有工具共用 executeTool 安全链路(权限/dry-run/备份/审计)。\n */\nimport { randomUUID } from 'node:crypto';\nimport type { IncomingMessage, ServerResponse } from 'node:http';\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js';\nimport type { Runtime } from './runtime.ts';\nimport { version } from '../package.json';\nimport { executeTool, formatResultForMcp } from './tools/handlers.ts';\nimport { TOOL_DEFS } from './tools/index.ts';\nimport { registerMcpPrompts } from './tools/prompts.ts';\nimport { registerMcpResources } from './tools/resources.ts';\n\nexport const MCP_SERVER_INFO = { name: 'git-cockpit-mcp-server', version } as const;\n\n/** 创建一个已注册全部工具的 McpServer(一个传输对应一个实例) */\nexport function createMcpServer(runtime: Runtime): McpServer {\n const server = new McpServer(\n { name: MCP_SERVER_INFO.name, version: MCP_SERVER_INFO.version },\n {\n capabilities: { tools: {}, prompts: {}, resources: {} },\n instructions: [\n 'Git Cockpit MCP Server:可视化的 Git 操作工具。',\n '使用规则:',\n '1. 先调用 git_status 查看工作区状态(含 operation=merge/rebase 时走工作区收尾,不要用预演工具冒充);',\n '2. 写操作(git_add/git_commit/git_fetch/git_push 等)默认可执行,但请先使用 dry_run=true 预览影响范围;',\n '3. 高风险工具(git_reset_hard/git_clean/git_push_force/git_branch_delete_force/git_rebase)默认禁用,',\n ' 需管理员在配置中开启;执行时系统会自动备份当前状态;',\n '4. 未指定 repoPath 时使用最近打开的仓库;',\n '5. 合并预演用 git_merge_preview / git_merge_rehearse(merge-tree,不改工作区),',\n ' into=合入目标/线上,from=我的分支;禁止用 git_merge 做预演。',\n ' 冲突行作者用 git_merge_blame(按文件、只读)。',\n ' 多分支扫描用 git_merge_survey;建议合入顺序用 git_merge_order。',\n '6. 落盘用 git_apply_resolve(独立 worktree,主区不切换);冲突时把选边后的 files 一并传入。',\n '7. 工作区已经冲突:git_merge_continue / git_rebase_continue(可带 files)或 abort;不是 apply_resolve。',\n '8. 更新远程跟踪分支用 git_fetch。两分支分叉对比用 git_branch_graph 并传 into/from。',\n '9. 开 PR/MR 用 git_mr_prepare / git_mr_create。方式与 Token 在设置 MR 配置(不进工具参数):本机 gh·glab / Token / 浏览器页。找不到 CLI 时结果含官方安装地址。',\n '10. 大结果默认摘要:git_diff / git_show / git_merge_rehearse 要正文请加 path 或 detail=true。',\n '11. 已打开仓库脉搏用 git_repo_overview。长任务用 git_job_list / git_job_get / git_job_cancel。',\n '12. 提交 / 预演落盘 / 工作区收尾 / 开 PR 用 Prompt:safe_commit、merge_preview_apply、workspace_continue、open_mr(正文与 README「Agent 该怎么用」相同)。',\n '13. 只读列表可读 Resource:git-cockpit://repos、git-cockpit://repo/current、git-cockpit://jobs、git-cockpit://jobs/{id}。'\n ].join('\\n')\n }\n );\n\n for (const def of TOOL_DEFS) {\n // SDK registerTool 的泛型联合推断在遍历场景下不稳定,统一收窄为运行时签名。\n // 注意:必须 bind(server),SDK 1.30 的 registerTool 内部访问 this._registeredTools,\n // 抽成裸函数调用会丢 this,注册时抛 TypeError 导致 MCP 握手挂起。\n const register = server.registerTool.bind(server) as unknown as (\n name: string,\n config: { title?: string; description?: string; inputSchema?: unknown },\n cb: (args: unknown, extra: unknown) => Promise<unknown>\n ) => unknown;\n\n register(\n def.name,\n { description: def.description, inputSchema: def.schema },\n async (args: unknown) => {\n const exec = await executeTool(def, (args ?? {}) as Record<string, unknown>, {\n runtime,\n source: 'mcp'\n });\n return {\n content: [{ type: 'text' as const, text: formatResultForMcp(exec) }],\n isError: !exec.success\n };\n }\n );\n }\n\n registerMcpPrompts(server);\n registerMcpResources(server, runtime);\n return server;\n}\n\n/** stdio 模式:单连接,适合 Claude Desktop / Cursor 直接拉起的独立进程 */\nexport async function startMcpStdio(runtime: Runtime): Promise<void> {\n const server = createMcpServer(runtime);\n const transport = new StdioServerTransport();\n await server.connect(transport);\n}\n\n// ---------------------------------------------------------------------------\n// Streamable HTTP 模式(daemon 内嵌):stateful 会话管理\n// ---------------------------------------------------------------------------\n\ninterface McpHttpSession {\n id: string;\n server: McpServer;\n transport: StreamableHTTPServerTransport;\n}\n\n/** 维护 Streamable HTTP 的会话映射(sessionId -> server+transport) */\nexport class McpHttpHandler {\n private readonly sessions = new Map<string, McpHttpSession>();\n constructor(private readonly runtime: Runtime) {}\n\n async handle(req: IncomingMessage, res: ServerResponse, parsedBody?: unknown): Promise<void> {\n const headerId = req.headers['mcp-session-id'];\n if (typeof headerId === 'string' && headerId) {\n const session = this.sessions.get(headerId);\n if (!session) {\n res.statusCode = 404;\n res.end('MCP session not found');\n return;\n }\n await session.transport.handleRequest(req, res, parsedBody);\n return;\n }\n\n // 新会话:创建 transport + server 并连接\n const transport = new StreamableHTTPServerTransport({\n sessionIdGenerator: () => randomUUID()\n });\n const server = createMcpServer(this.runtime);\n await server.connect(transport);\n const session: McpHttpSession = { id: '', server, transport };\n transport.onclose = () => {\n if (session.id) this.sessions.delete(session.id);\n void server.close().catch(() => undefined);\n };\n await transport.handleRequest(req, res, parsedBody);\n const sid = transport.sessionId;\n if (sid) {\n session.id = sid;\n this.sessions.set(sid, session);\n }\n }\n\n dispose(): void {\n for (const session of this.sessions.values()) {\n session.transport.close().catch(() => undefined);\n }\n this.sessions.clear();\n }\n}","{\n \"name\": \"@shaohui_jin/git-cockpit-mcp-server\",\n \"version\": \"0.1.17\",\n \"description\": \"Git Cockpit - 基于 MCP 的 Git 可视化操作工具(MCP Server + Web 服务 + CLI)\",\n \"type\": \"module\",\n \"license\": \"MIT\",\n \"engines\": {\n \"node\": \">=22.5.0\"\n },\n \"bin\": {\n \"git-cockpit\": \"./dist/cli-entry.js\"\n },\n \"publishConfig\": {\n \"access\": \"public\"\n },\n \"main\": \"./dist/index.js\",\n \"types\": \"./dist/index.d.ts\",\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"import\": \"./dist/index.js\"\n }\n },\n \"files\": [\n \"dist\"\n ],\n \"scripts\": {\n \"build\": \"tsup\",\n \"dev\": \"tsup --watch\",\n \"start\": \"node dist/cli-entry.js start\",\n \"test\": \"vitest run\",\n \"typecheck\": \"tsc --noEmit -p tsconfig.json\",\n \"prepublishOnly\": \"pnpm run typecheck && pnpm run build && node scripts/copy-web.mjs\"\n },\n \"dependencies\": {\n \"@fastify/cors\": \"^10.0.2\",\n \"@fastify/static\": \"^8.0.3\",\n \"@fastify/swagger\": \"^9.8.1\",\n \"@fastify/swagger-ui\": \"^5.2.6\",\n \"@modelcontextprotocol/sdk\": \"^1.12.0\",\n \"@shaohui_jin/git-cockpit-core\": \"workspace:^\",\n \"fastify\": \"^5.2.1\",\n \"zod\": \"^3.24.1\",\n \"zod-to-json-schema\": \"^3.25.2\"\n },\n \"devDependencies\": {\n \"simple-git\": \"^3.27.0\",\n \"tsup\": \"^8.3.5\",\n \"typescript\": \"^5.7.2\",\n \"vitest\": \"^3.0.4\"\n }\n}","/**\n * 工具执行层:所有工具(MCP / Web / CLI 共用)的收口。\n *\n * 统一处理:\n * 1. 权限检查(PermissionManager:禁用/需审批 → 拒绝并记录 denied);\n * 2. 参数 schema 校验(zod);\n * 3. 仓库解析(显式 repoPath / repoId / 最近打开仓库);\n * 4. dry_run 预览模式(默认取配置);\n * 5. 高风险操作自动备份(BackupManager,配置开启时);\n * 6. 执行 + 结果审计日志(脱敏);\n * 7. 触达事件(GitService 'changed' 已由 RepoManager 转发)。\n */\nimport { z } from 'zod';\nimport {\n BackupManager,\n GitOperationError,\n GitService,\n PermissionError\n} from '@shaohui_jin/git-cockpit-core';\nimport type { BackupResult, RiskLevel } from '@shaohui_jin/git-cockpit-core';\nimport type { RepoHandle } from '../repoManager.ts';\nimport type { Runtime } from '../runtime.ts';\n\nexport interface ToolExecutionContext {\n runtime: Runtime;\n source: 'mcp' | 'web' | 'cli';\n /** 上层已解析的仓库(Web 路由提供 repoId,MCP 可通过 tool args 的 repoPath 提供) */\n repoId?: number;\n repoPath?: string;\n}\n\nexport interface ToolDefBase {\n /** 工具名(如 git_status) */\n name: string;\n description: string;\n risk: RiskLevel;\n}\n\nexport interface ToolDef<TSchema extends z.ZodTypeAny = z.ZodTypeAny> extends ToolDefBase {\n schema: TSchema;\n handler: ToolHandler<TSchema>;\n /** false 时不解析仓库(任务列表、多仓脉搏) */\n needsRepo?: boolean;\n}\n\nexport type ToolHandler<TSchema extends z.ZodTypeAny> = (\n args: z.infer<TSchema> & { repoPath?: string; dryRun?: boolean },\n ctx: ToolExecutionContext & { git: GitService; repoPath: string }\n) => Promise<unknown>;\n\nexport interface ToolExecutionResult {\n tool: string;\n source: 'mcp' | 'web' | 'cli';\n dryRun: boolean;\n success: boolean;\n /** 成功时的返回值(字符串输出或结构化数据) */\n result?: unknown;\n error?: {\n code: string;\n message: string;\n requiredApproval: boolean;\n };\n /** 高风险操作自动创建的备份信息 */\n backupCreated?: BackupResult | null;\n durationMs: number;\n /** 预览格式(dryRun 时返回的 WritePreview 已包含命令) */\n preview?: unknown;\n /** 校验后的参数,供 MCP 摘要判断 detail/path */\n args?: Record<string, unknown>;\n}\n\n/** 解析目标仓库:优先级 repoId > repoPath(上下文) > args.repoPath > 最近打开 */\nasync function resolveRepo(runtime: Runtime, ctx: ToolExecutionContext, argsPath?: string): Promise<RepoHandle> {\n if (ctx.repoId !== undefined) {\n const handle = await runtime.repoManager.getById(ctx.repoId);\n if (handle) return handle;\n throw new GitOperationError(`仓库不存在: id=${ctx.repoId}`, 'REPO_NOT_FOUND');\n }\n if (ctx.repoPath) {\n return runtime.repoManager.getByPath(ctx.repoPath);\n }\n if (argsPath) {\n return runtime.repoManager.open(argsPath);\n }\n const current = await runtime.repoManager.getCurrent();\n if (!current) {\n throw new GitOperationError('尚未打开任何仓库。请先打开仓库或提供 repoPath 参数。', 'NO_ACTIVE_REPO');\n }\n return current;\n}\n\nfunction extractError(err: unknown): { code: string; message: string; requiredApproval: boolean } {\n if (err instanceof PermissionError) {\n return { code: 'PERMISSION_DENIED', message: err.message, requiredApproval: err.requiredApproval };\n }\n if (err instanceof GitOperationError) {\n return { code: err.code, message: err.message, requiredApproval: false };\n }\n if (err instanceof z.ZodError) {\n const summary = err.issues\n .map((i) => `${i.path.join('.') || '(root)'}: ${i.message}`)\n .slice(0, 5)\n .join('; ');\n return { code: 'INVALID_ARGS', message: `参数校验失败:${summary}`, requiredApproval: false };\n }\n const msg = err instanceof Error ? err.message : String(err);\n return { code: 'INTERNAL_ERROR', message: msg.slice(0, 500), requiredApproval: false };\n}\n\n/**\n * 执行一个工具(含统一安全链路)。返回标准化结果,不抛异常(错误编码进 error 字段)。\n */\nexport async function executeTool(\n def: ToolDef,\n rawArgs: Record<string, unknown>,\n ctx: ToolExecutionContext\n): Promise<ToolExecutionResult> {\n const runtime = ctx.runtime;\n const t0 = Date.now();\n const dryRun = typeof rawArgs.dryRun === 'boolean' ? rawArgs.dryRun : runtime.permissions.getDryRunDefault();\n\n const record = (result: 'success' | 'error' | 'denied', params: Record<string, unknown>, errorMessage?: string, repoPath?: string) => {\n runtime.auditLogger.log({\n timestamp: new Date().toISOString(),\n source: ctx.source,\n tool: def.name,\n repoPath: repoPath ?? '',\n params,\n result,\n error: errorMessage ?? null,\n durationMs: Date.now() - t0,\n dryRun\n });\n runtime.eventBus.emit('log', { tool: def.name, result, at: new Date().toISOString() });\n };\n\n try {\n // 1. 权限\n runtime.permissions.assertAllowed(def.name);\n\n // 2. schema 校验\n let args: Record<string, unknown>;\n try {\n args = def.schema.parse(rawArgs) as Record<string, unknown>;\n } catch (err) {\n const e = extractError(err);\n record('error', rawArgs, e.message);\n return { tool: def.name, source: ctx.source, dryRun, success: false, error: e, durationMs: Date.now() - t0 };\n }\n\n // 3. 仓库解析(任务/多仓一览可不依赖当前仓)\n let git: GitService | undefined;\n let repoPath = '';\n if (def.needsRepo !== false) {\n const handle = await resolveRepo(runtime, ctx, args.repoPath as string | undefined);\n git = handle.service;\n repoPath = git.repoPath;\n }\n\n // 4. 高风险自动备份(非预览时)\n let backup: BackupResult | null = null;\n if (!dryRun && def.risk === 'dangerous' && runtime.config.git.backupOnDangerousOps && git) {\n backup = await new BackupManager(git).createBackup();\n args = { ...args, __backup: { branch: backup.branch, stashRef: backup.stashRef } };\n }\n\n // 5. 执行\n const result = await def.handler(args, { ...ctx, git: git as GitService, repoPath });\n\n // 6. 审计\n record('success', args, undefined, repoPath);\n\n const preview = dryRun ? result : undefined;\n return {\n tool: def.name,\n source: ctx.source,\n dryRun,\n success: true,\n result,\n preview,\n backupCreated: backup,\n durationMs: Date.now() - t0,\n args\n };\n } catch (err) {\n const e = extractError(err);\n const isDenied = err instanceof PermissionError;\n record(isDenied ? 'denied' : 'error', rawArgs, e.message);\n return {\n tool: def.name,\n source: ctx.source,\n dryRun,\n success: false,\n error: e,\n durationMs: Date.now() - t0\n };\n }\n}\n\nexport { formatResultForMcp, summarizeForAgent } from './format.ts';","/**\n * MCP 文本输出:默认摘要,正文靠 path / detail。\n * Web REST / executeTool.result 仍是完整对象,不走这里。\n */\nimport type { ToolExecutionResult } from './handlers.ts';\n\nconst FILE_CONTENT_LIMIT = 64 * 1024;\n\nexport function wantsDetail(args: Record<string, unknown> | undefined): boolean {\n return args?.detail === true;\n}\n\nfunction hasPath(args: Record<string, unknown> | undefined): boolean {\n return typeof args?.path === 'string' && args.path.trim().length > 0;\n}\n\nfunction asRecord(value: unknown): Record<string, unknown> | null {\n return value !== null && typeof value === 'object' && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : null;\n}\n\nfunction stripDiffPatch(diff: unknown): unknown {\n const d = asRecord(diff);\n if (!d || !('rawPatch' in d)) return diff;\n const { rawPatch: _raw, ...rest } = d;\n return { ...rest, detailAvailable: true };\n}\n\nfunction stripRehearseBodies(result: unknown): unknown {\n const r = asRecord(result);\n if (!r) return result;\n const files = Array.isArray(r.conflictFiles) ? r.conflictFiles : [];\n const paths = files.map((f) => {\n const row = asRecord(f);\n return {\n path: row?.path ?? '',\n contentConflict: row?.contentConflict ?? true,\n hunks: []\n };\n });\n const first = typeof paths[0]?.path === 'string' ? paths[0].path : '';\n return {\n ...r,\n conflictFiles: paths,\n detailAvailable: true,\n next: first\n ? [{ tool: 'git_merge_rehearse', args: { into: r.into, from: r.from, path: first } }]\n : []\n };\n}\n\n/** 把完整工具结果收成 Agent 默认可消化的形状 */\nexport function summarizeForAgent(tool: string, result: unknown, args: Record<string, unknown> = {}): unknown {\n if (result == null) return result;\n const detail = wantsDetail(args);\n const pathSet = hasPath(args);\n\n if (tool === 'git_diff' || tool === 'git_stash_show') {\n if (detail || pathSet) return result;\n return stripDiffPatch(result);\n }\n if (tool === 'git_show') {\n if (detail || pathSet) return result;\n const row = asRecord(result);\n if (!row) return result;\n return { ...row, diff: stripDiffPatch(row.diff) };\n }\n if (tool === 'git_merge_rehearse') {\n if (detail || pathSet) return result;\n return stripRehearseBodies(result);\n }\n if (tool === 'git_repo_overview') {\n if (detail) return result;\n const row = asRecord(result);\n const repos = Array.isArray(row?.repos) ? row.repos : [];\n return {\n ...row,\n repos: repos.map((item) => {\n const rec = asRecord(item);\n if (!rec) return item;\n const { activity: _days, ...rest } = rec;\n return rest;\n })\n };\n }\n if (tool === 'git_file_content') {\n if (detail) return result;\n const row = asRecord(result);\n const content = typeof row?.content === 'string' ? row.content : '';\n const bytes = Buffer.byteLength(content, 'utf8');\n if (bytes <= FILE_CONTENT_LIMIT) return result;\n return {\n path: args.path,\n truncated: true,\n bytes,\n detailAvailable: true\n };\n }\n return result;\n}\n\n/** 把干运行/真实结果统一包成 MCP 文本输出 */\nexport function formatResultForMcp(exec: ToolExecutionResult): string {\n if (!exec.success) {\n const prefix = exec.error?.requiredApproval ? '需要审批' : '操作失败';\n return `${prefix}:${exec.error?.message ?? '未知错误'}`;\n }\n const parts: string[] = [];\n if (exec.dryRun) {\n parts.push('[dry-run 预览] 未实际执行任何操作');\n }\n if (exec.backupCreated) {\n parts.push(\n `[自动备份] 分支 ${exec.backupCreated.branch ?? '(未创建)'}${exec.backupCreated.stashRef ? `,stash ${exec.backupCreated.stashRef}` : ''}`\n );\n }\n const summarized = summarizeForAgent(exec.tool, exec.result, exec.args ?? {});\n const payload = typeof summarized === 'string' ? summarized : JSON.stringify(summarized);\n parts.push(payload);\n return parts.join('\\n\\n');\n}\n","/**\n * 工具注册表:全部 MCP 工具的静态定义(名称/描述/风险等级/schema/handler)。\n * handler 直接调用 core GitService 的方法;统一安全链路由 executeTool 承担。\n */\nimport {\n enrichPrepareMr,\n createPullOrMergeRequest,\n BackupManager,\n GitOperationError,\n SURVEY_ASYNC_THRESHOLD,\n type GitService\n} from '@shaohui_jin/git-cockpit-core';\nimport { collectRepoOverviews } from '../overview.ts';\nimport * as S from './schemas.ts';\nimport type { ToolDef } from './handlers.ts';\n\ntype Args = Record<string, unknown> & { repoPath?: string; dryRun?: boolean };\n\nexport const TOOL_DEFS: ToolDef[] = [\n // ---------------------------------------------------------------------------\n // 只读工具(默认开放)\n // ---------------------------------------------------------------------------\n {\n name: 'git_status',\n description: '获取当前仓库的工作区状态:当前分支、已暂存/未暂存/未跟踪文件、冲突文件、领先/落后于上游等。',\n risk: 'readonly',\n schema: S.GitStatusSchema,\n handler: async (_args: Args, ctx) => ctx.git.getStatus()\n },\n {\n name: 'git_log',\n description: '获取提交历史(默认 HEAD 起,最多返回 maxCount 条)。支持按作者、路径、提交范围过滤。',\n risk: 'readonly',\n schema: S.GitLogSchema,\n handler: async (args: Args, ctx) =>\n ctx.git.getLog({\n maxCount: args.maxCount as number | undefined,\n from: args.from as string | undefined,\n to: args.to as string | undefined,\n author: args.author as string | undefined,\n path: args.path as string | undefined,\n all: args.all as boolean | undefined\n })\n },\n {\n name: 'git_diff',\n description: '获取工作区/暂存区/提交范围的差异。支持指定文件、staged、大 diff 截断。返回文件级统计与完整 unified diff 文本。',\n risk: 'readonly',\n schema: S.GitDiffSchema,\n handler: async (args: Args, ctx) =>\n ctx.git.getDiff({\n from: args.from as string | undefined,\n to: args.to as string | undefined,\n path: args.path as string | undefined,\n staged: args.staged as boolean | undefined,\n maxPatchBytes: args.maxPatchBytes as number | undefined\n })\n },\n {\n name: 'git_show',\n description: '显示某个提交的详细信息(元信息 + 相对父提交的 diff)。',\n risk: 'readonly',\n schema: S.GitShowSchema,\n handler: async (args: Args, ctx) =>\n ctx.git.getShow(args.commit as string, {\n path: args.path as string | undefined,\n maxPatchBytes: args.maxPatchBytes as number | undefined\n })\n },\n {\n name: 'git_branch_list',\n description: '列出所有本地与远程分支,标注当前分支及其指向的提交。',\n risk: 'readonly',\n schema: S.GitBranchListSchema,\n handler: async (_args: Args, ctx) => ctx.git.listBranches()\n },\n {\n name: 'git_tag_list',\n description: '列出所有标签(按创建时间倒序)。',\n risk: 'readonly',\n schema: S.GitTagListSchema,\n handler: async (_args: Args, ctx) => ctx.git.listTags()\n },\n {\n name: 'git_remote_list',\n description: '列出远程仓库信息(名称、fetch/push URL)。',\n risk: 'readonly',\n schema: S.GitRemoteListSchema,\n handler: async (_args: Args, ctx) => ctx.git.listRemotes()\n },\n {\n name: 'git_file_content',\n description: '读取指定提交中某个文件的内容(大文件自动截断 2MB)。',\n risk: 'readonly',\n schema: S.GitFileContentSchema,\n handler: async (args: Args, ctx) => ctx.git.getFileContent(args.commit as string, args.path as string)\n },\n {\n name: 'git_graph',\n description:\n '获取全部分支的提交列表(hash/parent/subject/refs/HEAD),给需要线性历史的场景。状态页 G6 分支图请用 git_branch_graph(tip DAG)。',\n risk: 'readonly',\n schema: S.GitGraphSchema,\n handler: async (args: Args, ctx) => ctx.git.getGraph(args.maxCount as number | undefined)\n },\n {\n name: 'git_branch_graph',\n description:\n '分支 tip DAG:for-each-ref + rev-list --parents。节点是各分支 tip,边是最近祖先 tip。与 Git Insight 画布同一口径。不改工作区。',\n risk: 'readonly',\n schema: S.GitBranchGraphSchema,\n handler: async (args: Args, ctx) =>\n ctx.git.getBranchGraph({\n maxNodes: args.maxNodes as number | undefined,\n into: args.into as string | undefined,\n from: args.from as string | undefined\n })\n },\n {\n name: 'git_reflog',\n description: '只读列出 git reflog(HEAD 移动记录)。',\n risk: 'readonly',\n schema: S.GitReflogSchema,\n handler: async (args: Args, ctx) => ctx.git.getReflog(args.maxCount as number | undefined)\n },\n {\n name: 'git_backup_list',\n description: '列出高危操作前自动创建的 backup/pre-op-* 分支,以及说明含 git-cockpit backup 的 stash。',\n risk: 'readonly',\n schema: S.GitStatusSchema,\n handler: async (_args: Args, ctx) => new BackupManager(ctx.git).listBackups()\n },\n {\n name: 'git_merge_preview',\n description:\n '用 git merge-tree 预演把 from 合入 into(不改工作区)。into=合入目标/线上/ours,from=我的分支/theirs。返回是否可干净合并及冲突文件列表。禁止用 git_merge 做预演。Git >= 2.38。',\n risk: 'readonly',\n schema: S.GitMergePreviewSchema,\n handler: async (args: Args, ctx) =>\n ctx.git.previewMerge({\n into: args.into as string,\n from: args.from as string,\n fetch: args.fetch as boolean | undefined,\n remote: args.remote as string | undefined,\n path: args.path as string | undefined\n })\n },\n {\n name: 'git_merge_rehearse',\n description:\n '完整合并预演:冲突文件 + diff3 冲突正文 + ours/theirs/base(仍不改工作区)。MCP 默认只回路径摘要;要正文请带 path 或 detail=true。选边后把 files 交给 git_apply_resolve。into/from 同 git_merge_preview。',\n risk: 'readonly',\n schema: S.GitMergeRehearseSchema,\n handler: async (args: Args, ctx) => {\n const wantBody = args.detail === true || (typeof args.path === 'string' && args.path.trim().length > 0);\n if (!wantBody) {\n return ctx.git.previewMerge({\n into: args.into as string,\n from: args.from as string,\n fetch: args.fetch as boolean | undefined,\n remote: args.remote as string | undefined,\n path: args.path as string | undefined\n });\n }\n return ctx.git.rehearseMerge({\n into: args.into as string,\n from: args.from as string,\n fetch: args.fetch as boolean | undefined,\n remote: args.remote as string | undefined,\n path: args.path as string | undefined,\n maxFiles: args.maxFiles as number | undefined\n });\n }\n },\n {\n name: 'git_merge_blame',\n description:\n '对单个冲突文件两侧 tip 跑 git blame(不改工作区)。返回红块相关区间的作者/说明/时间,供选边参考。不是自动选边。into/from 同 git_merge_preview。',\n risk: 'readonly',\n schema: S.GitMergeBlameSchema,\n handler: async (args: Args, ctx) =>\n ctx.git.blameConflictFile({\n into: args.into as string,\n from: args.from as string,\n path: args.path as string,\n fetch: args.fetch as boolean | undefined,\n remote: args.remote as string | undefined\n })\n },\n {\n name: 'git_merge_survey',\n description:\n '批量预演矩阵:intos × froms 每对跑一次 merge-tree,整批只 fetch 一次。只返回结论与冲突路径。格子>20 或 async=true 时后台跑并返回 jobId(git_job_get)。禁止用 git_merge 做预演。',\n risk: 'readonly',\n schema: S.GitMergeSurveySchema,\n handler: async (args: Args, ctx) => {\n const intos = args.intos as string[];\n const froms = args.froms as string[];\n const asyncWanted = args.async === true || intos.length * froms.length > SURVEY_ASYNC_THRESHOLD;\n if (asyncWanted) {\n const job = ctx.runtime.jobs.startSurvey({\n repoPath: ctx.repoPath,\n intos,\n froms,\n fetch: args.fetch as boolean | undefined,\n remote: args.remote as string | undefined,\n git: ctx.git\n });\n return { jobId: job.id, status: job.status, async: true, title: job.title };\n }\n return ctx.git.surveyMerges({\n intos,\n froms,\n fetch: args.fetch as boolean | undefined,\n remote: args.remote as string | undefined\n });\n }\n },\n {\n name: 'git_merge_order',\n description:\n '建议把多个 from 合入同一个 into 的顺序。对象库内 merge-tree + commit-tree 串行模拟,不改工作区、不建分支。返回建议顺序、能连续干净合入几个、从哪一步开始要人工。',\n risk: 'readonly',\n schema: S.GitMergeOrderSchema,\n handler: async (args: Args, ctx) =>\n ctx.git.suggestMergeOrder({\n into: args.into as string,\n branches: args.branches as string[],\n fetch: args.fetch as boolean | undefined,\n remote: args.remote as string | undefined\n })\n },\n {\n name: 'git_mr_prepare',\n description:\n '只读:解析开 PR/MR 的源/目标、浏览器创建页、本机 gh/glab 是否可用(找不到会带官方安装地址)、可选审核人列表。Token 不进参数。into/from 同 git_merge_preview。',\n risk: 'readonly',\n schema: S.GitMrPrepareSchema,\n handler: async (args: Args, ctx) => {\n const mr = ctx.runtime.config.mr;\n const prep = await ctx.git.prepareMr({\n into: args.into as string,\n from: args.from as string,\n remote: (args.remote as string | undefined)?.trim() || undefined,\n sourceBranch: args.sourceBranch as string | undefined\n });\n return enrichPrepareMr({ prep, mr, cwd: ctx.git.repoPath });\n }\n },\n {\n name: 'git_repo_overview',\n description: '已打开仓库脉搏:分支、脏文件数、ahead/behind、工作区 operation、本地 merge/* 数、近 12 周提交总数。默认不含每日格子;detail=true 才回 activity[]。不回 diff。',\n risk: 'readonly',\n needsRepo: false,\n schema: S.GitRepoOverviewSchema,\n handler: async (_args: Args, ctx) => ({ repos: await collectRepoOverviews(ctx.runtime) })\n },\n {\n name: 'git_job_list',\n description: '列出后台任务摘要(克隆 / survey / fetch)。',\n risk: 'readonly',\n needsRepo: false,\n schema: S.GitJobListSchema,\n handler: async (_args: Args, ctx) => ({ jobs: ctx.runtime.jobs.list().map((j) => ctx.runtime.jobs.summary(j)) })\n },\n {\n name: 'git_job_get',\n description: '查看一条后台任务(日志 + 完成时的 result 摘要)。',\n risk: 'readonly',\n needsRepo: false,\n schema: S.GitJobGetSchema,\n handler: async (args: Args, ctx) => {\n const job = ctx.runtime.jobs.get(args.id as string);\n if (!job) throw new GitOperationError('任务不存在', 'JOB_NOT_FOUND');\n return ctx.runtime.jobs.detail(job);\n }\n },\n\n // ---------------------------------------------------------------------------\n // 写操作工具(默认开放,需预览/确认)\n // ---------------------------------------------------------------------------\n {\n name: 'git_add',\n description: '暂存指定文件;paths 为空表示暂存全部。支持 dry_run 预览。',\n risk: 'write',\n schema: S.GitAddSchema,\n handler: async (args: Args, ctx) =>\n ctx.git.add((args.paths as string[]) ?? [], { dryRun: args.dryRun as boolean | undefined })\n },\n {\n name: 'git_unstage',\n description: '取消暂存指定文件(git reset HEAD -- <paths>)。支持 dry_run 预览。',\n risk: 'write',\n schema: S.GitUnstageSchema,\n handler: async (args: Args, ctx) =>\n ctx.git.unstage((args.paths as string[]) ?? [], { dryRun: args.dryRun as boolean | undefined })\n },\n {\n name: 'git_commit',\n description: '创建提交。需要指定 message;paths 可限定仅提交部分文件;allowEmpty 允许空提交。支持 dry_run 预览。',\n risk: 'write',\n schema: S.GitCommitSchema,\n handler: async (args: Args, ctx) =>\n ctx.git.commit(args.message as string, {\n dryRun: args.dryRun as boolean | undefined,\n allowEmpty: args.allowEmpty as boolean | undefined,\n paths: args.paths as string[] | undefined\n })\n },\n {\n name: 'git_checkout',\n description: '切换到指定分支。若本地更改会被覆盖将拒绝并给出提示。支持 dry_run 预览。',\n risk: 'write',\n schema: S.GitCheckoutSchema,\n handler: async (args: Args, ctx) =>\n ctx.git.checkoutBranch(args.branch as string, { dryRun: args.dryRun as boolean | undefined })\n },\n {\n name: 'git_branch_create',\n description: '创建新分支(默认从当前 HEAD;startPoint 可指定起点)。支持 dry_run 预览。',\n risk: 'write',\n schema: S.GitBranchCreateSchema,\n handler: async (args: Args, ctx) =>\n ctx.git.createBranch(args.name as string, {\n dryRun: args.dryRun as boolean | undefined,\n startPoint: args.startPoint as string | undefined\n })\n },\n {\n name: 'git_branch_delete',\n description: '安全删除分支(-d,未合并分支会拒绝)。支持 dry_run 预览。',\n risk: 'write',\n schema: S.GitBranchDeleteSchema,\n handler: async (args: Args, ctx) =>\n ctx.git.deleteBranch(args.name as string, { dryRun: args.dryRun as boolean | undefined })\n },\n {\n name: 'git_merge',\n description: '把指定分支合并到当前分支(普通合并)。产生冲突时会提示解决。支持 dry_run 预览。',\n risk: 'write',\n schema: S.GitMergeSchema,\n handler: async (args: Args, ctx) =>\n ctx.git.merge(args.branch as string, { dryRun: args.dryRun as boolean | undefined })\n },\n {\n name: 'git_merge_abort',\n description:\n '中止当前工作区 merge(git merge --abort)。只用于已经开始的工作区合并,禁止拿来代替 merge-tree 预演。',\n risk: 'write',\n schema: S.GitMergeAbortSchema,\n handler: async (args: Args, ctx) => ctx.git.mergeAbort({ dryRun: args.dryRun as boolean | undefined })\n },\n {\n name: 'git_merge_continue',\n description:\n '继续当前工作区 merge。可把 files[{path,resolvedContent}] 写入工作区并 git add 后再 continue。不是 git_apply_resolve。',\n risk: 'write',\n schema: S.GitMergeContinueSchema,\n handler: async (args: Args, ctx) =>\n ctx.git.mergeContinue({\n dryRun: args.dryRun as boolean | undefined,\n files: args.files as { path: string; resolvedContent: string }[] | undefined\n })\n },\n {\n name: 'git_pull',\n description: '从远程拉取并合并(非强制)。远程有冲突将提示。支持 dry_run 预览。',\n risk: 'write',\n schema: S.GitPullSchema,\n handler: async (args: Args, ctx) =>\n ctx.git.pull({\n dryRun: args.dryRun as boolean | undefined,\n remote: args.remote as string | undefined,\n branch: args.branch as string | undefined\n })\n },\n {\n name: 'git_fetch',\n description:\n '从远程抓取跟踪分支(git fetch --prune --no-tags),不改工作区、不合并。更新 origin/xxx 后再做预演或分支图对比。支持 dry_run 预览。',\n risk: 'write',\n schema: S.GitFetchSchema,\n handler: async (args: Args, ctx) =>\n ctx.git.fetch({\n dryRun: args.dryRun as boolean | undefined,\n remote: args.remote as string | undefined\n })\n },\n {\n name: 'git_push',\n description: '推送到远程(非强制)。推送被拒绝(远程有新提交)会给出提示。支持 dry_run 预览。',\n risk: 'write',\n schema: S.GitPushSchema,\n handler: async (args: Args, ctx) =>\n ctx.git.push({\n dryRun: args.dryRun as boolean | undefined,\n remote: args.remote as string | undefined,\n branch: args.branch as string | undefined\n })\n },\n {\n name: 'git_tag_create',\n description: '创建标签;提供 message 则创建附注标签。支持 dry_run 预览。',\n risk: 'write',\n schema: S.GitTagCreateSchema,\n handler: async (args: Args, ctx) =>\n ctx.git.createTag(args.name as string, {\n dryRun: args.dryRun as boolean | undefined,\n message: args.message as string | undefined,\n commit: args.commit as string | undefined\n })\n },\n {\n name: 'git_stash',\n description: '暂存(stash)当前工作区更改,可选包含未跟踪文件(-u);paths 可指定仅暂存部分文件(对应 WebStorm Shelve 的选择性暂存)。支持 dry_run 预览。',\n risk: 'write',\n schema: S.GitStashSchema,\n handler: async (args: Args, ctx) =>\n ctx.git.stash(args.message as string | undefined, {\n dryRun: args.dryRun as boolean | undefined,\n includeUntracked: args.includeUntracked as boolean | undefined,\n paths: (args.paths as string[]) ?? []\n })\n },\n {\n name: 'git_stash_list',\n description: '列出全部 stash 记录(stash@{n} / 说明 / 时间)。',\n risk: 'readonly',\n schema: S.GitStashListSchema,\n handler: async (_args: Args, ctx) => ctx.git.listStashes()\n },\n {\n name: 'git_stash_show',\n description: '查看某条 stash 的差异内容(不修改仓库)。',\n risk: 'readonly',\n schema: S.GitStashShowSchema,\n handler: async (args: Args, ctx) =>\n ctx.git.stashShow({\n index: args.index as number | undefined,\n maxPatchBytes: args.maxPatchBytes as number | undefined\n })\n },\n {\n name: 'git_stash_apply',\n description: '应用某条 stash(保留记录,可反复应用)。产生冲突会提示。支持 dry_run 预览。',\n risk: 'write',\n schema: S.GitStashApplySchema,\n handler: async (args: Args, ctx) =>\n ctx.git.stashApply({ dryRun: args.dryRun as boolean | undefined, index: args.index as number | undefined })\n },\n {\n name: 'git_stash_drop',\n description: '删除某条 stash 记录(删除后不可直接恢复)。支持 dry_run 预览。',\n risk: 'write',\n schema: S.GitStashDropSchema,\n handler: async (args: Args, ctx) =>\n ctx.git.stashDrop({ dryRun: args.dryRun as boolean | undefined, index: args.index as number | undefined })\n },\n {\n name: 'git_stash_pop',\n description: '恢复最新(或指定 index)的 stash。恢复产生冲突会提示。支持 dry_run 预览。',\n risk: 'write',\n schema: S.GitStashPopSchema,\n handler: async (args: Args, ctx) =>\n ctx.git.stashPop({ dryRun: args.dryRun as boolean | undefined, index: args.index as number | undefined })\n },\n {\n name: 'git_apply_resolve',\n description:\n '在独立 git worktree 中把 from 合入 into 并提交到临时分支(主工作区不切换)。干净合并 files 可空;有冲突必须提供 files。默认 push 临时分支。不要用工作区 git_merge 代替本工具。',\n risk: 'write',\n schema: S.GitApplyResolveSchema,\n handler: async (args: Args, ctx) =>\n ctx.git.applyResolve({\n into: args.into as string,\n from: args.from as string,\n files: args.files as { path: string; resolvedContent: string }[] | undefined,\n remote: args.remote as string | undefined,\n push: args.push as boolean | undefined,\n keepLocal: args.keepLocal as boolean | undefined,\n tempBranch: args.tempBranch as string | undefined,\n dryRun: args.dryRun as boolean | undefined\n })\n },\n {\n name: 'git_mr_create',\n description:\n '按设置 MR 配置开 PR/MR:Token REST、本机 gh/glab,或浏览器创建页。Token 不进本工具参数。找不到 CLI 时结果里带官方安装地址。dry_run 可预览。',\n risk: 'write',\n schema: S.GitMrCreateSchema,\n handler: async (args: Args, ctx) => {\n const mr = ctx.runtime.config.mr;\n const prep = await ctx.git.prepareMr({\n into: args.into as string,\n from: args.from as string,\n remote: (args.remote as string | undefined)?.trim() || undefined,\n sourceBranch: args.sourceBranch as string | undefined\n });\n return createPullOrMergeRequest({\n prep,\n mr,\n cwd: ctx.git.repoPath,\n title: args.title as string | undefined,\n body: args.body as string | undefined,\n reviewers: args.reviewers as string[] | undefined,\n dryRun: args.dryRun as boolean | undefined\n });\n }\n },\n {\n name: 'git_job_cancel',\n description: '取消进行中的后台任务。克隆会杀进程并删除不完整目录。',\n risk: 'write',\n needsRepo: false,\n schema: S.GitJobCancelSchema,\n handler: async (args: Args, ctx) => {\n if (args.dryRun) {\n return {\n dryRun: true,\n command: 'job cancel',\n args: [args.id],\n risk: 'low',\n note: '将取消进行中的后台任务'\n };\n }\n return ctx.runtime.jobs.summary(ctx.runtime.jobs.cancel(args.id as string));\n }\n },\n\n // ---------------------------------------------------------------------------\n // 高风险工具(默认禁用,需开启/审批;自动备份)\n // ---------------------------------------------------------------------------\n {\n name: 'git_reset_hard',\n description: '硬重置到指定提交(丢弃索引与工作区更改,高风险不可逆,执行前自动备份)。',\n risk: 'dangerous',\n schema: S.GitResetHardSchema,\n handler: async (args: Args, ctx) =>\n ctx.git.resetHard(args.target as string, { dryRun: args.dryRun as boolean | undefined })\n },\n {\n name: 'git_clean',\n description: '清理(删除)所有未跟踪文件与目录(高风险不可逆,执行前自动备份)。支持 dry_run 预览。',\n risk: 'dangerous',\n schema: S.GitCleanSchema,\n handler: async (args: Args, ctx) => ctx.git.clean({ dryRun: args.dryRun as boolean | undefined })\n },\n {\n name: 'git_push_force',\n description: '以 --force-with-lease 强制推送(覆盖远程历史,高风险,执行前自动备份)。',\n risk: 'dangerous',\n schema: S.GitPushForceSchema,\n handler: async (args: Args, ctx) =>\n ctx.git.pushForce({\n dryRun: args.dryRun as boolean | undefined,\n remote: args.remote as string | undefined,\n branch: args.branch as string | undefined\n })\n },\n {\n name: 'git_branch_delete_force',\n description: '强制删除分支(-D,不检查合并状态,高风险)。支持 dry_run 预览。',\n risk: 'dangerous',\n schema: S.GitBranchDeleteForceSchema,\n handler: async (args: Args, ctx) =>\n ctx.git.deleteBranchForce(args.name as string, { dryRun: args.dryRun as boolean | undefined })\n },\n {\n name: 'git_rebase',\n description: '把当前分支变基到指定分支(重写提交历史,高风险,产生冲突需手动解决后 git rebase --continue)。',\n risk: 'dangerous',\n schema: S.GitRebaseSchema,\n handler: async (args: Args, ctx) =>\n ctx.git.rebase(args.branch as string, { dryRun: args.dryRun as boolean | undefined })\n },\n {\n name: 'git_rebase_abort',\n description: '中止当前工作区 rebase(git rebase --abort)。只用于已经开始的变基。',\n risk: 'write',\n schema: S.GitRebaseAbortSchema,\n handler: async (args: Args, ctx) => ctx.git.rebaseAbort({ dryRun: args.dryRun as boolean | undefined })\n },\n {\n name: 'git_rebase_continue',\n description:\n '继续当前工作区 rebase。可把 files 写入工作区并 git add 后再 continue。冲突须先解决。',\n risk: 'write',\n schema: S.GitRebaseContinueSchema,\n handler: async (args: Args, ctx) =>\n ctx.git.rebaseContinue({\n dryRun: args.dryRun as boolean | undefined,\n files: args.files as { path: string; resolvedContent: string }[] | undefined\n })\n }\n];\n\nexport const TOOL_DEF_MAP: ReadonlyMap<string, ToolDef> = new Map(TOOL_DEFS.map((d) => [d.name, d]));\n\n/** 供 mcpServer 注册工具列表(名称、描述、schema) */\nexport function toolSummaries(): { name: string; description: string }[] {\n return TOOL_DEFS.map((d) => ({ name: d.name, description: d.description }));\n}\n\nexport type { GitService };","import { emptyActivity, type RepoOverview } from '@shaohui_jin/git-cockpit-core';\nimport type { Runtime } from './runtime.ts';\n\nconst CONCURRENCY = 4;\n\nexport function unavailableOverview(path: string, extra: Partial<RepoOverview> = {}): RepoOverview {\n const name = path.replace(/[\\\\/]+$/, '').split(/[\\\\/]/).pop() || path;\n return {\n path,\n name,\n available: false,\n current: '',\n tracking: null,\n ahead: 0,\n behind: 0,\n dirtyCount: 0,\n conflictCount: 0,\n operation: 'none',\n tempMergeBranchCount: 0,\n ...emptyActivity(),\n ...extra\n };\n}\n\nasync function mapPool<T, R>(items: T[], n: number, fn: (t: T) => Promise<R>): Promise<R[]> {\n const out: R[] = new Array(items.length);\n let i = 0;\n async function worker() {\n while (i < items.length) {\n const idx = i++;\n out[idx] = await fn(items[idx]!);\n }\n }\n const workers = Math.min(n, items.length);\n await Promise.all(Array.from({ length: workers }, () => worker()));\n return out;\n}\n\nexport async function collectRepoOverviews(runtime: Runtime): Promise<RepoOverview[]> {\n const repos = runtime.repoManager.list();\n if (!repos.length) return [];\n return mapPool(repos, CONCURRENCY, async (r) => {\n try {\n const handle = await runtime.repoManager.getById(r.id);\n if (!handle) return unavailableOverview(r.path, { id: r.id, lastOpenedAt: r.lastOpenedAt });\n const o = await handle.service.getOverview();\n return { ...o, id: r.id, lastOpenedAt: r.lastOpenedAt };\n } catch {\n return unavailableOverview(r.path, { id: r.id, lastOpenedAt: r.lastOpenedAt });\n }\n });\n}\n","/**\n * MCP 工具参数 Schema(zod)。\n * 所有工具均支持可选的 repoPath(缺省使用当前打开的仓库)与 dryRun(缺省为配置默认)。\n */\nimport { z } from 'zod';\n\nconst repoPath = z\n .string()\n .optional()\n .describe('仓库绝对路径。不提供时使用当前打开的仓库。');\n\nconst dryRun = z\n .boolean()\n .optional()\n .describe('为 true 时仅返回将执行的命令与影响范围(预览/干运行),不真正修改仓库。');\n\nconst detail = z\n .boolean()\n .optional()\n .describe('为 true 时 MCP 返回完整正文;默认只回摘要(路径/统计)。网页 GET 不受影响。');\n\nconst maxCount = z\n .number()\n .int()\n .min(1)\n .max(10000)\n .optional()\n .describe('最多返回的提交数量。');\n\n/** 全部只读工具共享的 schema(仅 repoPath 可选) */\nconst readonlyBase = { repoPath };\n\nexport const GitStatusSchema = z.object({ ...readonlyBase });\nexport type GitStatusArgs = z.infer<typeof GitStatusSchema>;\n\nexport const GitLogSchema = z.object({\n ...readonlyBase,\n maxCount,\n from: z.string().optional().describe('起始提交(含);与 to 配合表示范围 from..to'),\n to: z.string().optional().describe('结束提交(含)'),\n author: z.string().optional().describe('按作者过滤(支持子串)'),\n path: z.string().optional().describe('仅查看该路径的历史'),\n all: z.boolean().optional().describe('包含所有分支(--all)')\n});\nexport type GitLogArgs = z.infer<typeof GitLogSchema>;\n\nexport const GitDiffSchema = z.object({\n ...readonlyBase,\n from: z.string().optional().describe('起点提交'),\n to: z.string().optional().describe('终点提交'),\n path: z.string().optional().describe('限定的文件路径'),\n staged: z.boolean().optional().describe('查看已暂存(索引)差异'),\n maxPatchBytes: z.number().int().positive().optional().describe('diff 正文最大字节数,超出截断'),\n detail\n});\nexport type GitDiffArgs = z.infer<typeof GitDiffSchema>;\n\nexport const GitShowSchema = z.object({\n ...readonlyBase,\n commit: z.string().describe('要查看的提交 hash'),\n path: z.string().optional().describe('限定文件'),\n maxPatchBytes: z.number().int().positive().optional(),\n detail\n});\nexport type GitShowArgs = z.infer<typeof GitShowSchema>;\n\nexport const GitBranchListSchema = z.object({ ...readonlyBase });\nexport type GitBranchListArgs = z.infer<typeof GitBranchListSchema>;\n\nexport const GitTagListSchema = z.object({ ...readonlyBase });\nexport type GitTagListArgs = z.infer<typeof GitTagListSchema>;\n\nexport const GitRemoteListSchema = z.object({ ...readonlyBase });\nexport type GitRemoteListArgs = z.infer<typeof GitRemoteListSchema>;\n\nexport const GitFileContentSchema = z.object({\n ...readonlyBase,\n commit: z.string().describe('提交 hash(如 HEAD、main)'),\n path: z.string().describe('仓库内文件相对路径'),\n detail\n});\nexport type GitFileContentArgs = z.infer<typeof GitFileContentSchema>;\n\nexport const GitGraphSchema = z.object({\n ...readonlyBase,\n maxCount: z.number().int().min(1).max(5000).optional().describe('最大提交数')\n});\nexport type GitGraphArgs = z.infer<typeof GitGraphSchema>;\n\nexport const GitBranchGraphSchema = z.object({\n ...readonlyBase,\n maxNodes: z.number().int().min(1).max(2000).optional().describe('rev-list 最多枚举的提交数,缺省 200'),\n into: z.string().optional().describe('合入目标(线上 / ours)。与 from 一起时返回 lineage'),\n from: z.string().optional().describe('我的分支(theirs)。与 into 一起时返回 lineage')\n});\nexport type GitBranchGraphArgs = z.infer<typeof GitBranchGraphSchema>;\n\nexport const GitReflogSchema = z.object({\n ...readonlyBase,\n maxCount: z.number().int().min(1).max(500).optional().describe('最多返回条数,缺省 50')\n});\nexport type GitReflogArgs = z.infer<typeof GitReflogSchema>;\n\nconst mergeIntoFrom = {\n into: z.string().min(1).describe('合入目标(线上 / ours / 预演左侧)。例如 origin/main'),\n from: z.string().min(1).describe('我的分支(theirs / 预演右侧)。例如 feature/x'),\n fetch: z.boolean().optional().describe('是否先非交互 fetch。缺省 true;失败则用本地引用并标明 stale'),\n remote: z.string().optional().describe('fetch/push 使用的远程名,缺省 origin'),\n path: z.string().optional().describe('仅关心该冲突文件路径')\n};\n\nexport const GitMergePreviewSchema = z.object({\n ...readonlyBase,\n ...mergeIntoFrom\n});\nexport type GitMergePreviewArgs = z.infer<typeof GitMergePreviewSchema>;\n\nexport const GitMergeRehearseSchema = z.object({\n ...readonlyBase,\n ...mergeIntoFrom,\n maxFiles: z.number().int().min(1).max(100).optional().describe('最多生成冲突正文的文件数,缺省 20'),\n detail\n});\nexport type GitMergeRehearseArgs = z.infer<typeof GitMergeRehearseSchema>;\n\nexport const GitMergeBlameSchema = z.object({\n ...readonlyBase,\n into: z.string().min(1).describe('合入目标(线上 / ours)'),\n from: z.string().min(1).describe('我的分支(theirs)'),\n path: z.string().min(1).describe('要溯源的冲突文件路径'),\n fetch: z.boolean().optional().describe('是否先非交互 fetch。缺省 false(预演之后按需拉)'),\n remote: z.string().optional().describe('fetch 使用的远程名,缺省 origin')\n});\nexport type GitMergeBlameArgs = z.infer<typeof GitMergeBlameSchema>;\n\nexport const GitMergeSurveySchema = z.object({\n ...readonlyBase,\n intos: z.array(z.string().min(1)).min(1).describe('合入目标(线上 / ours)列表'),\n froms: z.array(z.string().min(1)).min(1).describe('我的分支(theirs)列表'),\n fetch: z.boolean().optional().describe('是否先非交互 fetch。缺省 true;整批只 fetch 一次'),\n remote: z.string().optional().describe('fetch 使用的远程名,缺省 origin'),\n async: z\n .boolean()\n .optional()\n .describe('为 true 或格子数>20 时后台跑,立即返回 jobId,用 git_job_get 查结果')\n});\nexport type GitMergeSurveyArgs = z.infer<typeof GitMergeSurveySchema>;\n\nexport const GitMergeOrderSchema = z.object({\n ...readonlyBase,\n into: z.string().min(1).describe('合入目标(线上 / ours)'),\n branches: z.array(z.string().min(1)).min(2).describe('待依次合入的来源分支(至少 2 个)'),\n fetch: z.boolean().optional().describe('是否先非交互 fetch。缺省 true'),\n remote: z.string().optional().describe('fetch 使用的远程名,缺省 origin')\n});\nexport type GitMergeOrderArgs = z.infer<typeof GitMergeOrderSchema>;\n\n/** 写操作公共参数 */\nconst writeBase = { repoPath, dryRun };\nconst pathsField = z.array(z.string()).default([]).describe('文件路径列表;缺省为空即全部文件');\n\nexport const GitAddSchema = z.object({ ...writeBase, paths: pathsField });\nexport type GitAddArgs = z.infer<typeof GitAddSchema>;\n\nexport const GitUnstageSchema = z.object({ ...writeBase, paths: pathsField });\nexport type GitUnstageArgs = z.infer<typeof GitUnstageSchema>;\n\nexport const GitCommitSchema = z.object({\n ...writeBase,\n message: z.string().min(1).describe('提交信息'),\n paths: z.array(z.string()).optional().describe('仅提交这些路径(可空)'),\n allowEmpty: z.boolean().optional().describe('允许空提交(--allow-empty)')\n});\nexport type GitCommitArgs = z.infer<typeof GitCommitSchema>;\n\nexport const GitCheckoutSchema = z.object({\n ...writeBase,\n branch: z.string().describe('要切换到的分支名')\n});\nexport type GitCheckoutArgs = z.infer<typeof GitCheckoutSchema>;\n\nexport const GitBranchCreateSchema = z.object({\n ...writeBase,\n name: z.string().describe('新分支名'),\n startPoint: z.string().optional().describe('创建起点(提交/分支),缺省为当前 HEAD')\n});\nexport type GitBranchCreateArgs = z.infer<typeof GitBranchCreateSchema>;\n\nexport const GitBranchDeleteSchema = z.object({\n ...writeBase,\n name: z.string().describe('要删除的分支名(未合并分支会被拒绝)')\n});\nexport type GitBranchDeleteArgs = z.infer<typeof GitBranchDeleteSchema>;\n\nexport const GitMergeSchema = z.object({\n ...writeBase,\n branch: z.string().describe('要合并进来的分支名')\n});\nexport type GitMergeArgs = z.infer<typeof GitMergeSchema>;\n\nexport const GitPullSchema = z.object({\n ...writeBase,\n remote: z.string().optional().describe('远程名(缺省 origin)'),\n branch: z.string().optional().describe('远端分支名')\n});\nexport type GitPullArgs = z.infer<typeof GitPullSchema>;\n\nexport const GitFetchSchema = z.object({\n ...writeBase,\n remote: z.string().optional().describe('远程名(缺省 origin)')\n});\nexport type GitFetchArgs = z.infer<typeof GitFetchSchema>;\n\nconst continueFiles = z\n .array(\n z.object({\n path: z.string().describe('仓库内相对路径'),\n resolvedContent: z.string().describe('该文件解决后的完整内容')\n })\n )\n .optional()\n .describe('已解决冲突的文件;写入工作区并 git add 后再 continue。已在编辑器解决并可为空');\n\nexport const GitMergeAbortSchema = z.object({ ...writeBase });\nexport type GitMergeAbortArgs = z.infer<typeof GitMergeAbortSchema>;\n\nexport const GitMergeContinueSchema = z.object({\n ...writeBase,\n files: continueFiles\n});\nexport type GitMergeContinueArgs = z.infer<typeof GitMergeContinueSchema>;\n\nexport const GitRebaseAbortSchema = z.object({ ...writeBase });\nexport type GitRebaseAbortArgs = z.infer<typeof GitRebaseAbortSchema>;\n\nexport const GitRebaseContinueSchema = z.object({\n ...writeBase,\n files: continueFiles\n});\nexport type GitRebaseContinueArgs = z.infer<typeof GitRebaseContinueSchema>;\n\nexport const GitPushSchema = z.object({\n ...writeBase,\n remote: z.string().optional().describe('远程名(缺省 origin)'),\n branch: z.string().optional().describe('分支名')\n});\nexport type GitPushArgs = z.infer<typeof GitPushSchema>;\n\nexport const GitTagCreateSchema = z.object({\n ...writeBase,\n name: z.string().describe('标签名'),\n message: z.string().optional().describe('附注标签消息(带则创建 annotated tag)'),\n commit: z.string().optional().describe('打标签的提交,缺省为 HEAD')\n});\nexport type GitTagCreateArgs = z.infer<typeof GitTagCreateSchema>;\n\nexport const GitStashSchema = z.object({\n ...writeBase,\n message: z.string().optional().describe('stash 消息'),\n includeUntracked: z.boolean().optional().describe('包含未跟踪文件(-u)'),\n paths: pathsField.describe('仅暂存这些文件(对应 WebStorm Shelve 的选择性暂存;空则暂存全部)')\n});\nexport type GitStashArgs = z.infer<typeof GitStashSchema>;\n\nexport const GitStashListSchema = z.object({ ...readonlyBase });\nexport type GitStashListArgs = z.infer<typeof GitStashListSchema>;\n\nexport const GitStashShowSchema = z.object({\n ...readonlyBase,\n index: z.number().int().min(0).optional().describe('stash 序号,缺省为 stash@{0}'),\n maxPatchBytes: z.number().int().positive().optional().describe('diff 正文最大字节数,超出截断'),\n detail\n});\n\nexport const GitRepoOverviewSchema = z.object({ ...readonlyBase, detail });\nexport type GitRepoOverviewArgs = z.infer<typeof GitRepoOverviewSchema>;\n\nexport const GitJobListSchema = z.object({ ...readonlyBase });\nexport type GitJobListArgs = z.infer<typeof GitJobListSchema>;\n\nexport const GitJobGetSchema = z.object({\n ...readonlyBase,\n id: z.string().min(1).describe('后台任务 id')\n});\nexport type GitJobGetArgs = z.infer<typeof GitJobGetSchema>;\n\nexport const GitJobCancelSchema = z.object({\n ...writeBase,\n id: z.string().min(1).describe('要取消的后台任务 id')\n});\nexport type GitJobCancelArgs = z.infer<typeof GitJobCancelSchema>;\nexport type GitStashShowArgs = z.infer<typeof GitStashShowSchema>;\n\nexport const GitStashApplySchema = z.object({\n ...writeBase,\n index: z.number().int().min(0).optional().describe('stash 序号,缺省为 stash@{0}')\n});\nexport type GitStashApplyArgs = z.infer<typeof GitStashApplySchema>;\n\nexport const GitStashDropSchema = z.object({\n ...writeBase,\n index: z.number().int().min(0).optional().describe('stash 序号,缺省为 stash@{0}')\n});\nexport type GitStashDropArgs = z.infer<typeof GitStashDropSchema>;\n\nexport const GitStashPopSchema = z.object({\n ...writeBase,\n index: z.number().int().min(0).optional().describe('stash 序号,缺省为最新的 stash@{0}')\n});\nexport type GitStashPopArgs = z.infer<typeof GitStashPopSchema>;\n\nexport const GitApplyResolveSchema = z.object({\n ...writeBase,\n into: z.string().min(1).describe('合入目标(线上 / ours)。例如 origin/main'),\n from: z.string().min(1).describe('我的分支(theirs)。例如 feature/x'),\n remote: z.string().optional().describe('push 使用的远程名,缺省 origin'),\n files: z\n .array(\n z.object({\n path: z.string().describe('仓库内相对路径'),\n resolvedContent: z.string().describe('该文件解决后的完整内容')\n })\n )\n .optional()\n .describe('已解决冲突的文件。干净合并可省略或传空数组'),\n push: z.boolean().optional().describe('是否推送临时分支,缺省 true'),\n keepLocal: z.boolean().optional().describe('推送失败时仍保留本地临时分支'),\n tempBranch: z.string().optional().describe('自定义临时分支名;缺省 merge/<from>-into-<into>')\n});\nexport type GitApplyResolveArgs = z.infer<typeof GitApplyResolveSchema>;\n\nconst mrIntoFrom = {\n into: z.string().min(1).describe('合入目标(线上 / ours)。例如 origin/main'),\n from: z.string().min(1).describe('我的分支(theirs)。例如 feature/x'),\n remote: z.string().optional().describe('远程名,缺省 origin'),\n sourceBranch: z.string().optional().describe('PR 源分支;缺省已有临时分支 merge/<from>-into-<into>,否则 from')\n};\n\nexport const GitMrPrepareSchema = z.object({\n ...readonlyBase,\n ...mrIntoFrom\n});\nexport type GitMrPrepareArgs = z.infer<typeof GitMrPrepareSchema>;\n\nexport const GitMrCreateSchema = z.object({\n ...writeBase,\n ...mrIntoFrom,\n title: z.string().optional().describe('PR 标题;缺省 Merge <source> into <target>'),\n body: z.string().optional().describe('PR 正文'),\n reviewers: z.array(z.string()).optional().describe('审核人/指派人用户名;GitLab 会解析成数字 id。Token 不在此传入')\n});\nexport type GitMrCreateArgs = z.infer<typeof GitMrCreateSchema>;\n\n/** 高风险工具 */\nexport const GitResetHardSchema = z.object({ ...writeBase, target: z.string().describe('要重置到的提交') });\nexport type GitResetHardArgs = z.infer<typeof GitResetHardSchema>;\n\nexport const GitCleanSchema = z.object({ ...writeBase });\nexport type GitCleanArgs = z.infer<typeof GitCleanSchema>;\n\nexport const GitPushForceSchema = z.object({\n ...writeBase,\n remote: z.string().optional(),\n branch: z.string().optional()\n});\nexport type GitPushForceArgs = z.infer<typeof GitPushForceSchema>;\n\nexport const GitBranchDeleteForceSchema = z.object({\n ...writeBase,\n name: z.string().describe('要强制删除的分支名')\n});\nexport type GitBranchDeleteForceArgs = z.infer<typeof GitBranchDeleteForceSchema>;\n\nexport const GitRebaseSchema = z.object({\n ...writeBase,\n branch: z.string().describe('要变基到的分支/提交')\n});\nexport type GitRebaseArgs = z.infer<typeof GitRebaseSchema>;","/**\n * MCP Prompt:。正文抄仓库根 README「Agent 该怎么用」,不许另写流程\n */\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\n\nconst PREAMBLE = [\n '不要用终端 git 代替「预演、落盘、开 PR」。',\n '默认只给摘要;要看某文件正文时再说路径,或加 `detail=true`。写操作先干跑(`dry_run=true`)。高风险操作默认关着。'\n].join('\\n');\n\nexport const MCP_PROMPTS = [\n {\n name: 'safe_commit',\n title: '提交',\n description: '先看改了什么,再暂存、再提交。不要一上来就提交。',\n text: [\n PREAMBLE,\n '',\n '1. 提交',\n '先看工作区有没有改、改了什么,再暂存,再提交。不要一上来就提交。',\n '',\n '对应工具:`git_status` → `git_diff` → 按需 `git_add` → `git_commit`。'\n ].join('\\n')\n },\n {\n name: 'merge_preview_apply',\n title: '合不合得进去,以及写进仓库',\n description: '只做预演,人选边,独立目录落盘。工作区已经卡住时不要走这条。',\n text: [\n PREAMBLE,\n '',\n '2. 合不合得进去,以及写进仓库',\n '先看工作区是不是已经卡在 merge / rebase 里。卡住了走「工作区已经卡在 merge 或 rebase 里」,不要走这条。',\n '',\n '问能不能合进去时,只做预演,不要在当前工作区执行 merge。`into` 是要合进去的目标(线上),`from` 是你的分支。有冲突时把正文给人看、人选边,不要让模型自动选。',\n '',\n '看完要写进仓库:用独立目录落盘,不要切走你正在干活的分支。',\n '',\n '对应工具:`git_merge_preview` / `git_merge_rehearse`(冲突行是谁改的用 `git_merge_blame`)→ `git_apply_resolve`。禁止用 `git_merge` 冒充预演。'\n ].join('\\n')\n },\n {\n name: 'workspace_continue',\n title: '工作区已经卡在 merge 或 rebase 里',\n description: '看状态,然后继续或放弃。不要用预演落盘去收尾。',\n text: [\n PREAMBLE,\n '',\n '3. 工作区已经卡在 merge 或 rebase 里',\n '这是另一回事:冲突已经发生在当前目录了。看状态,然后继续或放弃。不要用「合不合得进去,以及写进仓库」的落盘去收尾。',\n '',\n '对应工具:`git_status`(看 `operation`)→ `git_merge_continue` / `git_rebase_continue` 或 abort。禁止用 `git_apply_resolve`。'\n ].join('\\n')\n },\n {\n name: 'open_mr',\n title: '开 Pull Request / Merge Request',\n description: '先准备标题和目标分支,再创建。Token 在网页设置里,不要塞进工具参数。',\n text: [\n PREAMBLE,\n '',\n '4. 开 Pull Request / Merge Request',\n '先准备标题和目标分支等信息,再创建。登录用的 Token 写在网页设置里,不要塞进工具参数。',\n '',\n '对应工具:`git_mr_prepare` → `git_mr_create`。'\n ].join('\\n')\n }\n] as const;\n\nexport function registerMcpPrompts(server: McpServer): void {\n const register = server.registerPrompt.bind(server);\n for (const p of MCP_PROMPTS) {\n register(p.name, { title: p.title, description: p.description }, () => ({\n description: p.description,\n messages: [{ role: 'user' as const, content: { type: 'text' as const, text: p.text } }]\n }));\n }\n}\n","/**\n * MCP Resources:只读、不进审计。形状与 git_repo_overview / git_job_* 摘要同源。\n */\nimport { McpServer, ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { Runtime } from '../runtime.ts';\nimport { collectRepoOverviews } from '../overview.ts';\n\nconst MIME = 'application/json';\n\nfunction jsonContents(uri: string, data: unknown) {\n return {\n contents: [\n {\n uri,\n mimeType: MIME,\n text: JSON.stringify(data)\n }\n ]\n };\n}\n\nfunction overviewWithoutDays(runtime: Runtime) {\n return collectRepoOverviews(runtime).then((repos) =>\n repos.map((row) => {\n const { activity: _days, ...rest } = row;\n return rest;\n })\n );\n}\n\nexport function registerMcpResources(server: McpServer, runtime: Runtime): void {\n const register = server.registerResource.bind(server);\n\n register(\n 'repos',\n 'git-cockpit://repos',\n { title: '已打开仓库脉搏', description: '与 git_repo_overview 同摘要,不含每日格子', mimeType: MIME },\n async (uri) => jsonContents(uri.href, { repos: await overviewWithoutDays(runtime) })\n );\n\n register(\n 'repo-current',\n 'git-cockpit://repo/current',\n { title: '最近打开仓', description: '最近打开仓库的工作区摘要,不含文件列表正文', mimeType: MIME },\n async (uri) => {\n const handle = await runtime.repoManager.getCurrent();\n if (!handle) {\n return jsonContents(uri.href, { available: false, hint: '没有已打开的仓库' });\n }\n const s = await handle.service.getStatus();\n return jsonContents(uri.href, {\n available: true,\n path: handle.record.path,\n current: s.current,\n tracking: s.tracking,\n ahead: s.ahead,\n behind: s.behind,\n operation: s.operation,\n isClean: s.isClean,\n stagedCount: s.staged.length,\n unstagedCount: s.unstaged.length,\n untrackedCount: s.untracked.length,\n conflictCount: s.conflicted.length,\n conflicted: s.conflicted.slice(0, 20)\n });\n }\n );\n\n register(\n 'jobs',\n 'git-cockpit://jobs',\n { title: '后台任务列表', description: '与 git_job_list 同摘要', mimeType: MIME },\n async (uri) =>\n jsonContents(uri.href, {\n jobs: runtime.jobs.list().map((j) => runtime.jobs.summary(j))\n })\n );\n\n register(\n 'job',\n new ResourceTemplate('git-cockpit://jobs/{id}', {\n list: async () => ({\n resources: runtime.jobs.list().map((j) => ({\n uri: `git-cockpit://jobs/${j.id}`,\n name: j.title,\n description: `${j.kind} ${j.status}`,\n mimeType: MIME\n }))\n })\n }),\n { title: '单条后台任务', description: '状态 + 日志尾 + result 摘要', mimeType: MIME },\n async (uri, variables) => {\n const id = String(variables.id ?? '');\n const job = runtime.jobs.get(id);\n if (!job) {\n return jsonContents(uri.href, { error: '任务不存在', id });\n }\n const summary = runtime.jobs.summary(job);\n return jsonContents(uri.href, {\n ...summary,\n logs: job.logs.slice(-20)\n });\n }\n );\n}\n"],"mappings":"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","names":["McpServer","detail","dryRun","repoPath","BackupManager","GitOperationError","z","BackupManager","GitOperationError","McpServer","session"]}
|
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
import {
|
|
3
3
|
createRuntime,
|
|
4
4
|
createWebServer
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-XNW2ZKY3.js";
|
|
6
6
|
import {
|
|
7
7
|
startMcpStdio,
|
|
8
8
|
version
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-I7QFIFI2.js";
|
|
10
10
|
|
|
11
11
|
// src/cli.ts
|
|
12
12
|
function printHelp() {
|
|
@@ -66,4 +66,4 @@ async function main(argv) {
|
|
|
66
66
|
export {
|
|
67
67
|
main
|
|
68
68
|
};
|
|
69
|
-
//# sourceMappingURL=chunk-
|
|
69
|
+
//# sourceMappingURL=chunk-NSG4PZRX.js.map
|