🔀 repo-mcp-server: 默认分支改为 notion/shuangyan(Notion人格体专属分支)
This commit is contained in:
parent
b6d94445ec
commit
953b79173b
@ -29,6 +29,7 @@ const GITEA_TOKEN = process.env.GITEA_TOKEN;
|
|||||||
const GITEA_URL = process.env.GITEA_URL || 'https://guanghulab.com';
|
const GITEA_URL = process.env.GITEA_URL || 'https://guanghulab.com';
|
||||||
const REPO_OWNER = process.env.REPO_OWNER || 'bingshuo';
|
const REPO_OWNER = process.env.REPO_OWNER || 'bingshuo';
|
||||||
const REPO_NAME = process.env.REPO_NAME || 'guanghulab';
|
const REPO_NAME = process.env.REPO_NAME || 'guanghulab';
|
||||||
|
const DEFAULT_BRANCH = process.env.REPO_DEFAULT_BRANCH || 'notion/shuangyan'; // Notion 人格体专属分支
|
||||||
|
|
||||||
// ─── 常量时间比较(防时序攻击) ───
|
// ─── 常量时间比较(防时序攻击) ───
|
||||||
function safeCompare(a, b) {
|
function safeCompare(a, b) {
|
||||||
@ -92,9 +93,9 @@ function registerTools(server) {
|
|||||||
server.tool(
|
server.tool(
|
||||||
'repo_read',
|
'repo_read',
|
||||||
'读取仓库文件内容',
|
'读取仓库文件内容',
|
||||||
{ path: z.string().describe('文件路径,如 brain/progress.json'), branch: z.string().optional().describe('分支,默认 main') },
|
{ path: z.string().describe('文件路径,如 brain/progress.json'), branch: z.string().optional().describe('分支,默认 notion/shuangyan') },
|
||||||
async ({ path, branch }) => {
|
async ({ path, branch }) => {
|
||||||
const data = await repoFetch(`/contents/${encodeURIComponent(path)}?ref=${branch || 'main'}`);
|
const data = await repoFetch(`/contents/${encodeURIComponent(path)}?ref=${branch || DEFAULT_BRANCH}`);
|
||||||
if (data.error) return { content: [{ type: 'text', text: `❌ 读取失败: ${data.message}` }] };
|
if (data.error) return { content: [{ type: 'text', text: `❌ 读取失败: ${data.message}` }] };
|
||||||
const content = Buffer.from(data.content, 'base64').toString('utf-8');
|
const content = Buffer.from(data.content, 'base64').toString('utf-8');
|
||||||
return { content: [{ type: 'text', text: content }] };
|
return { content: [{ type: 'text', text: content }] };
|
||||||
@ -109,10 +110,10 @@ function registerTools(server) {
|
|||||||
path: z.string().describe('文件路径'),
|
path: z.string().describe('文件路径'),
|
||||||
content: z.string().describe('文件内容'),
|
content: z.string().describe('文件内容'),
|
||||||
message: z.string().describe('提交信息'),
|
message: z.string().describe('提交信息'),
|
||||||
branch: z.string().optional().describe('目标分支,默认 main')
|
branch: z.string().optional().describe('目标分支,默认 notion/shuangyan')
|
||||||
},
|
},
|
||||||
async ({ path, content, message, branch }) => {
|
async ({ path, content, message, branch }) => {
|
||||||
const ref = branch || 'main';
|
const ref = branch || DEFAULT_BRANCH;
|
||||||
let sha = null;
|
let sha = null;
|
||||||
const existing = await repoFetch(`/contents/${encodeURIComponent(path)}?ref=${ref}`);
|
const existing = await repoFetch(`/contents/${encodeURIComponent(path)}?ref=${ref}`);
|
||||||
if (!existing.error) sha = existing.sha;
|
if (!existing.error) sha = existing.sha;
|
||||||
@ -136,10 +137,10 @@ function registerTools(server) {
|
|||||||
{
|
{
|
||||||
path: z.string().describe('文件路径'),
|
path: z.string().describe('文件路径'),
|
||||||
message: z.string().describe('提交信息'),
|
message: z.string().describe('提交信息'),
|
||||||
branch: z.string().optional().describe('分支,默认 main')
|
branch: z.string().optional().describe('分支,默认 notion/shuangyan')
|
||||||
},
|
},
|
||||||
async ({ path, message, branch }) => {
|
async ({ path, message, branch }) => {
|
||||||
const ref = branch || 'main';
|
const ref = branch || DEFAULT_BRANCH;
|
||||||
const existing = await repoFetch(`/contents/${encodeURIComponent(path)}?ref=${ref}`);
|
const existing = await repoFetch(`/contents/${encodeURIComponent(path)}?ref=${ref}`);
|
||||||
if (existing.error) return { content: [{ type: 'text', text: `❌ 文件不存在: ${path}` }] };
|
if (existing.error) return { content: [{ type: 'text', text: `❌ 文件不存在: ${path}` }] };
|
||||||
|
|
||||||
@ -156,11 +157,11 @@ function registerTools(server) {
|
|||||||
server.tool(
|
server.tool(
|
||||||
'repo_list',
|
'repo_list',
|
||||||
'列出仓库目录内容',
|
'列出仓库目录内容',
|
||||||
{ path: z.string().optional().describe('目录路径,默认根目录'), branch: z.string().optional().describe('分支,默认 main') },
|
{ path: z.string().optional().describe('目录路径,默认根目录'), branch: z.string().optional().describe('分支,默认 notion/shuangyan') },
|
||||||
async ({ path, branch }) => {
|
async ({ path, branch }) => {
|
||||||
const dir = path || '';
|
const dir = path || '';
|
||||||
const urlPath = dir ? `/contents/${encodeURIComponent(dir)}` : '/contents';
|
const urlPath = dir ? `/contents/${encodeURIComponent(dir)}` : '/contents';
|
||||||
const data = await repoFetch(`${urlPath}?ref=${branch || 'main'}`);
|
const data = await repoFetch(`${urlPath}?ref=${branch || DEFAULT_BRANCH}`);
|
||||||
if (data.error) return { content: [{ type: 'text', text: `❌ 列出失败: ${data.message}` }] };
|
if (data.error) return { content: [{ type: 'text', text: `❌ 列出失败: ${data.message}` }] };
|
||||||
if (!Array.isArray(data)) {
|
if (!Array.isArray(data)) {
|
||||||
return { content: [{ type: 'text', text: `📄 ${dir || '/'} 是一个文件,请用 repo_read 读取` }] };
|
return { content: [{ type: 'text', text: `📄 ${dir || '/'} 是一个文件,请用 repo_read 读取` }] };
|
||||||
@ -236,12 +237,12 @@ function registerTools(server) {
|
|||||||
title: z.string().describe('PR 标题'),
|
title: z.string().describe('PR 标题'),
|
||||||
body: z.string().optional().describe('PR 描述'),
|
body: z.string().optional().describe('PR 描述'),
|
||||||
head: z.string().describe('源分支'),
|
head: z.string().describe('源分支'),
|
||||||
base: z.string().optional().describe('目标分支,默认 main')
|
base: z.string().optional().describe('目标分支,默认 notion/shuangyan')
|
||||||
},
|
},
|
||||||
async ({ title, body, head, base }) => {
|
async ({ title, body, head, base }) => {
|
||||||
const result = await repoFetch('/pulls', {
|
const result = await repoFetch('/pulls', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: JSON.stringify({ title, body: body || '', head, base: base || 'main' })
|
body: JSON.stringify({ title, body: body || '', head, base: base || DEFAULT_BRANCH })
|
||||||
});
|
});
|
||||||
if (result.error) return { content: [{ type: 'text', text: `❌ 创建 PR 失败: ${result.message}` }] };
|
if (result.error) return { content: [{ type: 'text', text: `❌ 创建 PR 失败: ${result.message}` }] };
|
||||||
return {
|
return {
|
||||||
@ -325,12 +326,12 @@ function registerTools(server) {
|
|||||||
'查看最近提交历史',
|
'查看最近提交历史',
|
||||||
{
|
{
|
||||||
limit: z.number().optional().describe('数量,默认 10'),
|
limit: z.number().optional().describe('数量,默认 10'),
|
||||||
branch: z.string().optional().describe('分支,默认 main')
|
branch: z.string().optional().describe('分支,默认 notion/shuangyan')
|
||||||
},
|
},
|
||||||
async ({ limit, branch }) => {
|
async ({ limit, branch }) => {
|
||||||
const data = await repoFetch(`/commits?sha=${branch || 'main'}&limit=${limit || 10}`);
|
const data = await repoFetch(`/commits?sha=${branch || DEFAULT_BRANCH}&limit=${limit || 10}`);
|
||||||
if (data.error) return { content: [{ type: 'text', text: `❌ 获取提交历史失败: ${data.message}` }] };
|
if (data.error) return { content: [{ type: 'text', text: `❌ 获取提交历史失败: ${data.message}` }] };
|
||||||
let output = `📜 最近提交 (${branch || 'main'}):\n\n`;
|
let output = `📜 最近提交 (${branch || DEFAULT_BRANCH}):\n\n`;
|
||||||
for (const c of data) {
|
for (const c of data) {
|
||||||
const date = c.commit?.committer?.date?.slice(0, 10) || '';
|
const date = c.commit?.committer?.date?.slice(0, 10) || '';
|
||||||
const msg = (c.commit?.message || '').split('\n')[0];
|
const msg = (c.commit?.message || '').split('\n')[0];
|
||||||
@ -346,13 +347,13 @@ function registerTools(server) {
|
|||||||
'递归列出目录结构(探索仓库骨架)',
|
'递归列出目录结构(探索仓库骨架)',
|
||||||
{
|
{
|
||||||
path: z.string().optional().describe('起始路径,默认 brain'),
|
path: z.string().optional().describe('起始路径,默认 brain'),
|
||||||
branch: z.string().optional().describe('分支,默认 main'),
|
branch: z.string().optional().describe('分支,默认 notion/shuangyan'),
|
||||||
depth: z.number().optional().describe('递归深度,默认 2,最大 4')
|
depth: z.number().optional().describe('递归深度,默认 2,最大 4')
|
||||||
},
|
},
|
||||||
async ({ path, branch, depth }) => {
|
async ({ path, branch, depth }) => {
|
||||||
const startPath = path || 'brain';
|
const startPath = path || 'brain';
|
||||||
const maxDepth = Math.min(depth || 2, 4);
|
const maxDepth = Math.min(depth || 2, 4);
|
||||||
const ref = branch || 'main';
|
const ref = branch || DEFAULT_BRANCH;
|
||||||
|
|
||||||
async function walk(dirPath, currentDepth) {
|
async function walk(dirPath, currentDepth) {
|
||||||
if (currentDepth > maxDepth) return '';
|
if (currentDepth > maxDepth) return '';
|
||||||
@ -425,4 +426,4 @@ app.listen(PORT, () => {
|
|||||||
console.log(`健康: http://localhost:${PORT}/health`);
|
console.log(`健康: http://localhost:${PORT}/health`);
|
||||||
console.log(`MCP: POST http://localhost:${PORT}/mcp`);
|
console.log(`MCP: POST http://localhost:${PORT}/mcp`);
|
||||||
console.log(`认证: ${MCP_SECRET ? '✅ Bearer Token' : '⚠️ 本地模式(仅127.0.0.1)'}`);
|
console.log(`认证: ${MCP_SECRET ? '✅ Bearer Token' : '⚠️ 本地模式(仅127.0.0.1)'}`);
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user