@catchmexz/fedin-vibe-mcp-server 0.1.8 → 0.1.10

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.
@@ -11,7 +11,7 @@ export function getYunxiaoApiBaseUrl() {
11
11
  }
12
12
  export function debug(message, data) {
13
13
  if (data !== undefined) {
14
- console.error(`[DEBUG] ${message}`, typeof data === 'object' ? JSON.stringify(data, null, 2) : data);
14
+ console.error(`[DEBUG] ${message}`, typeof data === "object" ? JSON.stringify(data, null, 2) : data);
15
15
  }
16
16
  else {
17
17
  console.error(`[DEBUG] ${message}`);
@@ -27,7 +27,9 @@ async function parseResponseBody(response) {
27
27
  export function buildUrl(baseUrl, params) {
28
28
  // Handle baseUrl that doesn't have protocol
29
29
  const isAbsolute = baseUrl.startsWith("http://") || baseUrl.startsWith("https://");
30
- const fullBaseUrl = isAbsolute ? baseUrl : `${getYunxiaoApiBaseUrl()}${baseUrl.startsWith('/') ? baseUrl : `/${baseUrl}`}`;
30
+ const fullBaseUrl = isAbsolute
31
+ ? baseUrl
32
+ : `${getYunxiaoApiBaseUrl()}${baseUrl.startsWith("/") ? baseUrl : `/${baseUrl}`}`;
31
33
  try {
32
34
  const url = new URL(fullBaseUrl);
33
35
  Object.entries(params).forEach(([key, value]) => {
@@ -38,7 +40,7 @@ export function buildUrl(baseUrl, params) {
38
40
  const result = url.toString();
39
41
  console.error(`[DEBUG] Final URL: ${result}`);
40
42
  // If we started with a relative URL, return just the path portion
41
- if (!baseUrl.startsWith('http')) {
43
+ if (!baseUrl.startsWith("http")) {
42
44
  // Extract the path and query string from the full URL
43
45
  const urlObj = new URL(result);
44
46
  return urlObj.pathname + urlObj.search;
@@ -56,7 +58,8 @@ export function buildUrl(baseUrl, params) {
56
58
  }
57
59
  });
58
60
  if (queryParts.length > 0) {
59
- urlWithParams += (urlWithParams.includes('?') ? '&' : '?') + queryParts.join('&');
61
+ urlWithParams +=
62
+ (urlWithParams.includes("?") ? "&" : "?") + queryParts.join("&");
60
63
  }
61
64
  console.error(`[DEBUG] Fallback URL: ${urlWithParams}`);
62
65
  return urlWithParams;
@@ -65,24 +68,25 @@ export function buildUrl(baseUrl, params) {
65
68
  const USER_AGENT = `modelcontextprotocol/servers/alibabacloud-devops-mcp-server/v${VERSION} ${getUserAgent()}`;
66
69
  export async function yunxiaoRequest(urlPath, options = {}) {
67
70
  // Check if the URL is already a full URL or a path
71
+ const yunxiao_access_token = "pt-1ntvDyIqJuXDksW1cvnZTKGx_e1815902-148e-4709-a46a-c7b14c003234";
68
72
  const isAbsolute = urlPath.startsWith("http://") || urlPath.startsWith("https://");
69
- let url = isAbsolute ? urlPath : `${getYunxiaoApiBaseUrl()}${urlPath.startsWith("/") ? urlPath : `/${urlPath}`}`;
73
+ let url = isAbsolute
74
+ ? urlPath
75
+ : `${getYunxiaoApiBaseUrl()}${urlPath.startsWith("/") ? urlPath : `/${urlPath}`}`;
70
76
  const requestHeaders = {
71
- "Accept": "application/json",
77
+ Accept: "application/json",
72
78
  "Content-Type": "application/json",
73
79
  "User-Agent": USER_AGENT,
74
- ...options.headers,
80
+ ...options.headers
75
81
  };
76
- if (process.env.YUNXIAO_ACCESS_TOKEN) {
77
- requestHeaders["x-yunxiao-token"] = process.env.YUNXIAO_ACCESS_TOKEN;
78
- }
82
+ requestHeaders["x-yunxiao-token"] = yunxiao_access_token;
79
83
  debug(`Request: ${options.method} ${url}`);
80
84
  debug(`Headers:`, requestHeaders);
81
85
  debug(`Body:`, options.body);
82
86
  const response = await fetch(url, {
83
87
  method: options.method || "GET",
84
88
  headers: requestHeaders,
85
- body: options.body ? JSON.stringify(options.body) : undefined,
89
+ body: options.body ? JSON.stringify(options.body) : undefined
86
90
  });
87
91
  const responseBody = await parseResponseBody(response);
88
92
  debug(`Response Body:`, responseBody);
@@ -127,7 +131,7 @@ export function handleRepositoryIdEncoding(repositoryId) {
127
131
  */
128
132
  export function floatToIntString(value) {
129
133
  // 如果传入的是字符串,先尝试转为浮点数
130
- if (typeof value === 'string') {
134
+ if (typeof value === "string") {
131
135
  const floatValue = parseFloat(value);
132
136
  if (!isNaN(floatValue)) {
133
137
  value = floatValue;
@@ -137,7 +141,7 @@ export function floatToIntString(value) {
137
141
  }
138
142
  }
139
143
  // 处理浮点数
140
- if (typeof value === 'number') {
144
+ if (typeof value === "number") {
141
145
  const intValue = Math.floor(value + 0.5); // 四舍五入转整数
142
146
  return intValue.toString();
143
147
  }
@@ -156,7 +160,7 @@ export function floatToIntString(value) {
156
160
  * @returns 毫秒时间戳
157
161
  */
158
162
  export function convertToTimestamp(time) {
159
- if (typeof time === 'number') {
163
+ if (typeof time === "number") {
160
164
  // 如果已经是数字,假设已是时间戳
161
165
  return time;
162
166
  }
@@ -164,7 +168,7 @@ export function convertToTimestamp(time) {
164
168
  // 如果是Date对象,转换为时间戳
165
169
  return time.getTime();
166
170
  }
167
- else if (typeof time === 'string') {
171
+ else if (typeof time === "string") {
168
172
  // 尝试解析日期字符串
169
173
  const date = new Date(time);
170
174
  if (!isNaN(date.getTime())) {
@@ -172,7 +176,7 @@ export function convertToTimestamp(time) {
172
176
  }
173
177
  }
174
178
  // 无法转换时返回原值(如果是数字)或当前时间戳
175
- return typeof time === 'number' ? time : Date.now();
179
+ return typeof time === "number" ? time : Date.now();
176
180
  }
177
181
  /**
178
182
  * Get start of today timestamp
@@ -200,7 +204,7 @@ export function getEndOfTodayTimestamp() {
200
204
  * @returns Timestamp for start of the specified day
201
205
  */
202
206
  export function getStartOfDayTimestamp(date) {
203
- const targetDate = typeof date === 'string' ? new Date(date) : new Date(date);
207
+ const targetDate = typeof date === "string" ? new Date(date) : new Date(date);
204
208
  targetDate.setHours(0, 0, 0, 0);
205
209
  return targetDate.getTime();
206
210
  }
@@ -210,7 +214,7 @@ export function getStartOfDayTimestamp(date) {
210
214
  * @returns Timestamp for end of the specified day
211
215
  */
212
216
  export function getEndOfDayTimestamp(date) {
213
- const targetDate = typeof date === 'string' ? new Date(date) : new Date(date);
217
+ const targetDate = typeof date === "string" ? new Date(date) : new Date(date);
214
218
  targetDate.setHours(23, 59, 59, 999);
215
219
  return targetDate.getTime();
216
220
  }
@@ -222,9 +226,11 @@ export function getEndOfDayTimestamp(date) {
222
226
  export function getStartOfWeekTimestamp(startOnMonday = true) {
223
227
  const now = new Date();
224
228
  const dayOfWeek = now.getDay(); // 0 is Sunday, 1 is Monday, etc.
225
- const diff = startOnMonday ?
226
- (dayOfWeek === 0 ? 6 : dayOfWeek - 1) : // If startOnMonday, set Sunday as day 7
227
- dayOfWeek;
229
+ const diff = startOnMonday
230
+ ? dayOfWeek === 0
231
+ ? 6
232
+ : dayOfWeek - 1 // If startOnMonday, set Sunday as day 7
233
+ : dayOfWeek;
228
234
  // Set to beginning of the week
229
235
  now.setDate(now.getDate() - diff);
230
236
  now.setHours(0, 0, 0, 0);
@@ -238,9 +244,11 @@ export function getStartOfWeekTimestamp(startOnMonday = true) {
238
244
  export function getEndOfWeekTimestamp(startOnMonday = true) {
239
245
  const now = new Date();
240
246
  const dayOfWeek = now.getDay(); // 0 is Sunday, 1 is Monday, etc.
241
- const diff = startOnMonday ?
242
- (dayOfWeek === 0 ? 0 : 7 - dayOfWeek) : // If startOnMonday, set Sunday as day 7
243
- (6 - dayOfWeek);
247
+ const diff = startOnMonday
248
+ ? dayOfWeek === 0
249
+ ? 0
250
+ : 7 - dayOfWeek // If startOnMonday, set Sunday as day 7
251
+ : 6 - dayOfWeek;
244
252
  // Set to end of the week
245
253
  now.setDate(now.getDate() + diff);
246
254
  now.setHours(23, 59, 59, 999);
@@ -282,13 +290,13 @@ export function parseDateReference(dateReference) {
282
290
  }
283
291
  const normalizedRef = dateReference.trim().toLowerCase();
284
292
  // Today/yesterday
285
- if (normalizedRef === 'today' || normalizedRef === '今天') {
293
+ if (normalizedRef === "today" || normalizedRef === "今天") {
286
294
  return {
287
295
  startTime: getStartOfTodayTimestamp(),
288
296
  endTime: getEndOfTodayTimestamp()
289
297
  };
290
298
  }
291
- if (normalizedRef === 'yesterday' || normalizedRef === '昨天') {
299
+ if (normalizedRef === "yesterday" || normalizedRef === "昨天") {
292
300
  const yesterday = new Date();
293
301
  yesterday.setDate(yesterday.getDate() - 1);
294
302
  return {
@@ -297,16 +305,20 @@ export function parseDateReference(dateReference) {
297
305
  };
298
306
  }
299
307
  // This week/last week
300
- if (normalizedRef === 'this week' || normalizedRef === '本周' ||
301
- normalizedRef === 'current week' || normalizedRef === '这周' ||
302
- normalizedRef === '这个星期') {
308
+ if (normalizedRef === "this week" ||
309
+ normalizedRef === "本周" ||
310
+ normalizedRef === "current week" ||
311
+ normalizedRef === "这周" ||
312
+ normalizedRef === "这个星期") {
303
313
  return {
304
314
  startTime: getStartOfWeekTimestamp(),
305
315
  endTime: getEndOfWeekTimestamp()
306
316
  };
307
317
  }
308
- if (normalizedRef === 'last week' || normalizedRef === '上周' ||
309
- normalizedRef === '上個星期' || normalizedRef === '上个星期') {
318
+ if (normalizedRef === "last week" ||
319
+ normalizedRef === "上周" ||
320
+ normalizedRef === "上個星期" ||
321
+ normalizedRef === "上个星期") {
310
322
  const lastWeekStart = new Date(getStartOfWeekTimestamp());
311
323
  lastWeekStart.setDate(lastWeekStart.getDate() - 7);
312
324
  const lastWeekEnd = new Date(getEndOfWeekTimestamp());
@@ -317,15 +329,18 @@ export function parseDateReference(dateReference) {
317
329
  };
318
330
  }
319
331
  // This month/last month
320
- if (normalizedRef === 'this month' || normalizedRef === '本月' ||
321
- normalizedRef === 'current month' || normalizedRef === '这个月') {
332
+ if (normalizedRef === "this month" ||
333
+ normalizedRef === "本月" ||
334
+ normalizedRef === "current month" ||
335
+ normalizedRef === "这个月") {
322
336
  return {
323
337
  startTime: getStartOfMonthTimestamp(),
324
338
  endTime: getEndOfMonthTimestamp()
325
339
  };
326
340
  }
327
- if (normalizedRef === 'last month' || normalizedRef === '上月' ||
328
- normalizedRef === '上个月') {
341
+ if (normalizedRef === "last month" ||
342
+ normalizedRef === "上月" ||
343
+ normalizedRef === "上个月") {
329
344
  const now = new Date();
330
345
  const lastMonth = new Date(now.getFullYear(), now.getMonth() - 1);
331
346
  // Start of last month
@@ -345,3 +360,21 @@ export function parseDateReference(dateReference) {
345
360
  endTime: Date.now()
346
361
  };
347
362
  }
363
+ export async function fedinQueryRequest(endpoint, query) {
364
+ try {
365
+ const response = await fetch(`https://ai.fedin.cn/${endpoint}`, {
366
+ method: "post",
367
+ body: JSON.stringify({
368
+ query
369
+ }),
370
+ headers: {
371
+ "Content-Type": "application/json"
372
+ }
373
+ });
374
+ const data = await response.json();
375
+ return data;
376
+ }
377
+ catch (error) {
378
+ return [];
379
+ }
380
+ }
package/dist/index.js CHANGED
@@ -9,6 +9,7 @@ import { VERSION } from "./common/version.js";
9
9
  import { config } from "dotenv";
10
10
  import { getAllTools } from "./tool-registry/index.js";
11
11
  import { handleToolRequest } from "./tool-handlers/index.js";
12
+ import { fedinQueryRequest } from "./common/utils.js";
12
13
  const server = new Server({
13
14
  name: "alibabacloud-devops-mcp-server",
14
15
  version: VERSION,
@@ -64,47 +65,10 @@ function formatYunxiaoError(error) {
64
65
  }
65
66
  return message;
66
67
  }
67
- async function getRepositoryIdWithPat(pat) {
68
- const query = `
69
- SELECT
70
- c.*,
71
- ch.pat,
72
- ch.id as project_id,
73
- ch.mini_app_id
74
- FROM
75
- public.codeup AS c
76
- INNER JOIN
77
- public.chat_history AS ch
78
- ON
79
- c.chat_id = ch.id
80
- WHERE
81
- ch.pat = '${pat}'
82
- `;
83
- try {
84
- const response = await fetch('https://ai.fedin.cn/api/supabase/query', {
85
- method: "post",
86
- body: JSON.stringify({
87
- query
88
- }),
89
- headers: {
90
- 'Content-Type': 'application/json',
91
- },
92
- });
93
- const data = await response.json();
94
- if (data.length > 0) {
95
- return {
96
- repositoryId: data[0].repositoryId,
97
- projectId: data[0].project_id,
98
- miniappId: data[0].mini_app_id
99
- };
100
- }
101
- else {
102
- throw new Error("pat密钥无效:未找到对应的repositoryId");
103
- }
104
- }
105
- catch (error) {
106
- throw new Error("获取repositoryId失败");
107
- }
68
+ async function checkTokenValid(token) {
69
+ const query = `SELECT * FROM codeup_tokens WHERE token = '${token}'`;
70
+ const response = await fedinQueryRequest("api/supabase/query", query);
71
+ return response.length > 0;
108
72
  }
109
73
  server.setRequestHandler(ListToolsRequestSchema, async () => {
110
74
  return {
@@ -116,25 +80,33 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
116
80
  if (!request.params.arguments) {
117
81
  throw new Error("Arguments are required");
118
82
  }
119
- let pat = "";
120
- process.argv.forEach(arg => {
121
- if (arg.includes("--project-pat")) {
122
- pat = arg.split("=")?.[1];
123
- }
124
- });
125
- if (!pat) {
126
- throw new Error("缺少项目访问令牌project-pat");
127
- }
128
- const { repositoryId, projectId, miniappId } = await getRepositoryIdWithPat(pat);
129
- if (!repositoryId) {
130
- throw new Error("获取repositoryId失败");
83
+ const fedin_token = process.env.FEDIN_ACCESS_TOKEN;
84
+ if (!fedin_token) {
85
+ throw new Error("无权限访问:缺少访问令牌");
131
86
  }
132
- request.params.arguments.repositoryId = repositoryId;
133
- request.params.arguments.projectId = projectId;
134
- // 只有当 miniappId 不为 null 时才注入,避免 Zod 验证错误
135
- if (miniappId) {
136
- request.params.arguments.miniappId = miniappId;
87
+ const isTokenValid = await checkTokenValid(fedin_token);
88
+ if (!isTokenValid) {
89
+ throw new Error("无权限访问:访问令牌无效");
137
90
  }
91
+ // let pat = "";
92
+ // process.argv.forEach(arg => {
93
+ // if (arg.includes("--project-pat")) {
94
+ // pat = arg.split("=")?.[1];
95
+ // }
96
+ // })
97
+ // if (!pat) {
98
+ // throw new Error("缺少项目访问令牌project-pat");
99
+ // }
100
+ // const { repositoryId, projectId, miniappId } = await getRepositoryIdWithPat(pat);
101
+ // if (!repositoryId) {
102
+ // throw new Error("获取repositoryId失败");
103
+ // }
104
+ // request.params.arguments.repositoryId = repositoryId;
105
+ // request.params.arguments.projectId = projectId;
106
+ // // 只有当 miniappId 不为 null 时才注入,避免 Zod 验证错误
107
+ // if (miniappId) {
108
+ // request.params.arguments.miniappId = miniappId;
109
+ // }
138
110
  // Delegate to our modular tool handler
139
111
  return await handleToolRequest(request);
140
112
  }
@@ -4,6 +4,7 @@ import * as fs from "fs";
4
4
  import pkg from "fs-extra";
5
5
  import * as path from "path";
6
6
  import minimatch from "minimatch";
7
+ import { fedinQueryRequest } from "../../common/utils.js";
7
8
  const { removeSync } = pkg;
8
9
  function readGitignore(projectPath) {
9
10
  const gitignorePath = path.join(projectPath, ".gitignore");
@@ -250,46 +251,8 @@ export async function createFileFunc(organizationId, repositoryId, filePath, con
250
251
  });
251
252
  return CreateFileResponseSchema.parse(response);
252
253
  }
253
- async function getRepositoryDomain(projectId) {
254
- const query = `
255
- SELECT
256
- ch.id as id,
257
- ch.custom_domain as custom_domain,
258
- ch.domain_certificate as domain_certificate
259
- FROM
260
- public.chat_history AS ch
261
- WHERE
262
- ch.id = '${projectId}'
263
- `;
264
- try {
265
- const response = await fetch("https://ai.fedin.cn/api/supabase/query", {
266
- method: "post",
267
- body: JSON.stringify({
268
- query
269
- }),
270
- headers: {
271
- "Content-Type": "application/json"
272
- }
273
- });
274
- const data = await response.json();
275
- if (data.length > 0) {
276
- return {
277
- id: data[0].id,
278
- custom_domain: data[0].custom_domain,
279
- domain_certificate: data[0].domain_certificate
280
- };
281
- }
282
- else {
283
- console.error("项目ID无效:未找到对应的项目");
284
- return {};
285
- }
286
- }
287
- catch (error) {
288
- console.error("获取项目信息失败", error);
289
- return {};
290
- }
291
- }
292
- export async function pushFilesFunc(organizationId, repositoryId, commitMessage, projectPath, projectId) {
254
+ export async function pushFilesFunc(organizationId, projectId, currntProjectPath, commitMessage) {
255
+ let repositoryId = "";
293
256
  // 读取 .gitignore 模式
294
257
  // const ignorePatterns = readGitignore(projectPath);
295
258
  const ignorePatterns = [
@@ -306,8 +269,35 @@ export async function pushFilesFunc(organizationId, repositoryId, commitMessage,
306
269
  "package-lock.json",
307
270
  ".DS_Store"
308
271
  ];
272
+ const selectProjectQuery = `SELECT id FROM chat_history WHERE id = '${projectId}'`;
273
+ const projectResult = await fedinQueryRequest("api/supabase/query", selectProjectQuery);
274
+ if (!projectResult.length) {
275
+ throw new Error("当前项目不存在");
276
+ }
277
+ const query = `SELECT ch.id
278
+ FROM chat_history ch
279
+ JOIN codeup_tokens ct ON ch.user_id = ct.user_id
280
+ WHERE ct.token = '${process.env.FEDIN_ACCESS_TOKEN}';`;
281
+ const projects = await fedinQueryRequest("api/supabase/query", query);
282
+ if (!projects.length) {
283
+ throw new Error("token密钥未找到对应项目,请确保密钥的可用性");
284
+ }
285
+ // 判断查到的projects是否存在projectId
286
+ const project = projects.find((project) => project.id === projectId);
287
+ if (!project) {
288
+ throw new Error("无权限访问当前项目仓库");
289
+ }
290
+ const queryCodeUp = `SELECT "repositoryId" FROM codeup WHERE chat_id = '${projectId}'`;
291
+ const codeupDetail = await fedinQueryRequest("api/supabase/query", queryCodeUp);
292
+ if (!codeupDetail.length) {
293
+ throw new Error("当前项目仓库不存在,请先创建仓库");
294
+ }
295
+ repositoryId = codeupDetail[0].repositoryId;
296
+ if (!repositoryId) {
297
+ throw new Error("当前项目仓库不存在,请先到飞钉AI推送项目代码");
298
+ }
309
299
  // 获取所有文件
310
- const files = getAllFiles(projectPath, ignorePatterns);
300
+ const files = getAllFiles(currntProjectPath, ignorePatterns);
311
301
  // 检测项目类型
312
302
  let projectType = "default"; // 默认值
313
303
  // 检查是否存在 Next.js 配置文件
@@ -368,16 +358,8 @@ export async function pushFilesFunc(organizationId, repositoryId, commitMessage,
368
358
  repoUrl: `https://codeup.aliyun.com/ctrod/fedin-ai-project/${projectId}.git`,
369
359
  projectType,
370
360
  organizationId: organizationId,
371
- token: process.env.YUNXIAO_ACCESS_TOKEN
361
+ token: "pt-1ntvDyIqJuXDksW1cvnZTKGx_e1815902-148e-4709-a46a-c7b14c003234"
372
362
  };
373
- const projectInfo = await getRepositoryDomain(projectId);
374
- if (projectInfo.custom_domain) {
375
- pipelineBody.customDomain = projectInfo.custom_domain;
376
- }
377
- // 如果配置了证书,添加到请求体中
378
- if (projectInfo.domain_certificate) {
379
- pipelineBody.certificate = projectInfo.domain_certificate;
380
- }
381
363
  const pipelineResponse = await fetch("https://ai.fedin.cn/api/alicloud/create-pipeline-run", {
382
364
  method: "POST",
383
365
  body: JSON.stringify(pipelineBody),
@@ -409,7 +391,35 @@ export async function pushFilesFunc(organizationId, repositoryId, commitMessage,
409
391
  * @param repositoryId
410
392
  * @param projectPath
411
393
  */
412
- export async function pullFilesFunc(organizationId, repositoryId, currntProjectPath) {
394
+ export async function pullFilesFunc(organizationId, projectId, currntProjectPath) {
395
+ let repositoryId = "";
396
+ const selectProjectQuery = `SELECT id FROM chat_history WHERE id = '${projectId}'`;
397
+ const projectResult = await fedinQueryRequest("api/supabase/query", selectProjectQuery);
398
+ if (!projectResult.length) {
399
+ throw new Error("当前项目不存在");
400
+ }
401
+ const query = `SELECT ch.id
402
+ FROM chat_history ch
403
+ JOIN codeup_tokens ct ON ch.user_id = ct.user_id
404
+ WHERE ct.token = '${process.env.FEDIN_ACCESS_TOKEN}';`;
405
+ const projects = await fedinQueryRequest("api/supabase/query", query);
406
+ if (!projects.length) {
407
+ throw new Error("token密钥未找到对应项目,请确保密钥的可用性");
408
+ }
409
+ // 判断查到的projects是否存在projectId
410
+ const project = projects.find((project) => project.id === projectId);
411
+ if (!project) {
412
+ throw new Error("无权限访问当前项目仓库");
413
+ }
414
+ const queryCodeUp = `SELECT "repositoryId" FROM codeup WHERE chat_id = '${projectId}'`;
415
+ const codeupDetail = await fedinQueryRequest("api/supabase/query", queryCodeUp);
416
+ if (!codeupDetail.length) {
417
+ throw new Error("当前项目仓库不存在,请先创建仓库");
418
+ }
419
+ repositoryId = codeupDetail[0].repositoryId;
420
+ if (!repositoryId) {
421
+ throw new Error("当前项目仓库不存在,请先到飞钉AI推送项目代码");
422
+ }
413
423
  // 拉取之前 需要将当前projectPath路径下的所有代码文件清空
414
424
  await clearProjectPath(currntProjectPath);
415
425
  const allRemoteFilesPath = await listFilesFunc(organizationId, repositoryId, undefined, "master", "RECURSIVE");
@@ -1,5 +1,6 @@
1
1
  import { yunxiaoRequest, buildUrl, handleRepositoryIdEncoding } from "../../common/utils.js";
2
2
  import { RepositorySchema } from "./types.js";
3
+ import { fedinQueryRequest } from "../../common/utils.js";
3
4
  /**
4
5
  * 创建仓库
5
6
  * @param organizationId
@@ -70,5 +71,15 @@ export async function listRepositoriesFunc(organizationId, page, perPage, orderB
70
71
  if (!Array.isArray(response)) {
71
72
  return [];
72
73
  }
73
- return response.map((repo) => RepositorySchema.parse(repo));
74
+ const query = `SELECT cu."repositoryId"
75
+ FROM codeup cu
76
+ JOIN codeup_tokens ct ON cu.user_id = ct.user_id
77
+ WHERE ct.token = '${process.env.FEDIN_ACCESS_TOKEN}' AND cu."repositoryId" IS NOT NULL;`;
78
+ const projects = await fedinQueryRequest("api/supabase/query", query);
79
+ if (!projects.length) {
80
+ return [];
81
+ }
82
+ const availableProjectIds = projects.map((project) => Number(project.repositoryId));
83
+ const availableRepositories = response.filter((repo) => availableProjectIds.includes(repo.id));
84
+ return availableRepositories.map((repo) => RepositorySchema.parse(repo));
74
85
  }
@@ -266,12 +266,14 @@ export const CreateFileSchema = z.object({
266
266
  });
267
267
  export const PushFilesSchema = z.object({
268
268
  organizationId: z.string().describe("Organization ID, can be found in the basic information page of the organization admin console"),
269
- projectPath: z.string().describe("The project path, and it must be an absolute path."),
269
+ currntProjectPath: z.string().describe("The project path, and it must be an absolute path."),
270
+ projectId: z.string().describe("Project ID. Note that this is not the repository ID, but the project ID. The project ID is obtained from the user’s message. If the user’s message does not mention it, then it is retrieved from the projectName field in the package.json file."),
270
271
  commitMessage: z.string().describe("Commit message, not empty, no more than 102400 characters")
271
272
  });
272
273
  export const PullFilesSchema = z.object({
273
274
  organizationId: z.string().describe("Organization ID, can be found in the basic information page of the organization admin console"),
274
275
  currntProjectPath: z.string().describe("The absolute local path of the current project, and it must be an absolute path."),
276
+ projectId: z.string().describe("Project ID, the ID of the project corresponding to the repository to be fetched.")
275
277
  });
276
278
  export const UpdateFileSchema = z.object({
277
279
  organizationId: z.string().describe("Organization ID, can be found in the basic information page of the organization admin console"),
@@ -52,8 +52,8 @@ export const handleCodeManagementTools = async (request) => {
52
52
  };
53
53
  }
54
54
  case "push_files": {
55
- const args = request.params.arguments;
56
- const result = await files.pushFilesFunc(args.organizationId, args.repositoryId, args.commitMessage, args.projectPath, args.projectId);
55
+ const args = types.PushFilesSchema.parse(request.params.arguments);
56
+ const result = await files.pushFilesFunc(args.organizationId, args.projectId, args.currntProjectPath, args.commitMessage);
57
57
  const returnText = `项目部署地址:${result.onlineUrl}\n文件推送结果:${JSON.stringify(result.pushResult)}
58
58
  `;
59
59
  return {
@@ -61,8 +61,8 @@ export const handleCodeManagementTools = async (request) => {
61
61
  };
62
62
  }
63
63
  case "pull_files": {
64
- const args = request.params.arguments;
65
- const result = await files.pullFilesFunc(args.organizationId, args.repositoryId, args.currntProjectPath);
64
+ const args = types.PullFilesSchema.parse(request.params.arguments);
65
+ const result = await files.pullFilesFunc(args.organizationId, args.projectId, args.currntProjectPath);
66
66
  return {
67
67
  content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
68
68
  };
@@ -12,4 +12,20 @@ export const getCodeManagementTools = () => [
12
12
  describe: "[Code Management] Synchronize the latest code from a Codeup repository, ensuring local project alignment with remote repository state. Use when: User needs to update local codebase with the most recent changes from the remote repository.",
13
13
  inputSchema: zodToJsonSchema(types.PullFilesSchema),
14
14
  },
15
+ {
16
+ name: "get_repository",
17
+ description: "[Code Management] Get information about a Codeup repository",
18
+ inputSchema: zodToJsonSchema(types.GetRepositorySchema),
19
+ },
20
+ {
21
+ name: "list_repositories",
22
+ description: "[Code Management] Get the CodeUp Repository List.\n" +
23
+ "\n" +
24
+ "A Repository serves as a unit for managing source code and is distinct from a Project.\n" +
25
+ "\n" +
26
+ "Use Case:\n" +
27
+ "\n" +
28
+ "View my repositories",
29
+ inputSchema: zodToJsonSchema(types.ListRepositoriesSchema),
30
+ },
15
31
  ];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@catchmexz/fedin-vibe-mcp-server",
3
- "version": "0.1.8",
3
+ "version": "0.1.10",
4
4
  "type": "module",
5
5
  "publishConfig": {
6
6
  "access": "public"