@shaohui_jin/git-cockpit-mcp-server 0.1.8 → 0.1.9

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.
@@ -4,10 +4,10 @@
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <title>Git Cockpit</title>
7
- <script type="module" crossorigin src="/assets/index-MPCZvzsu.js"></script>
7
+ <script type="module" crossorigin src="/assets/index-C5nhakYS.js"></script>
8
8
  <link rel="modulepreload" crossorigin href="/assets/vue-CYNDxJyv.js">
9
9
  <link rel="modulepreload" crossorigin href="/assets/element-plus-D8uC5V5h.js">
10
- <link rel="stylesheet" crossorigin href="/assets/index-DUymtENk.css">
10
+ <link rel="stylesheet" crossorigin href="/assets/index-CFqNjmhP.css">
11
11
  </head>
12
12
  <body>
13
13
  <div id="app"></div>
package/dist/webServer.js CHANGED
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  createWebServer
4
- } from "./chunk-Y2UNG7RZ.js";
5
- import "./chunk-HWDOOYER.js";
4
+ } from "./chunk-2U5EIJJV.js";
5
+ import "./chunk-OKXMVKBU.js";
6
6
  export {
7
7
  createWebServer
8
8
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shaohui_jin/git-cockpit-mcp-server",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "description": "Git Cockpit - 基于 MCP 的 Git 可视化操作工具(MCP Server + Web 服务 + CLI)",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -33,7 +33,7 @@
33
33
  "fastify": "^5.2.1",
34
34
  "zod": "^3.24.1",
35
35
  "zod-to-json-schema": "^3.25.2",
36
- "@shaohui_jin/git-cockpit-core": "^0.1.8"
36
+ "@shaohui_jin/git-cockpit-core": "^0.1.9"
37
37
  },
38
38
  "devDependencies": {
39
39
  "simple-git": "^3.27.0",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/mcpServer.ts","../src/tools/handlers.ts","../src/tools/schemas.ts","../src/tools/index.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 { executeTool, formatResultForMcp } from './tools/handlers.ts';\nimport { TOOL_DEFS } from './tools/index.ts';\n\nexport const MCP_SERVER_INFO = { name: 'git-cockpit-mcp-server', version: '0.1.0' } 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: {} },\n instructions: [\n 'Git Cockpit MCP Server:可视化的 Git 操作工具。',\n '使用规则:',\n '1. 先调用 git_status 查看工作区状态;',\n '2. 写操作(git_add/git_commit/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 '6. 落盘用 git_apply_resolve(独立 worktree,主区不切换);冲突时把选边后的 files 一并传入。'\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 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 * 工具执行层:所有工具(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}\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}\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 const handle = await resolveRepo(runtime, ctx, args.repoPath as string | undefined);\n const git = handle.service;\n const repoPath = git.repoPath;\n\n // 4. 高风险自动备份(非预览时)\n let backup: BackupResult | null = null;\n if (!dryRun && def.risk === 'dangerous' && runtime.config.git.backupOnDangerousOps) {\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, 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 };\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\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(`[自动备份] 分支 ${exec.backupCreated.branch ?? '(未创建)'}${exec.backupCreated.stashRef ? `,stash ${exec.backupCreated.stashRef}` : ''}`);\n }\n const payload =\n typeof exec.result === 'string'\n ? exec.result\n : JSON.stringify(exec.result, null, 2);\n parts.push(payload);\n return parts.join('\\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 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});\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});\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});\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\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});\nexport type GitMergeRehearseArgs = z.infer<typeof GitMergeRehearseSchema>;\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 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});\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\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 工具的静态定义(名称/描述/风险等级/schema/handler)。\n * handler 直接调用 core GitService 的方法;统一安全链路由 executeTool 承担。\n */\nimport type { GitService } from '@shaohui_jin/git-cockpit-core';\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: '获取分支拓扑图数据(全部分支提交、父提交、引用装饰、HEAD 位置),供可视化渲染。',\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_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(仍不改工作区)。选边后把 files[{path,resolvedContent}] 交给 git_apply_resolve。into/from 含义同 git_merge_preview。',\n risk: 'readonly',\n schema: S.GitMergeRehearseSchema,\n handler: async (args: Args, ctx) =>\n 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 // 写操作工具(默认开放,需预览/确认)\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_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_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 // ---------------------------------------------------------------------------\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\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 };"],"mappings":"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","names":["dryRun","repoPath","z","session"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/webServer.ts","../src/runtime.ts","../src/config.ts","../src/repoManager.ts","../src/openapi.ts","../package.json"],"sourcesContent":["/**\n * Fastify Web 服务:\n * - REST API 供 Web 前端调用(仓库管理、状态/历史/差异/branch 等只读查询、通用写操作入口);\n * - SSE(GET /api/events)推送仓库变化事件;\n * - 挂载 MCP Streamable HTTP 传输(/mcp),供 AI 客户端(Cursor/Claude Desktop)连接;\n * - 托管 Web 前端构建产物(packages/web/dist,若存在)。\n */\nimport * as path from 'node:path';\nimport * as fs from 'node:fs';\nimport { fileURLToPath } from 'node:url';\nimport Fastify from 'fastify';\nimport type { FastifyInstance, FastifyReply } from 'fastify';\nimport cors from '@fastify/cors';\nimport fastifyStatic from '@fastify/static';\nimport {\n GitOperationError,\n GitService,\n PermissionManager,\n RepoNotFoundError\n} from '@shaohui_jin/git-cockpit-core';\nimport type { OpenedRepo } from '@shaohui_jin/git-cockpit-core';\nimport { disposeRuntime } from './runtime.ts';\nimport type { Runtime } from './runtime.ts';\nimport { McpHttpHandler } from './mcpServer.ts';\nimport { executeTool } from './tools/handlers.ts';\nimport { TOOL_DEF_MAP, toolSummaries } from './tools/index.ts';\nimport { registerApiDocs } from './openapi.ts';\n\nexport interface WebServerHandle {\n app: FastifyInstance;\n /** 关闭 HTTP 服务与相关资源 */\n close: () => Promise<void>;\n}\n\n/** 静态资源目录:优先 Web 构建产物;不存在则仅提供 API。\n * 解析基于脚本自身位置(而非 process.cwd()),保证任意启动目录都能找到前端。 */\nfunction resolveWebDist(): string | null {\n // 源码布局下脚本位于 packages/mcp-server/dist,../.. 回到 packages,再进 web/dist\n const here = path.resolve(path.dirname(fileURLToPath(import.meta.url)));\n const candidates = [\n path.resolve(here, '..', '..', 'web', 'dist'), // 源码布局:packages/mcp-server/dist → packages/web/dist\n path.resolve(here, 'web'), // 发布布局:产物由 copy-web.mjs 打入 dist/web(含 index.html)\n path.resolve(here, 'web', 'dist'), // 兼容旧式 dist/web/dist 布局\n path.resolve(here, '..', 'web', 'dist'), // 兼容 npm 全局安装目录的旧式布局\n path.resolve(process.cwd(), 'dist', 'web'),\n path.resolve(process.cwd(), '..', 'web', 'dist'),\n path.resolve(process.cwd(), 'node_modules', '@shaohui_jin', 'git-cockpit-web', 'dist')\n ];\n for (const c of candidates) {\n if (fs.existsSync(path.join(c, 'index.html'))) return c;\n }\n return null;\n}\n\nexport async function createWebServer(\n runtime: Runtime,\n options: { host?: string; port?: number; staticDir?: string | null; noListen?: boolean } = {}\n): Promise<WebServerHandle> {\n const app = Fastify({ logger: false, bodyLimit: 2 * 1024 * 1024 });\n\n await app.register(cors, {\n origin: true,\n methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],\n allowedHeaders: ['Content-Type', 'Mcp-Session-Id', 'Authorization']\n });\n\n await registerApiDocs(app);\n\n const staticDir = options.staticDir !== undefined ? options.staticDir : resolveWebDist();\n if (staticDir && fs.existsSync(staticDir)) {\n await app.register(fastifyStatic, { root: staticDir, prefix: '/' });\n }\n\n const mcpHttp = new McpHttpHandler(runtime);\n\n // Health\n app.get('/api/health', async () => ({\n ok: true,\n service: 'git-cockpit',\n version: '0.1.6',\n uptimeMs: process.uptime() * 1000\n }));\n\n // ---------------------------------------------------------------------------\n // 仓库管理\n // ---------------------------------------------------------------------------\n app.get('/api/repos', async () => ({\n repos: runtime.repoManager.list()\n }));\n\n app.post<{ Body: { path?: string } }>('/api/repos/open', async (req, reply) => {\n const target = req.body?.path?.trim();\n if (!target) {\n return reply.code(400).send({ error: '缺少 path 参数' } as never);\n }\n try {\n const handle = await runtime.repoManager.open(target);\n return { repo: handle.record };\n } catch (err) {\n return reply.code(400).send({ error: toError(err) } as never);\n }\n });\n\n app.delete<{ Params: { id: string } }>('/api/repos/:id', async (req, reply) => {\n const id = Number(req.params.id);\n if (!Number.isInteger(id)) {\n return reply.code(400).send({ error: '非法仓库 id' } as never);\n }\n runtime.repoManager.remove(id);\n return { ok: true };\n });\n\n /** 激活/进入仓库:刷新最近打开排序,并记录一条操作日志(source=web) */\n app.post<{ Params: { id: string } }>('/api/repos/:id/activate', async (req, reply) => {\n const id = Number(req.params.id);\n if (!Number.isInteger(id)) {\n return reply.code(400).send({ error: '非法仓库 id' } as never);\n }\n const t0 = Date.now();\n const repo = runtime.repoManager.activate(id);\n if (!repo) {\n return reply.code(404).send({ error: '仓库不存在或已失效' } as never);\n }\n runtime.auditLogger.log({\n timestamp: new Date().toISOString(),\n source: 'web',\n tool: 'repo_activate',\n repoPath: repo.path,\n params: { id: repo.id, path: repo.path },\n result: 'success',\n error: null,\n durationMs: Date.now() - t0,\n dryRun: false\n });\n runtime.eventBus.emit('log', { tool: 'repo_activate', result: 'success', at: new Date().toISOString() });\n return { repo };\n });\n\n // ---------------------------------------------------------------------------\n // 只读查询(按仓库 id)\n // ---------------------------------------------------------------------------\n async function withRepo<T>(\n req: { params: { id: string } },\n reply: FastifyReply,\n fn: (handle: { service: GitService; record: OpenedRepo }) => Promise<T>\n ): Promise<T | void> {\n const id = Number(req.params.id);\n const handle = await runtime.repoManager.getById(id);\n if (!handle) {\n await reply.code(404).send({ error: '仓库不存在或已失效' });\n return undefined;\n }\n try {\n return await fn(handle);\n } catch (err) {\n await reply.code(400).send({ error: toError(err) });\n return undefined;\n }\n }\n\n app.get<{ Params: { id: string } }>('/api/repos/:id/status', async (req, reply) =>\n withRepo(req, reply, async ({ service }) => service.getStatus())\n );\n\n app.get<{ Params: { id: string }; Querystring: Record<string, string | undefined> }>('/api/repos/:id/log', async (req, reply) =>\n withRepo(req, reply, async ({ service }) => {\n const q = req.query;\n return service.getLog({\n maxCount: q.maxCount ? Math.min(Number(q.maxCount) || 100, 10000) : undefined,\n from: q.from,\n to: q.to,\n author: q.author,\n path: q.path,\n all: q.all === 'true'\n });\n })\n );\n\n app.get<{ Params: { id: string }; Querystring: Record<string, string | undefined> }>('/api/repos/:id/diff', async (req, reply) =>\n withRepo(req, reply, async ({ service }) => {\n const q = req.query;\n return service.getDiff({\n from: q.from,\n to: q.to,\n path: q.path,\n staged: q.staged === 'true',\n maxPatchBytes: q.maxPatchBytes ? Number(q.maxPatchBytes) : undefined\n });\n })\n );\n\n app.get<{ Params: { id: string; commit: string }; Querystring: Record<string, string | undefined> }>(\n '/api/repos/:id/show/:commit',\n async (req, reply) =>\n withRepo(req, reply, async ({ service }) =>\n service.getShow(req.params.commit, {\n path: req.query.path,\n maxPatchBytes: req.query.maxPatchBytes ? Number(req.query.maxPatchBytes) : undefined\n })\n )\n );\n\n app.get<{ Params: { id: string } }>('/api/repos/:id/branches', async (req, reply) =>\n withRepo(req, reply, async ({ service }) => service.listBranches())\n );\n\n app.get<{ Params: { id: string } }>('/api/repos/:id/tags', async (req, reply) =>\n withRepo(req, reply, async ({ service }) => service.listTags())\n );\n\n app.get<{ Params: { id: string } }>('/api/repos/:id/remotes', async (req, reply) =>\n withRepo(req, reply, async ({ service }) => service.listRemotes())\n );\n\n app.get<{ Params: { id: string }; Querystring: Record<string, string | undefined> }>('/api/repos/:id/graph', async (req, reply) =>\n withRepo(req, reply, async ({ service }) => service.getGraph(req.query.maxCount ? Number(req.query.maxCount) : 500))\n );\n\n app.get<{ Params: { id: string }; Querystring: { commit?: string; path?: string } }>('/api/repos/:id/file', async (req, reply) =>\n withRepo(req, reply, async ({ service }) => {\n if (!req.query.commit || !req.query.path) {\n return { error: '需要 commit 与 path 参数' };\n }\n return service.getFileContent(req.query.commit, req.query.path);\n })\n );\n\n app.get<{ Params: { id: string } }>('/api/repos/:id/stashes', async (req, reply) =>\n withRepo(req, reply, async ({ service }) => service.listStashes())\n );\n\n // ---------------------------------------------------------------------------\n // 通用写操作入口(复用 MCP 同款安全链路)\n // ---------------------------------------------------------------------------\n app.post<{ Params: { id: string; tool: string }; Body: { params?: Record<string, unknown> } }>(\n '/api/repos/:id/tools/:tool',\n { schema: { hide: true } },\n async (req, reply) => {\n const def = TOOL_DEF_MAP.get(req.params.tool);\n if (!def) return reply.code(404).send({ error: `未知工具: ${req.params.tool}` });\n const params = req.body?.params ?? {};\n const exec = await executeTool(def, params, {\n runtime,\n source: 'web',\n repoId: Number(req.params.id)\n });\n if (!exec.success) {\n const status = exec.error?.requiredApproval ? 403 : 400;\n return reply\n .code(status)\n .send({ error: exec.error?.message, requiredApproval: exec.error?.requiredApproval, code: exec.error?.code });\n }\n return { ...exec };\n }\n );\n\n // ---------------------------------------------------------------------------\n // 工具注册表信息(供前端渲染可操作按钮)\n // ---------------------------------------------------------------------------\n app.get('/api/tools', async () => ({\n tools: toolSummaries().map((t) => ({\n ...t,\n riskLevel: runtime.permissions.getRiskLevel(t.name),\n enabled: runtime.permissions.isEnabled(t.name)\n }))\n }));\n\n // ---------------------------------------------------------------------------\n // 操作日志\n // ---------------------------------------------------------------------------\n app.get<{ Querystring: Record<string, string | undefined> }>('/api/logs', async (req) => {\n const q = req.query;\n return {\n logs: runtime.auditLogger.list({\n limit: q.limit ? Number(q.limit) : undefined,\n offset: q.offset ? Number(q.offset) : undefined,\n tool: q.tool,\n source: (q.source as 'mcp' | 'web' | 'cli' | undefined) ?? undefined\n })\n };\n });\n\n // ---------------------------------------------------------------------------\n // 配置 / 权限\n // ---------------------------------------------------------------------------\n app.get('/api/settings', async () => ({\n config: runtime.configStore.snapshot(),\n permissions: {\n disabledTools: runtime.config.permissions.disabledTools,\n requireApprovalFor: runtime.config.permissions.requireApprovalFor,\n dryRunDefault: runtime.config.permissions.dryRunDefault\n },\n tools: toolSummaries().map((t) => ({\n name: t.name,\n description: t.description,\n riskLevel: runtime.permissions.getRiskLevel(t.name),\n enabled: runtime.permissions.isEnabled(t.name)\n }))\n }));\n\n app.put<{\n Body: { permissions?: { disabledTools?: string[]; requireApprovalFor?: string[]; dryRunDefault?: boolean } };\n }>('/api/settings', async (req, reply) => {\n const patch = req.body ?? {};\n if (patch.permissions === undefined) {\n return reply.code(400).send({ error: '仅支持更新 permissions 段' });\n }\n runtime.configStore.update({ permissions: patch.permissions });\n runtime.config = runtime.configStore.get();\n runtime.permissions = new PermissionManager(runtime.config);\n return { ok: true, config: runtime.configStore.snapshot() };\n });\n\n // ---------------------------------------------------------------------------\n // SSE:仓库变化推送\n // ---------------------------------------------------------------------------\n app.get('/api/events', async (req, reply) => {\n reply.hijack();\n const raw = reply.raw;\n raw.writeHead(200, {\n 'Content-Type': 'text/event-stream; charset=utf-8',\n 'Cache-Control': 'no-cache, no-transform',\n Connection: 'keep-alive',\n 'X-Accel-Buffering': 'no'\n });\n raw.write(': connected\\n\\n');\n\n const listener = (payload: unknown) => {\n raw.write(`event: repo-changed\\ndata: ${JSON.stringify(payload)}\\n\\n`);\n };\n const logListener = () => {\n raw.write('event: log\\ndata: {}\\n\\n');\n };\n runtime.eventBus.on('repo-changed', listener);\n runtime.eventBus.on('log', logListener);\n\n const keepAlive = setInterval(() => raw.write(': ping\\n\\n'), 15_000);\n\n req.raw.on('close', () => {\n clearInterval(keepAlive);\n runtime.eventBus.off('repo-changed', listener);\n runtime.eventBus.off('log', logListener);\n });\n });\n\n // ---------------------------------------------------------------------------\n // MCP Streamable HTTP\n // ---------------------------------------------------------------------------\n app.get('/mcp', { schema: { hide: true } }, async (req, reply) => {\n reply.hijack();\n await mcpHttp.handle(req.raw, reply.raw, undefined);\n });\n app.post('/mcp', { schema: { hide: true } }, async (req, reply) => {\n // fastify 预读并解析了请求体(req.body);SDK transport 需要 parsedBody 透传\n // (handleRequest(req, res, parsedBody)),否则它再读 req.raw 时流已空,initialize 无响应。\n reply.hijack();\n await mcpHttp.handle(req.raw, reply.raw, req.body);\n });\n\n // SPA fallback(静态托管存在时)\n if (staticDir) {\n app.setNotFoundHandler(async (req, reply) => {\n if (req.url.startsWith('/api') || req.url.startsWith('/mcp') || req.url.startsWith('/docs')) {\n return reply.code(404).send({ error: 'Not Found' });\n }\n const index = path.join(staticDir, 'index.html');\n if (fs.existsSync(index)) {\n reply.type('text/html').send(fs.readFileSync(index, 'utf8'));\n return;\n }\n return reply.code(404).send({ error: 'Not Found' });\n });\n }\n\n const port = options.port ?? runtime.config.server.port;\n const host = options.host ?? runtime.config.server.host;\n if (!options.noListen) {\n await app.listen({ port, host });\n }\n\n return {\n app,\n close: async () => {\n mcpHttp.dispose();\n await app.close();\n disposeRuntime(runtime);\n }\n };\n}\n\nfunction toError(err: unknown): { code: string; message: string; requiredApproval?: boolean } {\n if (err instanceof GitOperationError) return { code: err.code, message: err.message };\n if (err instanceof RepoNotFoundError) return { code: 'REPO_NOT_FOUND', message: err.message };\n if (err instanceof Error) return { code: 'INTERNAL_ERROR', message: err.message.slice(0, 500) };\n return { code: 'INTERNAL_ERROR', message: String(err) };\n}","/**\n * Runtime:mcp-server 共享运行时上下文。\n * - 唯一数据库实例、审计日志、权限管理器、仓库存储与其管理模式;\n * - eventBus 承载 Git 变更事件(changed / log),被 Web SSE 与订阅者消费。\n */\nimport { EventEmitter } from 'node:events';\nimport type { DatabaseSync } from 'node:sqlite';\nimport {\n AuditLogger,\n PermissionManager,\n RepoStore,\n openDatabase\n} from '@shaohui_jin/git-cockpit-core';\nimport type { GitCockpitConfig } from '@shaohui_jin/git-cockpit-core';\nimport { ConfigStore } from './config.ts';\nimport { RepoManager } from './repoManager.ts';\n\nexport interface RuntimeOptions {\n dataDir?: string;\n configOverrides?: ConstructorParameters<typeof ConfigStore>[1];\n db?: DatabaseSync;\n}\n\nexport interface Runtime {\n configStore: ConfigStore;\n config: GitCockpitConfig;\n db: DatabaseSync;\n auditLogger: AuditLogger;\n permissions: PermissionManager;\n repoStore: RepoStore;\n repoManager: RepoManager;\n /** 全局事件总线:'repo-changed' | 'log' */\n eventBus: EventEmitter;\n}\n\n/** 创建运行时(唯一后端共享);须在进程生命周期内调用一次 */\nexport function createRuntime(options: RuntimeOptions = {}): Runtime {\n const configStore = new ConfigStore(options.dataDir ?? '~/.git-cockpit', options.configOverrides);\n const config = configStore.get();\n const db = options.db ?? openDatabase(config.storage.dataDir);\n const eventBus = new EventEmitter();\n eventBus.setMaxListeners(200);\n\n const auditLogger = new AuditLogger(db, config.logging);\n const permissions = new PermissionManager(config);\n const repoStore = new RepoStore(db);\n const repoManager = new RepoManager({ repoStore, eventBus, config });\n\n return {\n configStore,\n config,\n db,\n auditLogger,\n permissions,\n repoStore,\n repoManager,\n eventBus\n };\n}\n\n/** 关闭运行时占用的资源(数据库等) */\nexport function disposeRuntime(runtime: Runtime): void {\n try {\n runtime.eventBus.removeAllListeners();\n runtime.repoManager.dispose();\n } catch {\n /* ignore */\n }\n try {\n runtime.db.close();\n } catch {\n /* ignore */\n }\n}","/**\n * 配置管理:默认值 <- 配置文件(config.json)合并(浅/深合并)。\n * 运行时通过 ConfigStore 读写,权限配置界面直接修改其内部状态并持久化。\n */\nimport * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { DEFAULT_CONFIG, expandHome } from '@shaohui_jin/git-cockpit-core';\nimport type { GitCockpitConfig } from '@shaohui_jin/git-cockpit-core';\n\nexport type DeepPartial<T> = {\n [P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];\n};\n\n/** 递归合并:target 上已存在的值优先保留,仅用 source 填充缺失字段与新增对象 */\nfunction deepMerge<T>(target: T, source: unknown): T {\n if (source === null || source === undefined) return target;\n if (Array.isArray(source)) {\n return (source as unknown[]) as T;\n }\n if (typeof source === 'object' && typeof target === 'object' && target !== null) {\n const out = { ...(target as Record<string, unknown>) } as Record<string, unknown>;\n for (const [k, v] of Object.entries(source as Record<string, unknown>)) {\n if (v !== undefined) out[k] = deepMerge(out[k], v);\n }\n return out as T;\n }\n return source as T;\n}\n\nfunction isPlainObject(v: unknown): v is Record<string, unknown> {\n return typeof v === 'object' && v !== null && !Array.isArray(v);\n}\n\n/**\n * ConfigStore:\n * - 配置存储在 <dataDir>/config.json;\n * - 数据目录默认 ~/.git-cockpit(支持 ~ 展开)。\n */\nexport class ConfigStore {\n private config: GitCockpitConfig;\n\n constructor(\n private readonly dataDir: string,\n overrides?: DeepPartial<GitCockpitConfig>\n ) {\n const dir = expandHome(dataDir);\n const file = path.join(dir, 'config.json');\n // 数据目录同时写入 storage.dataDir,保证数据库与配置存放在同一目录\n this.config = {\n ...this.load(file, overrides),\n storage: { dataDir: dir }\n };\n }\n\n private load(file: string, overrides?: DeepPartial<GitCockpitConfig>): GitCockpitConfig {\n let fileConfig: unknown = {};\n try {\n if (fs.existsSync(file)) {\n fileConfig = JSON.parse(fs.readFileSync(file, 'utf8'));\n }\n } catch (err) {\n // 配置文件损坏时回退默认(不阻断启动)\n console.warn(`[git-cockpit] 配置文件 ${file} 无法解析,已使用默认配置:`, (err as Error).message);\n }\n let merged = deepMerge(structuredClone(DEFAULT_CONFIG), fileConfig);\n if (overrides) merged = deepMerge(merged, overrides);\n return merged;\n }\n\n get(): GitCockpitConfig {\n return this.config;\n }\n\n /** 合并并持久化;返回新配置 */\n update(patch: DeepPartial<GitCockpitConfig>): GitCockpitConfig {\n this.config = deepMerge(this.config, patch);\n this.save();\n return this.config;\n }\n\n save(): void {\n const dir = expandHome(this.config.storage.dataDir);\n fs.mkdirSync(dir, { recursive: true });\n const file = path.join(dir, 'config.json');\n fs.writeFileSync(file, JSON.stringify(this.config, null, 2), 'utf8');\n }\n\n /** 供日志/调试:仅返回脱敏后的配置快照(隐藏敏感键名) */\n snapshot(): Record<string, unknown> {\n const copy = structuredClone(this.config);\n const redact = (v: unknown): unknown => {\n if (isPlainObject(v)) {\n const out: Record<string, unknown> = {};\n for (const [k, val] of Object.entries(v)) {\n const lower = k.toLowerCase();\n if (/password|token|secret|authorization|url/i.test(lower)) out[k] = '[REDACTED]';\n else out[k] = redact(val);\n }\n return out;\n }\n if (Array.isArray(v)) return v.map(redact);\n return v;\n };\n return redact(copy) as Record<string, unknown>;\n }\n}","/**\n * RepoManager:GitService 实例池 + 已打开仓库存储。\n * - 每个仓库根路径对应一个 GitService 实例(内含串行队列),Web 与 MCP 共用,\n * 保证\"唯一后端\"与锁全局有效;\n * - 打开仓库时校验合法性(GitService.open),并在 SQLite 中记录最近列表;\n * - 监听 Git 变更事件并转发到全局 eventBus,驱动前端实时刷新。\n */\nimport { EventEmitter } from 'node:events';\nimport * as path from 'node:path';\nimport {\n GitService,\n RepoNotFoundError,\n RepoStore\n} from '@shaohui_jin/git-cockpit-core';\nimport type { GitCockpitConfig, OpenedRepo } from '@shaohui_jin/git-cockpit-core';\n\nexport interface RepoHandle {\n service: GitService;\n record: OpenedRepo;\n}\n\nexport interface RepoManagerOptions {\n repoStore: RepoStore;\n eventBus: EventEmitter;\n config: GitCockpitConfig;\n}\n\nexport class RepoManager {\n /** repo 根路径(规范化绝对路径) -> repoId */\n private readonly pathToId = new Map<string, number>();\n private readonly idToService = new Map<number, GitService>();\n private readonly eventBus: EventEmitter;\n\n constructor(private readonly options: RepoManagerOptions) {\n this.eventBus = options.eventBus;\n // 为历史记录建立 路径->id 索引(服务实例懒创建)\n for (const repo of options.repoStore.list()) {\n this.pathToId.set(normalizePath(repo.path), repo.id);\n }\n }\n\n list(): (OpenedRepo & { available: boolean })[] {\n return this.options.repoStore.list().map((r) => ({\n ...r,\n available: r.path === '' || true\n }));\n }\n\n /** 取最近打开的仓库(懒创建服务) */\n async getCurrent(): Promise<RepoHandle | null> {\n const record = this.options.repoStore.list()[0];\n return record ? this.getByRecord(record) : null;\n }\n\n /** 按 id 取仓库(懒创建服务) */\n async getById(id: number): Promise<RepoHandle | null> {\n const record = this.options.repoStore.getById(id);\n if (!record) return null;\n try {\n return await this.getByRecord(record);\n } catch (err) {\n if (err instanceof Error && /NOT_A_GIT_REPO|REPO_NOT_FOUND/.test(err.message)) {\n return null;\n }\n throw err;\n }\n }\n\n /** 打开仓库:校验并记录;重复打开返回既有实例 */\n async open(repoPath: string): Promise<RepoHandle> {\n const service = await GitService.open(repoPath);\n const root = service.repoPath;\n const key = normalizePath(root);\n const existingId = this.pathToId.get(key);\n if (existingId !== undefined && existingId !== 0) {\n const record = this.options.repoStore.getById(existingId);\n if (record) {\n this.options.repoStore.open(root); // 刷新最近打开时间\n this.idToService.set(record.id, service);\n this.attach(service);\n return { service, record: this.options.repoStore.getById(record.id) ?? record };\n }\n }\n const record = this.options.repoStore.open(root);\n this.pathToId.set(key, record.id);\n this.idToService.set(record.id, service);\n this.attach(service);\n return { service, record };\n }\n\n /** 激活仓库:刷新最近打开时间,驱动「最近打开」列表重排到首位;仓库不存在返回 null */\n activate(id: number): OpenedRepo | null {\n const record = this.options.repoStore.getById(id);\n if (!record) return null;\n this.options.repoStore.open(record.path); // 同路径 open 仅更新 last_opened_at\n return this.options.repoStore.getById(id) ?? record;\n }\n\n /** 按路径取服务,未打开则报错(避免隐式副作用) */\n getByPath(repoPath: string): RepoHandle {\n const key = normalizePath(repoPath);\n const id = this.pathToId.get(key);\n if (id !== undefined && id !== 0) {\n const record = this.options.repoStore.getById(id);\n if (record) {\n const service = this.idToService.get(id);\n if (service) return { service, record };\n }\n }\n throw new RepoNotFoundError(`仓库未打开: ${repoPath}。请先打开仓库(POST /api/repos/open)。`);\n }\n\n /** 关闭:仅从内存服务池移除;保留历史记录 */\n close(id: number): void {\n const record = this.options.repoStore.getById(id);\n if (record) this.pathToId.delete(normalizePath(record.path));\n const svc = this.idToService.get(id);\n if (svc) svc.removeAllListeners('changed');\n this.idToService.delete(id);\n }\n\n /** 从历史记录中删除并关闭 */\n remove(id: number): void {\n this.close(id);\n this.options.repoStore.remove(id);\n }\n\n dispose(): void {\n for (const id of [...this.idToService.keys()]) this.close(id);\n }\n\n /** 按记录取句柄;服务缺失时(合法)创建并缓存 */\n private async getByRecord(record: OpenedRepo): Promise<RepoHandle> {\n let service = this.idToService.get(record.id);\n if (!service) {\n service = await GitService.open(record.path);\n this.pathToId.set(normalizePath(service.repoPath), record.id);\n this.idToService.set(record.id, service);\n this.attach(service);\n }\n return { service, record };\n }\n\n private attach(service: GitService): void {\n service.on('changed', (payload: { repoPath: string; command: string[] }) => {\n this.eventBus.emit('repo-changed', {\n repoPath: payload.repoPath,\n command: payload.command,\n at: new Date().toISOString()\n });\n });\n }\n}\n\nfunction normalizePath(p: string): string {\n let normalized = path.resolve(p);\n if (process.platform === 'win32') normalized = normalized.toLowerCase();\n return normalized;\n}","/**\n * OpenAPI / Swagger UI:挂在同一 Fastify 进程的 /docs。\n * REST 摘要集中在此;MCP 工具从 TOOL_DEFS + zod 生成,避免手写 32 份。\n */\nimport type { FastifyInstance } from 'fastify';\nimport swagger from '@fastify/swagger';\nimport swaggerUi from '@fastify/swagger-ui';\nimport { zodToJsonSchema } from 'zod-to-json-schema';\nimport { version } from '../package.json';\nimport { TOOL_DEFS } from './tools/index.ts';\n\nconst REST_META: Record<string, { summary: string; tags: string[] }> = {\n 'get /api/health': { summary: '探活', tags: ['系统'] },\n 'get /api/repos': { summary: '已打开仓库列表', tags: ['仓库'] },\n 'post /api/repos/open': { summary: '打开本地仓库', tags: ['仓库'] },\n 'delete /api/repos/{id}': { summary: '关闭并移除仓库', tags: ['仓库'] },\n 'post /api/repos/{id}/activate': { summary: '激活仓库(置顶)', tags: ['仓库'] },\n 'get /api/repos/{id}/status': { summary: '工作区状态', tags: ['只读'] },\n 'get /api/repos/{id}/log': { summary: '提交历史', tags: ['只读'] },\n 'get /api/repos/{id}/diff': { summary: '差异', tags: ['只读'] },\n 'get /api/repos/{id}/show/{commit}': { summary: '提交详情', tags: ['只读'] },\n 'get /api/repos/{id}/branches': { summary: '分支列表', tags: ['只读'] },\n 'get /api/repos/{id}/tags': { summary: '标签列表', tags: ['只读'] },\n 'get /api/repos/{id}/remotes': { summary: '远程列表', tags: ['只读'] },\n 'get /api/repos/{id}/graph': { summary: '提交图数据', tags: ['只读'] },\n 'get /api/repos/{id}/file': { summary: '读取某提交中的文件', tags: ['只读'] },\n 'get /api/repos/{id}/stashes': { summary: 'stash 列表', tags: ['只读'] },\n 'get /api/tools': { summary: '工具注册表(含风险与是否启用)', tags: ['系统'] },\n 'get /api/logs': { summary: '操作审计日志', tags: ['系统'] },\n 'get /api/settings': { summary: '配置与权限', tags: ['设置'] },\n 'put /api/settings': { summary: '更新权限配置', tags: ['设置'] },\n 'get /api/events': { summary: 'SSE:仓库变化与日志', tags: ['系统'] }\n};\n\ntype OpenApiDoc = {\n paths?: Record<string, Record<string, Record<string, unknown> | undefined> | undefined>;\n};\n\nfunction applyRestMeta(spec: OpenApiDoc): void {\n for (const [path, item] of Object.entries(spec.paths ?? {})) {\n if (!item) continue;\n for (const method of Object.keys(item)) {\n const op = item[method];\n if (!op || typeof op !== 'object') continue;\n const meta = REST_META[`${method} ${path}`];\n if (meta) {\n if (!op.summary) op.summary = meta.summary;\n if (!op.tags) op.tags = meta.tags;\n }\n }\n }\n}\n\nfunction injectToolPaths(spec: OpenApiDoc): void {\n if (!spec.paths) spec.paths = {};\n delete spec.paths['/api/repos/{id}/tools/{tool}'];\n\n const riskTag = (risk: string): string =>\n risk === 'dangerous' ? '高风险工具' : risk === 'write' ? '写操作工具' : '只读工具';\n\n for (const def of TOOL_DEFS) {\n const jsonSchema = zodToJsonSchema(def.schema, {\n target: 'openApi3',\n $refStrategy: 'none'\n }) as Record<string, unknown>;\n delete jsonSchema.$schema;\n\n spec.paths[`/api/repos/{id}/tools/${def.name}`] = {\n post: {\n tags: [riskTag(def.risk)],\n summary: def.name,\n description: def.description,\n operationId: def.name,\n parameters: [\n {\n name: 'id',\n in: 'path',\n required: true,\n schema: { type: 'integer' },\n description: '仓库 id(GET /api/repos)'\n }\n ],\n requestBody: {\n required: false,\n content: {\n 'application/json': {\n schema: {\n type: 'object',\n properties: { params: jsonSchema }\n }\n }\n }\n },\n responses: {\n '200': { description: '成功(result 或 dry-run preview)' },\n '400': { description: '失败或参数错误' },\n '403': { description: '工具禁用或需要审批' },\n '404': { description: '未知工具或仓库不存在' }\n }\n }\n };\n }\n}\n\nexport async function registerApiDocs(app: FastifyInstance): Promise<void> {\n await app.register(swagger, {\n openapi: {\n info: {\n title: 'Git Cockpit API',\n description:\n 'Web REST。写操作与 MCP 工具均为 POST /api/repos/{id}/tools/{name},请求体 { params }。MCP 传输 /mcp 不在本文档。',\n version\n }\n },\n exposeHeadRoutes: false,\n transformObject: (doc) => {\n if (!('openapiObject' in doc)) return 'swaggerObject' in doc ? doc.swaggerObject : doc;\n const spec = doc.openapiObject as OpenApiDoc;\n applyRestMeta(spec);\n injectToolPaths(spec);\n return spec;\n }\n });\n\n await app.register(swaggerUi, {\n routePrefix: '/docs',\n uiConfig: { docExpansion: 'list', deepLinking: true }\n });\n}\n","{\n \"name\": \"@shaohui_jin/git-cockpit-mcp-server\",\n \"version\": \"0.1.8\",\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}"],"mappings":"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","names":["path","fs","PermissionManager","RepoNotFoundError","EventEmitter","RepoStore","path","record","EventEmitter","RepoStore","path","PermissionManager","RepoNotFoundError"]}