@shaohui_jin/git-cockpit-mcp-server 0.1.19 → 0.1.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -53,13 +53,13 @@ git-cockpit version # 输出版本号
53
53
  **1. 提交** — 先看改了什么,再暂存、再提交。写之前先 `dry_run=true`。
54
54
  `git_status` → `git_diff` → 按需 `git_add` → `git_commit`。
55
55
 
56
- **2. 合不合得进去,以及写进仓库** — 先看工作区是不是已经卡在 merge / rebase 里(卡住了走第 3 条)。问能不能合时只做预演,不要在当前目录 merge。`into` 是线上目标,`from` 是你的分支。人选边,模型不要自动选。写进仓库用独立目录落盘(`git_apply_resolve`),不要用 `git_merge` 冒充预演。
56
+ **2. 合不合得进去,以及写进仓库** — 先看工作区是不是已经卡在 merge / rebase 里(卡住了走第 3 条)。问能不能合时只做预演,不要在当前目录 merge。`into` 是线上目标,`from` 是你的分支。有冲突把 `webUrl` 给人打开合并页,然后停止。不要选边,不要传 `files`。不要 `git_mr_create`(含 dry_run)。仅干净合并才 `git_apply_resolve`。不要用 `git_merge` 冒充预演。人口头说解决了不算:用原来的 into/from 再预演,认这一对的 `merge/<from>-into-<into>`。
57
57
 
58
- **3. 工作区已经卡在 merge 或 rebase 里** — 看状态,然后继续或放弃。不要用第 2 条的落盘去收尾。
59
- `git_status` → `git_merge_continue` / `git_rebase_continue` 或 abort。禁止 `git_apply_resolve`。
58
+ **3. 工作区已经卡在 merge 或 rebase 里** — 看状态。人先解决,再继续或放弃。不要传 `files`。不要用第 2 条的落盘去收尾。
59
+ `git_status` → `git_merge_continue` / `git_rebase_continue`(不要带 `files`)或 abort。禁止 `git_apply_resolve`。
60
60
 
61
- **4. 开 Pull Request / Merge Request** — 先准备信息再创建。Token 在网页设置里,不要塞进工具参数。
62
- `git_mr_prepare` → `git_mr_create`。
61
+ **4. 开 Pull Request / Merge Request** — 先预演。有冲突则停。干净则落盘并推送临时枝,再 `git_mr_prepare`;只有 `mergeGate.ok` 才 `git_mr_create`,且只 dry_run。Token 在网页设置里,不要塞进工具参数。
62
+ `git_merge_preview` → `git_apply_resolve` / `git_push` → `git_mr_prepare` → `git_mr_create`(只 dry_run)。
63
63
 
64
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
65
 
@@ -2,11 +2,11 @@
2
2
  import {
3
3
  createRuntime,
4
4
  createWebServer
5
- } from "./chunk-K7XHGELU.js";
5
+ } from "./chunk-ZQDJRSNS.js";
6
6
  import {
7
7
  startMcpStdio,
8
8
  version
9
- } from "./chunk-DPQSSEDA.js";
9
+ } from "./chunk-3LZDEB7B.js";
10
10
 
11
11
  // src/cli.ts
12
12
  function printHelp() {
@@ -22,6 +22,9 @@ function printHelp() {
22
22
  GIT_COCKPIT_DATA_DIR \u6570\u636E\u76EE\u5F55\uFF08\u9ED8\u8BA4 ~/.git-cockpit\uFF09
23
23
  GIT_COCKPIT_PORT \u7AEF\u53E3\uFF08\u9ED8\u8BA4 3000\uFF09
24
24
  GIT_COCKPIT_HOST \u76D1\u542C\u5730\u5740\uFF08\u9ED8\u8BA4 localhost\uFF09
25
+ GIT_COCKPIT_LLM_API_KEY \u5F00\u53D1\u53EF\u9009\uFF1A\u8986\u76D6\u8BBE\u7F6E\u91CC\u7684\u6A21\u578B Key\uFF0C\u4E0D\u5199\u56DE config.json
26
+ GIT_COCKPIT_LLM_MODEL \u5F00\u53D1\u53EF\u9009\uFF1A\u8986\u76D6\u6A21\u578B\u540D
27
+ GIT_COCKPIT_LLM_BASE_URL \u5F00\u53D1\u53EF\u9009\uFF1A\u8986\u76D6 OpenAI \u517C\u5BB9 Base URL
25
28
  `);
26
29
  }
27
30
  async function main(argv) {
@@ -66,4 +69,4 @@ async function main(argv) {
66
69
  export {
67
70
  main
68
71
  };
69
- //# sourceMappingURL=chunk-M7EO3ZCZ.js.map
72
+ //# sourceMappingURL=chunk-2ZYL4JZF.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli.ts"],"sourcesContent":["/**\n * CLI:`git-cockpit` 入口。\n * - git-cockpit start 启动常驻 daemon(Web 服务 + MCP Streamable HTTP),默认端口 3000;\n * - git-cockpit mcp 以 stdio 模式运行 MCP Server(供客户端直接拉起);\n * - git-cockpit version / --help。\n */\nimport { createRuntime, disposeRuntime } from './runtime.ts';\nimport { createWebServer } from './webServer.ts';\nimport { startMcpStdio } from './mcpServer.ts';\nimport { version } from '../package.json'\n\nfunction printHelp(): void {\n console.log(`Git Cockpit - 基于 MCP 的 Git 可视化操作工具\n\n用法:\n git-cockpit start 启动 daemon:Web 界面 + MCP Server(Streamable HTTP)\n git-cockpit mcp 以 stdio 模式运行 MCP Server(供 Claude Desktop / Cursor 配置)\n git-cockpit version 输出版本号\n git-cockpit help 显示帮助\n\n环境变量:\n GIT_COCKPIT_DATA_DIR 数据目录(默认 ~/.git-cockpit)\n GIT_COCKPIT_PORT 端口(默认 3000)\n GIT_COCKPIT_HOST 监听地址(默认 localhost)\n GIT_COCKPIT_LLM_API_KEY 开发可选:覆盖设置里的模型 Key,不写回 config.json\n GIT_COCKPIT_LLM_MODEL 开发可选:覆盖模型名\n GIT_COCKPIT_LLM_BASE_URL 开发可选:覆盖 OpenAI 兼容 Base URL\n`);\n}\n\nexport async function main(argv: string[]): Promise<number> {\n const args = argv.slice(2);\n const command = args[0] ?? 'start';\n\n if (command === 'help' || command === '--help' || command === '-h') {\n printHelp();\n return 0;\n }\n if (command === 'version' || command === '--version' || command === '-v') {\n console.log(version);\n return 0;\n }\n\n const dataDir = process.env.GIT_COCKPIT_DATA_DIR ?? '~/.git-cockpit';\n const runtime = createRuntime({ dataDir });\n\n if (command === 'mcp') {\n await startMcpStdio(runtime);\n return 0;\n }\n\n if (command === 'start') {\n const port = Number(process.env.GIT_COCKPIT_PORT) || runtime.config.server.port;\n const host = process.env.GIT_COCKPIT_HOST ?? runtime.config.server.host;\n const server = await createWebServer(runtime, { host, port });\n console.log(`[git-cockpit] Web UI: http://${host}:${port}`);\n console.log(`[git-cockpit] API 文档: http://${host}:${port}/docs`);\n console.log(`[git-cockpit] MCP (HTTP): http://${host}:${port}/mcp`);\n console.log(`[git-cockpit] 数据目录: ${dataDir}`);\n console.log(`[git-cockpit] Ctrl+C 退出`);\n return await new Promise<number>((resolve) => {\n const shutdown = () => {\n void server.close().then(() => resolve(0));\n };\n process.on('SIGINT', shutdown);\n process.on('SIGTERM', shutdown);\n });\n }\n\n console.error(`未知命令: ${command}`);\n printHelp();\n return 1;\n}\n\nexport { createRuntime, disposeRuntime };"],"mappings":";;;;;;;;;;;AAWA,SAAS,YAAkB;AACzB,UAAQ,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAeb;AACD;AAEA,eAAsB,KAAK,MAAiC;AAC1D,QAAM,OAAO,KAAK,MAAM,CAAC;AACzB,QAAM,UAAU,KAAK,CAAC,KAAK;AAE3B,MAAI,YAAY,UAAU,YAAY,YAAY,YAAY,MAAM;AAClE,cAAU;AACV,WAAO;AAAA,EACT;AACA,MAAI,YAAY,aAAa,YAAY,eAAe,YAAY,MAAM;AACxE,YAAQ,IAAI,OAAO;AACnB,WAAO;AAAA,EACT;AAEA,QAAM,UAAU,QAAQ,IAAI,wBAAwB;AACpD,QAAM,UAAU,cAAc,EAAE,QAAQ,CAAC;AAEzC,MAAI,YAAY,OAAO;AACrB,UAAM,cAAc,OAAO;AAC3B,WAAO;AAAA,EACT;AAEA,MAAI,YAAY,SAAS;AACvB,UAAM,OAAO,OAAO,QAAQ,IAAI,gBAAgB,KAAK,QAAQ,OAAO,OAAO;AAC3E,UAAM,OAAO,QAAQ,IAAI,oBAAoB,QAAQ,OAAO,OAAO;AACnE,UAAM,SAAS,MAAM,gBAAgB,SAAS,EAAE,MAAM,KAAK,CAAC;AAC5D,YAAQ,IAAI,qCAAqC,IAAI,IAAI,IAAI,EAAE;AAC/D,YAAQ,IAAI,8CAAoC,IAAI,IAAI,IAAI,OAAO;AACnE,YAAQ,IAAI,qCAAqC,IAAI,IAAI,IAAI,MAAM;AACnE,YAAQ,IAAI,gDAA4B,OAAO,EAAE;AACjD,YAAQ,IAAI,mCAAyB;AACrC,WAAO,MAAM,IAAI,QAAgB,CAAC,YAAY;AAC5C,YAAM,WAAW,MAAM;AACrB,aAAK,OAAO,MAAM,EAAE,KAAK,MAAM,QAAQ,CAAC,CAAC;AAAA,MAC3C;AACA,cAAQ,GAAG,UAAU,QAAQ;AAC7B,cAAQ,GAAG,WAAW,QAAQ;AAAA,IAChC,CAAC;AAAA,EACH;AAEA,UAAQ,MAAM,6BAAS,OAAO,EAAE;AAChC,YAAU;AACV,SAAO;AACT;","names":[]}
@@ -7,7 +7,7 @@ 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.19";
10
+ var version = "0.1.21";
11
11
 
12
12
  // src/tools/format.ts
13
13
  import { suggestNext } from "@shaohui_jin/git-cockpit-core";
@@ -224,12 +224,25 @@ async function executeTool(def, rawArgs, ctx) {
224
224
  }
225
225
 
226
226
  // src/tools/bindMcp.ts
227
+ var HIDE_FILES_ON_MCP = /* @__PURE__ */ new Set(["git_apply_resolve", "git_merge_continue", "git_rebase_continue"]);
228
+ function mcpInputSchema(def) {
229
+ if (!HIDE_FILES_ON_MCP.has(def.name)) return def.schema;
230
+ const schema = def.schema;
231
+ return typeof schema.omit === "function" ? schema.omit({ files: true }) : def.schema;
232
+ }
233
+ function mcpAnnotations(def) {
234
+ return {
235
+ readOnlyHint: def.risk === "readonly",
236
+ destructiveHint: def.risk === "dangerous",
237
+ openWorldHint: false
238
+ };
239
+ }
227
240
  function bindMcpTools(server, runtime, capabilities) {
228
241
  for (const def of capabilities) {
229
242
  const register = server.registerTool.bind(server);
230
243
  register(
231
244
  def.name,
232
- { description: def.description, inputSchema: def.schema },
245
+ { description: def.description, inputSchema: mcpInputSchema(def), annotations: mcpAnnotations(def) },
233
246
  async (args) => {
234
247
  const exec = await executeTool(def, args ?? {}, {
235
248
  runtime,
@@ -270,44 +283,44 @@ var MCP_PROMPTS = [
270
283
  {
271
284
  name: "merge_preview_apply",
272
285
  title: "\u5408\u4E0D\u5408\u5F97\u8FDB\u53BB\uFF0C\u4EE5\u53CA\u5199\u8FDB\u4ED3\u5E93",
273
- 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",
286
+ description: "\u53EA\u505A\u9884\u6F14\u3002\u6709\u51B2\u7A81\u7ED9\u4EBA\u7F51\u9875\uFF0C\u4E0D\u8981\u9009\u8FB9\u3002\u5DE5\u4F5C\u533A\u5DF2\u7ECF\u5361\u4F4F\u65F6\u4E0D\u8981\u8D70\u8FD9\u6761\u3002",
274
287
  text: [
275
288
  PREAMBLE,
276
289
  "",
277
290
  "2. \u5408\u4E0D\u5408\u5F97\u8FDB\u53BB\uFF0C\u4EE5\u53CA\u5199\u8FDB\u4ED3\u5E93",
278
291
  "\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",
279
292
  "",
280
- "\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",
293
+ "\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 webUrl \u7ED9\u4EBA\u6253\u5F00\u5408\u5E76\u9875\uFF08`/#/merge?into=&from=&preview=1`\uFF09\uFF0C\u7136\u540E\u505C\u6B62\u3002\u4E0D\u8981\u9009\u8FB9\uFF0C\u4E0D\u8981\u4F20 files / resolvedContent\uFF0C\u4E0D\u8981\u5728\u51B2\u7A81\u65F6 git_mr_create\uFF08\u542B dry_run\uFF09\u3002",
281
294
  "",
282
- "\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",
295
+ "\u770B\u5B8C\u8981\u5199\u8FDB\u4ED3\u5E93\uFF1A\u4EC5\u5E72\u51C0\u5408\u5E76\u624D\u7528\u72EC\u7ACB\u76EE\u5F55\u843D\u76D8\uFF0C\u4E0D\u8981\u5207\u8D70\u4F60\u6B63\u5728\u5E72\u6D3B\u7684\u5206\u652F\u3002\u4EBA\u53E3\u5934\u8BF4\u89E3\u51B3\u4E86\u4E0D\u7B97\uFF1A\u7528\u539F\u6765\u7684 into/from \u518D\u9884\u6F14\uFF0C\u8BA4\u8FD9\u4E00\u5BF9\u7684 `merge/<from>-into-<into>`\uFF08\u6216 `origin/merge/\u2026`\uFF09\u3002\u522B\u4EBA\u7684 `merge/*` \u5F53\u566A\u97F3\u3002",
283
296
  "",
284
- "\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"
297
+ "\u5BF9\u5E94\u5DE5\u5177\uFF1A`git_merge_preview` / `git_merge_rehearse`\uFF08\u51B2\u7A81\u884C\u662F\u8C01\u6539\u7684\u7528 `git_merge_blame`\uFF0C\u53EA\u8BFB\uFF09\u3002\u5E72\u51C0\u624D `git_apply_resolve`\u3002\u7981\u6B62\u7528 `git_merge` \u5192\u5145\u9884\u6F14\u3002"
285
298
  ].join("\n")
286
299
  },
287
300
  {
288
301
  name: "workspace_continue",
289
302
  title: "\u5DE5\u4F5C\u533A\u5DF2\u7ECF\u5361\u5728 merge \u6216 rebase \u91CC",
290
- description: "\u770B\u72B6\u6001\uFF0C\u7136\u540E\u7EE7\u7EED\u6216\u653E\u5F03\u3002\u4E0D\u8981\u7528\u9884\u6F14\u843D\u76D8\u53BB\u6536\u5C3E\u3002",
303
+ description: "\u770B\u72B6\u6001\u3002\u4EBA\u5148\u89E3\u51B3\uFF0C\u518D\u7EE7\u7EED\u6216\u653E\u5F03\u3002\u4E0D\u8981\u4F20 files\uFF0C\u4E0D\u8981\u7528\u9884\u6F14\u843D\u76D8\u53BB\u6536\u5C3E\u3002",
291
304
  text: [
292
305
  PREAMBLE,
293
306
  "",
294
307
  "3. \u5DE5\u4F5C\u533A\u5DF2\u7ECF\u5361\u5728 merge \u6216 rebase \u91CC",
295
- "\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",
308
+ "\u8FD9\u662F\u53E6\u4E00\u56DE\u4E8B\uFF1A\u51B2\u7A81\u5DF2\u7ECF\u53D1\u751F\u5728\u5F53\u524D\u76EE\u5F55\u4E86\u3002\u770B\u72B6\u6001\u3002\u4EBA\u5148\u5728\u7F16\u8F91\u5668\u6216\u7F51\u9875\u89E3\u51B3\uFF0C\u518D\u7EE7\u7EED\u6216\u653E\u5F03\u3002\u4E0D\u8981\u4F20 files\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",
296
309
  "",
297
- "\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"
310
+ "\u5BF9\u5E94\u5DE5\u5177\uFF1A`git_status`\uFF08\u770B `operation`\uFF09\u2192 `git_merge_continue` / `git_rebase_continue`\uFF08\u4E0D\u8981\u5E26 `files`\uFF09\u6216 abort\u3002\u7981\u6B62\u7528 `git_apply_resolve`\u3002"
298
311
  ].join("\n")
299
312
  },
300
313
  {
301
314
  name: "open_mr",
302
315
  title: "\u5F00 Pull Request / Merge Request",
303
- 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",
316
+ description: "\u5148\u9884\u6F14\uFF1B\u51B2\u7A81\u5219\u505C\u3002\u5E72\u51C0\u624D\u843D\u76D8\u5F00\u5355\u3002Token \u5728\u7F51\u9875\u8BBE\u7F6E\u91CC\uFF0C\u4E0D\u8981\u585E\u8FDB\u5DE5\u5177\u53C2\u6570\u3002",
304
317
  text: [
305
318
  PREAMBLE,
306
319
  "",
307
320
  "4. \u5F00 Pull Request / Merge Request",
308
- "\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",
321
+ "\u5148 `git_merge_preview`\u3002\u6709\u51B2\u7A81\u4E0D\u8981 `git_mr_create`\uFF08\u542B dry_run\uFF09\uFF0C\u628A webUrl \u7ED9\u4EBA\u5728\u7F51\u9875\u9009\u8FB9\u3002\u5E72\u51C0\u5219\u843D\u76D8\u5E76\u63A8\u9001\u4E34\u65F6\u679D\uFF0C\u518D `git_mr_prepare`\uFF1B\u53EA\u6709 `mergeGate.ok` \u624D `git_mr_create`\uFF0C\u4E14\u53EA dry_run \u9884\u89C8\u6B63\u6587\uFF0C\u4E0D\u8981\u628A\u5E72\u8DD1\u5F53\u786E\u8BA4\u5F00\u5355\u3002\u767B\u5F55\u7528\u7684 Token \u5199\u5728\u7F51\u9875\u8BBE\u7F6E\u91CC\uFF0C\u4E0D\u8981\u585E\u8FDB\u5DE5\u5177\u53C2\u6570\u3002",
309
322
  "",
310
- "\u5BF9\u5E94\u5DE5\u5177\uFF1A`git_mr_prepare` \u2192 `git_mr_create`\u3002"
323
+ "\u5BF9\u5E94\u5DE5\u5177\uFF1A`git_merge_preview` \u2192\uFF08\u51B2\u7A81\u5219\u505C\uFF09`git_apply_resolve` / `git_push` \u2192 `git_mr_prepare` \u2192 `git_mr_create`\uFF08\u53EA dry_run\uFF09\u3002"
311
324
  ].join("\n")
312
325
  }
313
326
  ];
@@ -431,12 +444,13 @@ function createMcpServer(runtime) {
431
444
  "4. \u672A\u6307\u5B9A repoPath \u65F6\u4F7F\u7528\u6700\u8FD1\u6253\u5F00\u7684\u4ED3\u5E93\uFF1B",
432
445
  "5. \u5408\u5E76\u9884\u6F14\u7528 git_merge_preview / git_merge_rehearse\uFF08merge-tree\uFF0C\u4E0D\u6539\u5DE5\u4F5C\u533A\uFF09\uFF0C",
433
446
  " into=\u5408\u5165\u76EE\u6807/\u7EBF\u4E0A\uFF0Cfrom=\u6211\u7684\u5206\u652F\uFF1B\u7981\u6B62\u7528 git_merge \u505A\u9884\u6F14\u3002",
434
- " \u51B2\u7A81\u884C\u4F5C\u8005\u7528 git_merge_blame\uFF08\u6309\u6587\u4EF6\u3001\u53EA\u8BFB\uFF09\u3002",
447
+ " \u51B2\u7A81\u884C\u4F5C\u8005\u7528 git_merge_blame\uFF08\u6309\u6587\u4EF6\u3001\u53EA\u8BFB\uFF0C\u4E0D\u662F\u9009\u8FB9\uFF09\u3002",
435
448
  " \u591A\u5206\u652F\u626B\u63CF\u7528 git_merge_survey\uFF1B\u5EFA\u8BAE\u5408\u5165\u987A\u5E8F\u7528 git_merge_order\u3002",
436
- "6. \u843D\u76D8\u7528 git_apply_resolve\uFF08\u72EC\u7ACB worktree\uFF0C\u4E3B\u533A\u4E0D\u5207\u6362\uFF09\uFF1B\u51B2\u7A81\u65F6\u628A\u9009\u8FB9\u540E\u7684 files \u4E00\u5E76\u4F20\u5165\u3002",
437
- "7. \u5DE5\u4F5C\u533A\u5DF2\u7ECF\u51B2\u7A81\uFF1Agit_merge_continue / git_rebase_continue\uFF08\u53EF\u5E26 files\uFF09\u6216 abort\uFF1B\u4E0D\u662F apply_resolve\u3002",
449
+ " \u6709\u51B2\u7A81\u53EA\u628A webUrl \u7ED9\u4EBA\u5728\u7F51\u9875\u9009\u8FB9\uFF1BAgent \u4E0D\u8981\u9009\u8FB9\u3001\u4E0D\u8981\u4F20 files / resolvedContent\u3002",
450
+ "6. \u843D\u76D8\u7528 git_apply_resolve\uFF08\u72EC\u7ACB worktree\uFF0C\u4E3B\u533A\u4E0D\u5207\u6362\uFF09\u3002\u4EC5\u5E72\u51C0\u5408\u5E76\u3002\u6709\u51B2\u7A81\u4E0D\u8981\u8C03\u7528\u3002",
451
+ "7. \u5DE5\u4F5C\u533A\u5DF2\u7ECF\u51B2\u7A81\uFF1A\u4EBA\u5148\u5728\u7F16\u8F91\u5668\u6216\u7F51\u9875\u89E3\u51B3\uFF0C\u518D git_merge_continue / git_rebase_continue\uFF08\u4E0D\u8981\u5E26 files\uFF09\u6216 abort\uFF1B\u4E0D\u662F apply_resolve\u3002",
438
452
  "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",
439
- "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",
453
+ "9. \u5F00 PR/MR\uFF1A\u5148 git_merge_preview\u3002\u6709\u51B2\u7A81\u4E0D\u8981 git_mr_create\uFF08\u542B dry_run\uFF09\uFF0C\u628A webUrl \u7ED9\u4EBA\u5728\u7F51\u9875\u9009\u8FB9\u3002\u5E72\u51C0\u5219\u843D\u76D8\u5E76\u63A8\u9001\u4E34\u65F6\u679D\uFF0C\u518D git_mr_prepare\uFF08\u770B mergeGate.ok\uFF09\u2192 git_mr_create \u53EA dry_run\u3002\u65B9\u5F0F\u4E0E Token \u5728\u8BBE\u7F6E MR \u914D\u7F6E\uFF08\u4E0D\u8FDB\u5DE5\u5177\u53C2\u6570\uFF09\u3002\u627E\u4E0D\u5230 CLI \u65F6\u7ED3\u679C\u542B\u5B98\u65B9\u5B89\u88C5\u5730\u5740\u3002",
440
454
  "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",
441
455
  "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",
442
456
  "12. worktree \u5217\u8868/\u6DFB\u52A0/\u5220\u9664\u7528 git_worktree_list / git_worktree_add / git_worktree_remove\uFF1B\u4E0D\u8981\u628A linked worktree \u5F53\u6210\u7B2C\u4E8C\u5957\u5DE5\u4F5C\u533A\u505A merge\u3002",
@@ -474,7 +488,9 @@ var McpHttpHandler = class {
474
488
  return;
475
489
  }
476
490
  const transport = new StreamableHTTPServerTransport({
477
- sessionIdGenerator: () => randomUUID()
491
+ sessionIdGenerator: () => randomUUID(),
492
+ enableDnsRebindingProtection: true,
493
+ allowedHosts: ["127.0.0.1", "localhost", "[::1]"]
478
494
  });
479
495
  const server = createMcpServer(this.runtime);
480
496
  await server.connect(transport);
@@ -501,6 +517,7 @@ var McpHttpHandler = class {
501
517
  export {
502
518
  collectRepoOverviews,
503
519
  version,
520
+ summarizeForAgent,
504
521
  formatResultForMcp,
505
522
  executeTool,
506
523
  TOOL_DEFS,
@@ -512,4 +529,4 @@ export {
512
529
  startMcpStdio,
513
530
  McpHttpHandler
514
531
  };
515
- //# sourceMappingURL=chunk-DPQSSEDA.js.map
532
+ //# sourceMappingURL=chunk-3LZDEB7B.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/mcpServer.ts","../package.json","../src/tools/format.ts","../src/tools/handlers.ts","../src/host.ts","../src/overview.ts","../src/tools/bindMcp.ts","../src/tools/index.ts","../src/tools/prompts.ts","../src/tools/resources.ts"],"sourcesContent":["/**\n * MCP Server 装配:\n * - 基于官方 SDK 的 McpServer(tools 能力),注册全部工具;\n * - 支持 stdio(独立子进程模式)与 Streamable HTTP(daemon 转发模式)两种传输。\n *\n * 所有工具共用 executeCapability 安全链路(权限/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 { bindMcpTools } from './tools/bindMcp.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 ' 有冲突只把 webUrl 给人在网页选边;Agent 不要选边、不要传 files / resolvedContent。',\n '6. 落盘用 git_apply_resolve(独立 worktree,主区不切换)。仅干净合并。有冲突不要调用。',\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_merge_preview。有冲突不要 git_mr_create(含 dry_run),把 webUrl 给人在网页选边。干净则落盘并推送临时枝,再 git_mr_prepare(看 mergeGate.ok)→ git_mr_create 只 dry_run。方式与 Token 在设置 MR 配置(不进工具参数)。找不到 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. worktree 列表/添加/删除用 git_worktree_list / git_worktree_add / git_worktree_remove;不要把 linked worktree 当成第二套工作区做 merge。',\n '13. 提交 / 预演落盘 / 工作区收尾 / 开 PR 用 Prompt:safe_commit、merge_preview_apply、workspace_continue、open_mr(正文与 README「Agent 该怎么用」相同)。',\n '14. 只读列表可读 Resource:git-cockpit://repos、git-cockpit://repo/current、git-cockpit://jobs、git-cockpit://jobs/{id}。'\n ].join('\\n')\n }\n );\n\n bindMcpTools(server, runtime, TOOL_DEFS);\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 enableDnsRebindingProtection: true,\n allowedHosts: ['127.0.0.1', 'localhost', '[::1]']\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.21\",\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 \"@ai-sdk/openai\": \"^4.0.66\",\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 \"ai\": \"^7.0.99\",\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 文本输出:默认摘要,正文靠 path / detail。\n * Web REST / executeTool.result 仍是完整对象,不走这里。\n */\nimport { suggestNext } from '@shaohui_jin/git-cockpit-core';\nimport type { ExecutionResult } from '@shaohui_jin/git-cockpit-core';\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 return {\n ...r,\n conflictFiles: paths,\n detailAvailable: true\n };\n}\n\nfunction attachNext(tool: string, result: unknown, args: Record<string, unknown>, dryRun: boolean): unknown {\n const rec = asRecord(result);\n if (!rec) return result;\n if (Array.isArray(rec.next) && rec.next.length) return result;\n const next = suggestNext(tool, result, args, { dryRun });\n if (!next.length) return result;\n return { ...rec, next };\n}\n\n/** 把完整工具结果收成 Agent 默认可消化的形状 */\nexport function summarizeForAgent(\n tool: string,\n result: unknown,\n args: Record<string, unknown> = {},\n dryRun = false\n): unknown {\n if (result == null) return result;\n const detail = wantsDetail(args);\n const pathSet = hasPath(args);\n\n let summarized: unknown = result;\n if (tool === 'git_diff' || tool === 'git_stash_show') {\n summarized = detail || pathSet ? result : stripDiffPatch(result);\n } else if (tool === 'git_show') {\n if (detail || pathSet) {\n summarized = result;\n } else {\n const row = asRecord(result);\n summarized = row ? { ...row, diff: stripDiffPatch(row.diff) } : result;\n }\n } else if (tool === 'git_merge_rehearse') {\n summarized = detail || pathSet ? result : stripRehearseBodies(result);\n } else if (tool === 'git_repo_overview') {\n if (!detail) {\n const row = asRecord(result);\n const repos = Array.isArray(row?.repos) ? row.repos : [];\n summarized = {\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 } else if (tool === 'git_file_content') {\n if (!detail) {\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) {\n summarized = {\n path: args.path,\n truncated: true,\n bytes,\n detailAvailable: true\n };\n }\n }\n }\n\n return attachNext(tool, summarized, args, dryRun);\n}\n\n/** 把干运行/真实结果统一包成 MCP 文本输出 */\nexport function formatResultForMcp(exec: ExecutionResult): 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 ?? {}, exec.dryRun);\n const rec = asRecord(summarized);\n const next = Array.isArray(rec?.next) ? rec.next : [];\n if (next.length) {\n const names = next\n .map((step) => asRecord(step)?.tool)\n .filter((n): n is string => typeof n === 'string' && n.length > 0);\n if (names.length) parts.push(`next: ${names.join(' → ')}`);\n }\n const payload = typeof summarized === 'string' ? summarized : JSON.stringify(summarized);\n parts.push(payload);\n return parts.join('\\n\\n');\n}\n","/**\n * 工具执行层:MCP / Web / CLI 共用。安全链路在 core executeCapability。\n */\nimport { executeCapability } from '@shaohui_jin/git-cockpit-core';\nimport type { Capability, ExecutionResult } from '@shaohui_jin/git-cockpit-core';\nimport { hostFromRuntime } from '../host.ts';\nimport type { Runtime } from '../runtime.ts';\n\nexport type ToolDef = Capability;\nexport type ToolExecutionResult = ExecutionResult;\n\nexport interface ToolExecutionContext {\n runtime: Runtime;\n source: 'mcp' | 'web' | 'cli' | 'chat';\n /** 上层已解析的仓库(Web 路由提供 repoId,MCP 可通过 tool args 的 repoPath 提供) */\n repoId?: number;\n repoPath?: string;\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 return executeCapability(def, rawArgs, {\n source: ctx.source,\n repoId: ctx.repoId,\n repoPath: ctx.repoPath,\n host: hostFromRuntime(ctx.runtime)\n });\n}\n\nexport { formatResultForMcp, summarizeForAgent } from './format.ts';\n","import { GitOperationError } from '@shaohui_jin/git-cockpit-core';\nimport type { CapabilityHost } from '@shaohui_jin/git-cockpit-core';\nimport { collectRepoOverviews } from './overview.ts';\nimport type { Runtime } from './runtime.ts';\n\n/** 把进程壳 Runtime 收成 core executor 认识的 CapabilityHost */\nexport function hostFromRuntime(runtime: Runtime): CapabilityHost {\n return {\n config: runtime.config,\n permissions: runtime.permissions,\n auditLogger: runtime.auditLogger,\n eventBus: runtime.eventBus,\n jobs: runtime.jobs,\n async resolveRepo({ repoId, repoPath, argsPath }) {\n if (repoId !== undefined) {\n const handle = await runtime.repoManager.getById(repoId);\n if (handle) return { git: handle.service, repoPath: handle.service.repoPath };\n throw new GitOperationError(`仓库不存在: id=${repoId}`, 'REPO_NOT_FOUND');\n }\n if (repoPath) {\n const handle = runtime.repoManager.getByPath(repoPath);\n return { git: handle.service, repoPath: handle.service.repoPath };\n }\n if (argsPath) {\n const handle = await runtime.repoManager.open(argsPath);\n return { git: handle.service, repoPath: handle.service.repoPath };\n }\n const current = await runtime.repoManager.getCurrent();\n if (!current) {\n throw new GitOperationError('尚未打开任何仓库。请先打开仓库或提供 repoPath 参数。', 'NO_ACTIVE_REPO');\n }\n return { git: current.service, repoPath: current.service.repoPath };\n },\n listOverviews: () => collectRepoOverviews(runtime)\n };\n}\n","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 * 把 Capability 登记成 MCP tool。SDK registerTool 必须 bind(server),\n * 抽成裸函数会丢 this,注册时抛 TypeError 导致握手挂起。\n */\nimport type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport type { Capability } from '@shaohui_jin/git-cockpit-core';\nimport type { Runtime } from '../runtime.ts';\nimport { formatResultForMcp } from './format.ts';\nimport { executeTool } from './handlers.ts';\n\nconst HIDE_FILES_ON_MCP = new Set(['git_apply_resolve', 'git_merge_continue', 'git_rebase_continue']);\n\nfunction mcpInputSchema(def: Capability): unknown {\n if (!HIDE_FILES_ON_MCP.has(def.name)) return def.schema;\n const schema = def.schema as { omit?: (mask: { files: true }) => unknown };\n return typeof schema.omit === 'function' ? schema.omit({ files: true }) : def.schema;\n}\n\nfunction mcpAnnotations(def: Capability): {\n readOnlyHint: boolean;\n destructiveHint: boolean;\n openWorldHint: boolean;\n} {\n return {\n readOnlyHint: def.risk === 'readonly',\n destructiveHint: def.risk === 'dangerous',\n openWorldHint: false\n };\n}\n\nexport function bindMcpTools(server: McpServer, runtime: Runtime, capabilities: readonly Capability[]): void {\n for (const def of capabilities) {\n const register = server.registerTool.bind(server) as unknown as (\n name: string,\n config: { title?: string; description?: string; inputSchema?: unknown; annotations?: unknown },\n cb: (args: unknown, extra: unknown) => Promise<unknown>\n ) => unknown;\n\n register(\n def.name,\n { description: def.description, inputSchema: mcpInputSchema(def), annotations: mcpAnnotations(def) },\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","/**\n * 工具注册表:定义在 core/capabilities/git/*.ts。\n * 加载本模块时写入 Capability registry。新工具禁止只写在本包。\n */\nimport { getCapabilityRegistry, TOOL_DEFS, TOOL_DEF_MAP, toolSummaries } from '@shaohui_jin/git-cockpit-core';\nimport type { GitService } from '@shaohui_jin/git-cockpit-core';\n\ngetCapabilityRegistry().registerAll(TOOL_DEFS);\n\nexport { TOOL_DEFS, TOOL_DEF_MAP, toolSummaries };\nexport type { GitService };\n","/**\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` 是你的分支。有冲突时把 webUrl 给人打开合并页(`/#/merge?into=&from=&preview=1`),然后停止。不要选边,不要传 files / resolvedContent,不要在冲突时 git_mr_create(含 dry_run)。',\n '',\n '看完要写进仓库:仅干净合并才用独立目录落盘,不要切走你正在干活的分支。人口头说解决了不算:用原来的 into/from 再预演,认这一对的 `merge/<from>-into-<into>`(或 `origin/merge/…`)。别人的 `merge/*` 当噪音。',\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: '看状态。人先解决,再继续或放弃。不要传 files,不要用预演落盘去收尾。',\n text: [\n PREAMBLE,\n '',\n '3. 工作区已经卡在 merge 或 rebase 里',\n '这是另一回事:冲突已经发生在当前目录了。看状态。人先在编辑器或网页解决,再继续或放弃。不要传 files。不要用「合不合得进去,以及写进仓库」的落盘去收尾。',\n '',\n '对应工具:`git_status`(看 `operation`)→ `git_merge_continue` / `git_rebase_continue`(不要带 `files`)或 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 '先 `git_merge_preview`。有冲突不要 `git_mr_create`(含 dry_run),把 webUrl 给人在网页选边。干净则落盘并推送临时枝,再 `git_mr_prepare`;只有 `mergeGate.ok` 才 `git_mr_create`,且只 dry_run 预览正文,不要把干跑当确认开单。登录用的 Token 写在网页设置里,不要塞进工具参数。',\n '',\n '对应工具:`git_merge_preview` →(冲突则停)`git_apply_resolve` / `git_push` → `git_mr_prepare` → `git_mr_create`(只 dry_run)。'\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":";;;AAOA,SAAS,kBAAkB;AAE3B,SAAS,aAAAA,kBAAiB;AAC1B,SAAS,4BAA4B;AACrC,SAAS,qCAAqC;;;ACT5C,cAAW;;;ACEb,SAAS,mBAAmB;AAG5B,IAAM,qBAAqB,KAAK;AAEzB,SAAS,YAAY,MAAoD;AAC9E,SAAO,MAAM,WAAW;AAC1B;AAEA,SAAS,QAAQ,MAAoD;AACnE,SAAO,OAAO,MAAM,SAAS,YAAY,KAAK,KAAK,KAAK,EAAE,SAAS;AACrE;AAEA,SAAS,SAAS,OAAgD;AAChE,SAAO,UAAU,QAAQ,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,KAAK,IACrE,QACD;AACN;AAEA,SAAS,eAAe,MAAwB;AAC9C,QAAM,IAAI,SAAS,IAAI;AACvB,MAAI,CAAC,KAAK,EAAE,cAAc,GAAI,QAAO;AACrC,QAAM,EAAE,UAAU,MAAM,GAAG,KAAK,IAAI;AACpC,SAAO,EAAE,GAAG,MAAM,iBAAiB,KAAK;AAC1C;AAEA,SAAS,oBAAoB,QAA0B;AACrD,QAAM,IAAI,SAAS,MAAM;AACzB,MAAI,CAAC,EAAG,QAAO;AACf,QAAM,QAAQ,MAAM,QAAQ,EAAE,aAAa,IAAI,EAAE,gBAAgB,CAAC;AAClE,QAAM,QAAQ,MAAM,IAAI,CAAC,MAAM;AAC7B,UAAM,MAAM,SAAS,CAAC;AACtB,WAAO;AAAA,MACL,MAAM,KAAK,QAAQ;AAAA,MACnB,iBAAiB,KAAK,mBAAmB;AAAA,MACzC,OAAO,CAAC;AAAA,IACV;AAAA,EACF,CAAC;AACD,SAAO;AAAA,IACL,GAAG;AAAA,IACH,eAAe;AAAA,IACf,iBAAiB;AAAA,EACnB;AACF;AAEA,SAAS,WAAW,MAAc,QAAiB,MAA+B,QAA0B;AAC1G,QAAM,MAAM,SAAS,MAAM;AAC3B,MAAI,CAAC,IAAK,QAAO;AACjB,MAAI,MAAM,QAAQ,IAAI,IAAI,KAAK,IAAI,KAAK,OAAQ,QAAO;AACvD,QAAM,OAAO,YAAY,MAAM,QAAQ,MAAM,EAAE,OAAO,CAAC;AACvD,MAAI,CAAC,KAAK,OAAQ,QAAO;AACzB,SAAO,EAAE,GAAG,KAAK,KAAK;AACxB;AAGO,SAAS,kBACd,MACA,QACA,OAAgC,CAAC,GACjC,SAAS,OACA;AACT,MAAI,UAAU,KAAM,QAAO;AAC3B,QAAM,SAAS,YAAY,IAAI;AAC/B,QAAM,UAAU,QAAQ,IAAI;AAE5B,MAAI,aAAsB;AAC1B,MAAI,SAAS,cAAc,SAAS,kBAAkB;AACpD,iBAAa,UAAU,UAAU,SAAS,eAAe,MAAM;AAAA,EACjE,WAAW,SAAS,YAAY;AAC9B,QAAI,UAAU,SAAS;AACrB,mBAAa;AAAA,IACf,OAAO;AACL,YAAM,MAAM,SAAS,MAAM;AAC3B,mBAAa,MAAM,EAAE,GAAG,KAAK,MAAM,eAAe,IAAI,IAAI,EAAE,IAAI;AAAA,IAClE;AAAA,EACF,WAAW,SAAS,sBAAsB;AACxC,iBAAa,UAAU,UAAU,SAAS,oBAAoB,MAAM;AAAA,EACtE,WAAW,SAAS,qBAAqB;AACvC,QAAI,CAAC,QAAQ;AACX,YAAM,MAAM,SAAS,MAAM;AAC3B,YAAM,QAAQ,MAAM,QAAQ,KAAK,KAAK,IAAI,IAAI,QAAQ,CAAC;AACvD,mBAAa;AAAA,QACX,GAAG;AAAA,QACH,OAAO,MAAM,IAAI,CAAC,SAAS;AACzB,gBAAM,MAAM,SAAS,IAAI;AACzB,cAAI,CAAC,IAAK,QAAO;AACjB,gBAAM,EAAE,UAAU,OAAO,GAAG,KAAK,IAAI;AACrC,iBAAO;AAAA,QACT,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF,WAAW,SAAS,oBAAoB;AACtC,QAAI,CAAC,QAAQ;AACX,YAAM,MAAM,SAAS,MAAM;AAC3B,YAAM,UAAU,OAAO,KAAK,YAAY,WAAW,IAAI,UAAU;AACjE,YAAM,QAAQ,OAAO,WAAW,SAAS,MAAM;AAC/C,UAAI,QAAQ,oBAAoB;AAC9B,qBAAa;AAAA,UACX,MAAM,KAAK;AAAA,UACX,WAAW;AAAA,UACX;AAAA,UACA,iBAAiB;AAAA,QACnB;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO,WAAW,MAAM,YAAY,MAAM,MAAM;AAClD;AAGO,SAAS,mBAAmB,MAA+B;AAChE,MAAI,CAAC,KAAK,SAAS;AACjB,UAAM,SAAS,KAAK,OAAO,mBAAmB,6BAAS;AACvD,WAAO,GAAG,MAAM,SAAI,KAAK,OAAO,WAAW,0BAAM;AAAA,EACnD;AACA,QAAM,QAAkB,CAAC;AACzB,MAAI,KAAK,QAAQ;AACf,UAAM,KAAK,+EAAwB;AAAA,EACrC;AACA,MAAI,KAAK,eAAe;AACtB,UAAM;AAAA,MACJ,2CAAa,KAAK,cAAc,UAAU,sBAAO,GAAG,KAAK,cAAc,WAAW,eAAU,KAAK,cAAc,QAAQ,KAAK,EAAE;AAAA,IAChI;AAAA,EACF;AACA,QAAM,aAAa,kBAAkB,KAAK,MAAM,KAAK,QAAQ,KAAK,QAAQ,CAAC,GAAG,KAAK,MAAM;AACzF,QAAM,MAAM,SAAS,UAAU;AAC/B,QAAM,OAAO,MAAM,QAAQ,KAAK,IAAI,IAAI,IAAI,OAAO,CAAC;AACpD,MAAI,KAAK,QAAQ;AACf,UAAM,QAAQ,KACX,IAAI,CAAC,SAAS,SAAS,IAAI,GAAG,IAAI,EAClC,OAAO,CAAC,MAAmB,OAAO,MAAM,YAAY,EAAE,SAAS,CAAC;AACnE,QAAI,MAAM,OAAQ,OAAM,KAAK,SAAS,MAAM,KAAK,UAAK,CAAC,EAAE;AAAA,EAC3D;AACA,QAAM,UAAU,OAAO,eAAe,WAAW,aAAa,KAAK,UAAU,UAAU;AACvF,QAAM,KAAK,OAAO;AAClB,SAAO,MAAM,KAAK,MAAM;AAC1B;;;AC1IA,SAAS,yBAAyB;;;ACHlC,SAAS,yBAAyB;;;ACAlC,SAAS,qBAAwC;AAGjD,IAAM,cAAc;AAEb,SAAS,oBAAoB,MAAc,QAA+B,CAAC,GAAiB;AACjG,QAAM,OAAO,KAAK,QAAQ,WAAW,EAAE,EAAE,MAAM,OAAO,EAAE,IAAI,KAAK;AACjE,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,WAAW;AAAA,IACX,SAAS;AAAA,IACT,UAAU;AAAA,IACV,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,eAAe;AAAA,IACf,WAAW;AAAA,IACX,sBAAsB;AAAA,IACtB,GAAG,cAAc;AAAA,IACjB,GAAG;AAAA,EACL;AACF;AAEA,eAAe,QAAc,OAAY,GAAW,IAAwC;AAC1F,QAAM,MAAW,IAAI,MAAM,MAAM,MAAM;AACvC,MAAI,IAAI;AACR,iBAAe,SAAS;AACtB,WAAO,IAAI,MAAM,QAAQ;AACvB,YAAM,MAAM;AACZ,UAAI,GAAG,IAAI,MAAM,GAAG,MAAM,GAAG,CAAE;AAAA,IACjC;AAAA,EACF;AACA,QAAM,UAAU,KAAK,IAAI,GAAG,MAAM,MAAM;AACxC,QAAM,QAAQ,IAAI,MAAM,KAAK,EAAE,QAAQ,QAAQ,GAAG,MAAM,OAAO,CAAC,CAAC;AACjE,SAAO;AACT;AAEA,eAAsB,qBAAqB,SAA2C;AACpF,QAAM,QAAQ,QAAQ,YAAY,KAAK;AACvC,MAAI,CAAC,MAAM,OAAQ,QAAO,CAAC;AAC3B,SAAO,QAAQ,OAAO,aAAa,OAAO,MAAM;AAC9C,QAAI;AACF,YAAM,SAAS,MAAM,QAAQ,YAAY,QAAQ,EAAE,EAAE;AACrD,UAAI,CAAC,OAAQ,QAAO,oBAAoB,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,cAAc,EAAE,aAAa,CAAC;AAC1F,YAAM,IAAI,MAAM,OAAO,QAAQ,YAAY;AAC3C,aAAO,EAAE,GAAG,GAAG,IAAI,EAAE,IAAI,cAAc,EAAE,aAAa;AAAA,IACxD,QAAQ;AACN,aAAO,oBAAoB,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,cAAc,EAAE,aAAa,CAAC;AAAA,IAC/E;AAAA,EACF,CAAC;AACH;;;AD7CO,SAAS,gBAAgB,SAAkC;AAChE,SAAO;AAAA,IACL,QAAQ,QAAQ;AAAA,IAChB,aAAa,QAAQ;AAAA,IACrB,aAAa,QAAQ;AAAA,IACrB,UAAU,QAAQ;AAAA,IAClB,MAAM,QAAQ;AAAA,IACd,MAAM,YAAY,EAAE,QAAQ,UAAU,SAAS,GAAG;AAChD,UAAI,WAAW,QAAW;AACxB,cAAM,SAAS,MAAM,QAAQ,YAAY,QAAQ,MAAM;AACvD,YAAI,OAAQ,QAAO,EAAE,KAAK,OAAO,SAAS,UAAU,OAAO,QAAQ,SAAS;AAC5E,cAAM,IAAI,kBAAkB,sCAAa,MAAM,IAAI,gBAAgB;AAAA,MACrE;AACA,UAAI,UAAU;AACZ,cAAM,SAAS,QAAQ,YAAY,UAAU,QAAQ;AACrD,eAAO,EAAE,KAAK,OAAO,SAAS,UAAU,OAAO,QAAQ,SAAS;AAAA,MAClE;AACA,UAAI,UAAU;AACZ,cAAM,SAAS,MAAM,QAAQ,YAAY,KAAK,QAAQ;AACtD,eAAO,EAAE,KAAK,OAAO,SAAS,UAAU,OAAO,QAAQ,SAAS;AAAA,MAClE;AACA,YAAM,UAAU,MAAM,QAAQ,YAAY,WAAW;AACrD,UAAI,CAAC,SAAS;AACZ,cAAM,IAAI,kBAAkB,4IAAmC,gBAAgB;AAAA,MACjF;AACA,aAAO,EAAE,KAAK,QAAQ,SAAS,UAAU,QAAQ,QAAQ,SAAS;AAAA,IACpE;AAAA,IACA,eAAe,MAAM,qBAAqB,OAAO;AAAA,EACnD;AACF;;;ADbA,eAAsB,YACpB,KACA,SACA,KAC8B;AAC9B,SAAO,kBAAkB,KAAK,SAAS;AAAA,IACrC,QAAQ,IAAI;AAAA,IACZ,QAAQ,IAAI;AAAA,IACZ,UAAU,IAAI;AAAA,IACd,MAAM,gBAAgB,IAAI,OAAO;AAAA,EACnC,CAAC;AACH;;;AGvBA,IAAM,oBAAoB,oBAAI,IAAI,CAAC,qBAAqB,sBAAsB,qBAAqB,CAAC;AAEpG,SAAS,eAAe,KAA0B;AAChD,MAAI,CAAC,kBAAkB,IAAI,IAAI,IAAI,EAAG,QAAO,IAAI;AACjD,QAAM,SAAS,IAAI;AACnB,SAAO,OAAO,OAAO,SAAS,aAAa,OAAO,KAAK,EAAE,OAAO,KAAK,CAAC,IAAI,IAAI;AAChF;AAEA,SAAS,eAAe,KAItB;AACA,SAAO;AAAA,IACL,cAAc,IAAI,SAAS;AAAA,IAC3B,iBAAiB,IAAI,SAAS;AAAA,IAC9B,eAAe;AAAA,EACjB;AACF;AAEO,SAAS,aAAa,QAAmB,SAAkB,cAA2C;AAC3G,aAAW,OAAO,cAAc;AAC9B,UAAM,WAAW,OAAO,aAAa,KAAK,MAAM;AAMhD;AAAA,MACE,IAAI;AAAA,MACJ,EAAE,aAAa,IAAI,aAAa,aAAa,eAAe,GAAG,GAAG,aAAa,eAAe,GAAG,EAAE;AAAA,MACnG,OAAO,SAAkB;AACvB,cAAM,OAAO,MAAM,YAAY,KAAM,QAAQ,CAAC,GAA+B;AAAA,UAC3E;AAAA,UACA,QAAQ;AAAA,QACV,CAAC;AACD,eAAO;AAAA,UACL,SAAS,CAAC,EAAE,MAAM,QAAiB,MAAM,mBAAmB,IAAI,EAAE,CAAC;AAAA,UACnE,SAAS,CAAC,KAAK;AAAA,QACjB;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;;;ACjDA,SAAS,uBAAuB,WAAW,cAAc,qBAAqB;AAG9E,sBAAsB,EAAE,YAAY,SAAS;;;ACF7C,IAAM,WAAW;AAAA,EACf;AAAA,EACA;AACF,EAAE,KAAK,IAAI;AAEJ,IAAM,cAAc;AAAA,EACzB;AAAA,IACE,MAAM;AAAA,IACN,OAAO;AAAA,IACP,aAAa;AAAA,IACb,MAAM;AAAA,MACJ;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,EAAE,KAAK,IAAI;AAAA,EACb;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,OAAO;AAAA,IACP,aAAa;AAAA,IACb,MAAM;AAAA,MACJ;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,EAAE,KAAK,IAAI;AAAA,EACb;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,OAAO;AAAA,IACP,aAAa;AAAA,IACb,MAAM;AAAA,MACJ;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,EAAE,KAAK,IAAI;AAAA,EACb;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,OAAO;AAAA,IACP,aAAa;AAAA,IACb,MAAM;AAAA,MACJ;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,EAAE,KAAK,IAAI;AAAA,EACb;AACF;AAEO,SAAS,mBAAmB,QAAyB;AAC1D,QAAM,WAAW,OAAO,eAAe,KAAK,MAAM;AAClD,aAAW,KAAK,aAAa;AAC3B,aAAS,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,aAAa,EAAE,YAAY,GAAG,OAAO;AAAA,MACtE,aAAa,EAAE;AAAA,MACf,UAAU,CAAC,EAAE,MAAM,QAAiB,SAAS,EAAE,MAAM,QAAiB,MAAM,EAAE,KAAK,EAAE,CAAC;AAAA,IACxF,EAAE;AAAA,EACJ;AACF;;;AC1EA,SAAoB,wBAAwB;AAI5C,IAAM,OAAO;AAEb,SAAS,aAAa,KAAa,MAAe;AAChD,SAAO;AAAA,IACL,UAAU;AAAA,MACR;AAAA,QACE;AAAA,QACA,UAAU;AAAA,QACV,MAAM,KAAK,UAAU,IAAI;AAAA,MAC3B;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,oBAAoB,SAAkB;AAC7C,SAAO,qBAAqB,OAAO,EAAE;AAAA,IAAK,CAAC,UACzC,MAAM,IAAI,CAAC,QAAQ;AACjB,YAAM,EAAE,UAAU,OAAO,GAAG,KAAK,IAAI;AACrC,aAAO;AAAA,IACT,CAAC;AAAA,EACH;AACF;AAEO,SAAS,qBAAqB,QAAmB,SAAwB;AAC9E,QAAM,WAAW,OAAO,iBAAiB,KAAK,MAAM;AAEpD;AAAA,IACE;AAAA,IACA;AAAA,IACA,EAAE,OAAO,8CAAW,aAAa,yFAAkC,UAAU,KAAK;AAAA,IAClF,OAAO,QAAQ,aAAa,IAAI,MAAM,EAAE,OAAO,MAAM,oBAAoB,OAAO,EAAE,CAAC;AAAA,EACrF;AAEA;AAAA,IACE;AAAA,IACA;AAAA,IACA,EAAE,OAAO,kCAAS,aAAa,kIAAyB,UAAU,KAAK;AAAA,IACvE,OAAO,QAAQ;AACb,YAAM,SAAS,MAAM,QAAQ,YAAY,WAAW;AACpD,UAAI,CAAC,QAAQ;AACX,eAAO,aAAa,IAAI,MAAM,EAAE,WAAW,OAAO,MAAM,mDAAW,CAAC;AAAA,MACtE;AACA,YAAM,IAAI,MAAM,OAAO,QAAQ,UAAU;AACzC,aAAO,aAAa,IAAI,MAAM;AAAA,QAC5B,WAAW;AAAA,QACX,MAAM,OAAO,OAAO;AAAA,QACpB,SAAS,EAAE;AAAA,QACX,UAAU,EAAE;AAAA,QACZ,OAAO,EAAE;AAAA,QACT,QAAQ,EAAE;AAAA,QACV,WAAW,EAAE;AAAA,QACb,SAAS,EAAE;AAAA,QACX,aAAa,EAAE,OAAO;AAAA,QACtB,eAAe,EAAE,SAAS;AAAA,QAC1B,gBAAgB,EAAE,UAAU;AAAA,QAC5B,eAAe,EAAE,WAAW;AAAA,QAC5B,YAAY,EAAE,WAAW,MAAM,GAAG,EAAE;AAAA,MACtC,CAAC;AAAA,IACH;AAAA,EACF;AAEA;AAAA,IACE;AAAA,IACA;AAAA,IACA,EAAE,OAAO,wCAAU,aAAa,0CAAsB,UAAU,KAAK;AAAA,IACrE,OAAO,QACL,aAAa,IAAI,MAAM;AAAA,MACrB,MAAM,QAAQ,KAAK,KAAK,EAAE,IAAI,CAAC,MAAM,QAAQ,KAAK,QAAQ,CAAC,CAAC;AAAA,IAC9D,CAAC;AAAA,EACL;AAEA;AAAA,IACE;AAAA,IACA,IAAI,iBAAiB,2BAA2B;AAAA,MAC9C,MAAM,aAAa;AAAA,QACjB,WAAW,QAAQ,KAAK,KAAK,EAAE,IAAI,CAAC,OAAO;AAAA,UACzC,KAAK,sBAAsB,EAAE,EAAE;AAAA,UAC/B,MAAM,EAAE;AAAA,UACR,aAAa,GAAG,EAAE,IAAI,IAAI,EAAE,MAAM;AAAA,UAClC,UAAU;AAAA,QACZ,EAAE;AAAA,MACJ;AAAA,IACF,CAAC;AAAA,IACD,EAAE,OAAO,wCAAU,aAAa,2DAAwB,UAAU,KAAK;AAAA,IACvE,OAAO,KAAK,cAAc;AACxB,YAAM,KAAK,OAAO,UAAU,MAAM,EAAE;AACpC,YAAM,MAAM,QAAQ,KAAK,IAAI,EAAE;AAC/B,UAAI,CAAC,KAAK;AACR,eAAO,aAAa,IAAI,MAAM,EAAE,OAAO,kCAAS,GAAG,CAAC;AAAA,MACtD;AACA,YAAM,UAAU,QAAQ,KAAK,QAAQ,GAAG;AACxC,aAAO,aAAa,IAAI,MAAM;AAAA,QAC5B,GAAG;AAAA,QACH,MAAM,IAAI,KAAK,MAAM,GAAG;AAAA,MAC1B,CAAC;AAAA,IACH;AAAA,EACF;AACF;;;ATrFO,IAAM,kBAAkB,EAAE,MAAM,0BAA0B,QAAQ;AAGlE,SAAS,gBAAgB,SAA6B;AAC3D,QAAM,SAAS,IAAIC;AAAA,IACjB,EAAE,MAAM,gBAAgB,MAAM,SAAS,gBAAgB,QAAQ;AAAA,IAC/D;AAAA,MACE,cAAc,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC,GAAG,WAAW,CAAC,EAAE;AAAA,MACtD,cAAc;AAAA,QACZ;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,EAAE,KAAK,IAAI;AAAA,IACb;AAAA,EACF;AAEA,eAAa,QAAQ,SAAS,SAAS;AAEvC,qBAAmB,MAAM;AACzB,uBAAqB,QAAQ,OAAO;AACpC,SAAO;AACT;AAGA,eAAsB,cAAc,SAAiC;AACnE,QAAM,SAAS,gBAAgB,OAAO;AACtC,QAAM,YAAY,IAAI,qBAAqB;AAC3C,QAAM,OAAO,QAAQ,SAAS;AAChC;AAaO,IAAM,iBAAN,MAAqB;AAAA,EAE1B,YAA6B,SAAkB;AAAlB;AAAA,EAAmB;AAAA,EAAnB;AAAA,EADZ,WAAW,oBAAI,IAA4B;AAAA,EAG5D,MAAM,OAAO,KAAsB,KAAqB,YAAqC;AAC3F,UAAM,WAAW,IAAI,QAAQ,gBAAgB;AAC7C,QAAI,OAAO,aAAa,YAAY,UAAU;AAC5C,YAAMC,WAAU,KAAK,SAAS,IAAI,QAAQ;AAC1C,UAAI,CAACA,UAAS;AACZ,YAAI,aAAa;AACjB,YAAI,IAAI,uBAAuB;AAC/B;AAAA,MACF;AACA,YAAMA,SAAQ,UAAU,cAAc,KAAK,KAAK,UAAU;AAC1D;AAAA,IACF;AAGA,UAAM,YAAY,IAAI,8BAA8B;AAAA,MAClD,oBAAoB,MAAM,WAAW;AAAA,MACrC,8BAA8B;AAAA,MAC9B,cAAc,CAAC,aAAa,aAAa,OAAO;AAAA,IAClD,CAAC;AACD,UAAM,SAAS,gBAAgB,KAAK,OAAO;AAC3C,UAAM,OAAO,QAAQ,SAAS;AAC9B,UAAM,UAA0B,EAAE,IAAI,IAAI,QAAQ,UAAU;AAC5D,cAAU,UAAU,MAAM;AACxB,UAAI,QAAQ,GAAI,MAAK,SAAS,OAAO,QAAQ,EAAE;AAC/C,WAAK,OAAO,MAAM,EAAE,MAAM,MAAM,MAAS;AAAA,IAC3C;AACA,UAAM,UAAU,cAAc,KAAK,KAAK,UAAU;AAClD,UAAM,MAAM,UAAU;AACtB,QAAI,KAAK;AACP,cAAQ,KAAK;AACb,WAAK,SAAS,IAAI,KAAK,OAAO;AAAA,IAChC;AAAA,EACF;AAAA,EAEA,UAAgB;AACd,eAAW,WAAW,KAAK,SAAS,OAAO,GAAG;AAC5C,cAAQ,UAAU,MAAM,EAAE,MAAM,MAAM,MAAS;AAAA,IACjD;AACA,SAAK,SAAS,MAAM;AAAA,EACtB;AACF;","names":["McpServer","McpServer","session"]}