plugin-git-manager 1.1.12 → 1.2.1

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.
@@ -1,12 +1,3 @@
1
- /**
2
- * This file is part of the NocoBase (R) project.
3
- * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
- * Authors: NocoBase Team.
5
- *
6
- * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
- * For more information, please refer to: https://www.nocobase.com/agreement.
8
- */
9
-
10
1
  var __defProp = Object.defineProperty;
11
2
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
12
3
  var __getOwnPropNames = Object.getOwnPropertyNames;
@@ -50,6 +41,17 @@ const REVIEW_QUEUE_TIMEOUT_MS = Math.max(
50
41
  6e4,
51
42
  Number.parseInt(process.env.GIT_REVIEW_QUEUE_TIMEOUT_MS || "", 10) || 10 * 60 * 1e3
52
43
  );
44
+ const REVIEW_QUEUE_POLL_INTERVAL_MS = Math.max(
45
+ 1e3,
46
+ Number.parseInt(process.env.GIT_REVIEW_QUEUE_POLL_INTERVAL_MS || "", 10) || 5e3
47
+ );
48
+ const REVIEW_PROCESS_LOCK_TTL_MS = Math.max(REVIEW_QUEUE_TIMEOUT_MS + 6e4, 11 * 60 * 1e3);
49
+ const REVIEW_QUEUE_WAKE_CHANNEL = "plugin-git-manager.review.wake";
50
+ const REVIEW_QUEUE_REDIS_CONNECTION = "plugin-git-manager.review.queue";
51
+ let reviewQueueTimer = null;
52
+ let reviewQueueKickTimer = null;
53
+ let reviewQueueProcessing = false;
54
+ let reviewWakeHandler = null;
53
55
  function getActionParams(ctx) {
54
56
  var _a, _b;
55
57
  return { ...ctx.action.params, ...(_a = ctx.action.params) == null ? void 0 : _a.values, ...((_b = ctx.request) == null ? void 0 : _b.body) || {} };
@@ -67,15 +69,7 @@ async function withTriggerLock(app, key, fn) {
67
69
  async function triggerReview(ctx, next) {
68
70
  var _a, _b;
69
71
  const params = getActionParams(ctx);
70
- const {
71
- flowId,
72
- repositoryId,
73
- targetType,
74
- mrIid,
75
- commitSha,
76
- branch,
77
- extraInstructions
78
- } = params;
72
+ const { flowId, repositoryId, targetType, mrIid, commitSha, branch, extraInstructions } = params;
79
73
  if (!repositoryId) ctx.throw(400, "repositoryId is required");
80
74
  if (!targetType) ctx.throw(400, "targetType is required");
81
75
  if (!["mr", "commit", "branch"].includes(targetType)) ctx.throw(400, "invalid targetType");
@@ -156,12 +150,19 @@ async function triggerReviewInternalLocked(app, args) {
156
150
  triggeredBy: args.triggeredBy || "manual",
157
151
  status: "pending",
158
152
  // `startedAt` is stamped by the queue worker when execution actually
159
- // starts. Pending rows may be legitimately waiting in Redis.
153
+ // starts. Pending rows are durable queue items for worker polling.
160
154
  startedAt: null,
161
155
  finishedAt: null,
162
156
  durationMs: null,
163
157
  postStatus: getInitialPostStatus(flow, args.targetType),
164
- error: null
158
+ error: null,
159
+ metadata: {
160
+ queuedAt: (/* @__PURE__ */ new Date()).toISOString(),
161
+ aiEmployeeUsername,
162
+ extraInstructions: args.extraInstructions || null,
163
+ userId: args.userId ?? null,
164
+ flowSnapshot: createFlowSnapshot(flow)
165
+ }
165
166
  };
166
167
  let reviewId;
167
168
  if (existing) {
@@ -201,9 +202,14 @@ function registerReviewQueue(app) {
201
202
  await processQueuedReview(app, message);
202
203
  }
203
204
  });
205
+ if (!isGitReviewWorker(app)) {
206
+ app.on("afterStart", () => clearLocalReviewMemoryQueue(app));
207
+ }
208
+ startReviewQueueProcessor(app);
204
209
  }
205
210
  function unregisterReviewQueue(app) {
206
211
  app.eventQueue.unsubscribe(REVIEW_QUEUE_CHANNEL);
212
+ stopReviewQueueProcessor(app);
207
213
  }
208
214
  function createFlowSnapshot(flow) {
209
215
  return {
@@ -230,12 +236,215 @@ function isGitReviewWorker(app) {
230
236
  const workerMode = process.env.WORKER_MODE || "";
231
237
  return app.serving(WORKER_JOB_GIT_REVIEW_PROCESS) || workerMode === "worker" || workerMode === "task" || process.env.APP_ROLE === "worker";
232
238
  }
233
- async function enqueueReview(app, message) {
239
+ function clearLocalReviewMemoryQueue(app) {
240
+ var _a, _b, _c, _d, _e;
241
+ const eventQueue = app.eventQueue;
242
+ const adapter = eventQueue == null ? void 0 : eventQueue.adapter;
243
+ const fullChannel = (_a = eventQueue == null ? void 0 : eventQueue.getFullChannel) == null ? void 0 : _a.call(eventQueue, REVIEW_QUEUE_CHANNEL);
244
+ const queue = fullChannel ? (_c = (_b = adapter == null ? void 0 : adapter.queues) == null ? void 0 : _b.get) == null ? void 0 : _c.call(_b, fullChannel) : null;
245
+ if (!(queue == null ? void 0 : queue.length)) return;
246
+ adapter.queues.set(fullChannel, []);
247
+ (_e = (_d = app.log) == null ? void 0 : _d.warn) == null ? void 0 : _e.call(
248
+ _d,
249
+ `git review queue: cleared ${queue.length} stale local memory message(s) on non-worker node; pending DB rows will be picked up by workers`
250
+ );
251
+ }
252
+ function getReviewQueueRedisKey(app) {
253
+ const appName = app.name || process.env.APP_NAME || "main";
254
+ return `${appName}:plugin-git-manager:review:queue`;
255
+ }
256
+ async function getReviewQueueRedis(app) {
257
+ var _a, _b;
258
+ const manager = app.redisConnectionManager;
259
+ if (!(manager == null ? void 0 : manager.getConnectionSync)) {
260
+ return null;
261
+ }
234
262
  try {
235
- await app.eventQueue.publish(REVIEW_QUEUE_CHANNEL, message, {
236
- timeout: REVIEW_QUEUE_TIMEOUT_MS,
237
- maxRetries: 1
263
+ const connectionString = process.env.QUEUE_ADAPTER_REDIS_URL || process.env.REDIS_URL;
264
+ return await manager.getConnectionSync(
265
+ REVIEW_QUEUE_REDIS_CONNECTION,
266
+ connectionString ? { connectionString } : void 0
267
+ );
268
+ } catch (err) {
269
+ (_b = (_a = app.log) == null ? void 0 : _a.debug) == null ? void 0 : _b.call(_a, `git review queue: Redis queue unavailable, falling back to DB polling: ${(err == null ? void 0 : err.message) || err}`);
270
+ return null;
271
+ }
272
+ }
273
+ async function enqueueReviewToRedis(app, message) {
274
+ var _a, _b;
275
+ const redis = await getReviewQueueRedis(app);
276
+ if (!redis) return false;
277
+ await redis.sendCommand(["RPUSH", getReviewQueueRedisKey(app), JSON.stringify(message)]);
278
+ (_b = (_a = app.log) == null ? void 0 : _a.debug) == null ? void 0 : _b.call(_a, `git review queue: enqueued review ${message.reviewId} to Redis`);
279
+ return true;
280
+ }
281
+ async function publishReviewQueueWake(app, reviewId) {
282
+ var _a, _b, _c, _d;
283
+ try {
284
+ await ((_b = (_a = app.pubSubManager) == null ? void 0 : _a.publish) == null ? void 0 : _b.call(
285
+ _a,
286
+ REVIEW_QUEUE_WAKE_CHANNEL,
287
+ { reviewId },
288
+ { skipSelf: !isGitReviewWorker(app) }
289
+ ));
290
+ } catch (err) {
291
+ (_d = (_c = app.log) == null ? void 0 : _c.debug) == null ? void 0 : _d.call(_c, `git review queue: wake publish skipped: ${(err == null ? void 0 : err.message) || err}`);
292
+ }
293
+ }
294
+ function startReviewQueueProcessor(app) {
295
+ var _a, _b, _c, _d, _e, _f, _g;
296
+ if (!isGitReviewWorker(app)) {
297
+ (_b = (_a = app.log) == null ? void 0 : _a.debug) == null ? void 0 : _b.call(_a, "plugin-git-manager: review queue processor disabled on non-worker node");
298
+ return;
299
+ }
300
+ if (reviewQueueTimer) return;
301
+ reviewWakeHandler = async () => {
302
+ scheduleReviewQueueTick(app, 0);
303
+ };
304
+ const subscribe = (_d = (_c = app.pubSubManager) == null ? void 0 : _c.subscribe) == null ? void 0 : _d.call(_c, REVIEW_QUEUE_WAKE_CHANNEL, reviewWakeHandler);
305
+ if (subscribe == null ? void 0 : subscribe.catch) {
306
+ subscribe.catch((err) => {
307
+ var _a2, _b2;
308
+ return (_b2 = (_a2 = app.log) == null ? void 0 : _a2.debug) == null ? void 0 : _b2.call(_a2, `git review queue: wake subscribe skipped: ${(err == null ? void 0 : err.message) || err}`);
238
309
  });
310
+ }
311
+ reviewQueueTimer = setInterval(() => scheduleReviewQueueTick(app, 0), REVIEW_QUEUE_POLL_INTERVAL_MS);
312
+ (_e = reviewQueueTimer.unref) == null ? void 0 : _e.call(reviewQueueTimer);
313
+ scheduleReviewQueueTick(app, 1e3);
314
+ (_g = (_f = app.log) == null ? void 0 : _f.info) == null ? void 0 : _g.call(_f, `plugin-git-manager: review queue processor started (interval ${REVIEW_QUEUE_POLL_INTERVAL_MS}ms)`);
315
+ }
316
+ function stopReviewQueueProcessor(app) {
317
+ var _a, _b;
318
+ if (reviewQueueTimer) {
319
+ clearInterval(reviewQueueTimer);
320
+ reviewQueueTimer = null;
321
+ }
322
+ if (reviewQueueKickTimer) {
323
+ clearTimeout(reviewQueueKickTimer);
324
+ reviewQueueKickTimer = null;
325
+ }
326
+ if (reviewWakeHandler) {
327
+ const unsubscribe = (_b = (_a = app.pubSubManager) == null ? void 0 : _a.unsubscribe) == null ? void 0 : _b.call(_a, REVIEW_QUEUE_WAKE_CHANNEL, reviewWakeHandler);
328
+ if (unsubscribe == null ? void 0 : unsubscribe.catch) {
329
+ unsubscribe.catch(() => void 0);
330
+ }
331
+ reviewWakeHandler = null;
332
+ }
333
+ reviewQueueProcessing = false;
334
+ }
335
+ function scheduleReviewQueueTick(app, delayMs) {
336
+ var _a;
337
+ if (reviewQueueKickTimer) return;
338
+ reviewQueueKickTimer = setTimeout(() => {
339
+ reviewQueueKickTimer = null;
340
+ runReviewQueueTick(app).catch((err) => {
341
+ var _a2, _b;
342
+ return (_b = (_a2 = app.log) == null ? void 0 : _a2.error) == null ? void 0 : _b.call(_a2, "git review queue: processor tick failed", err);
343
+ });
344
+ }, delayMs);
345
+ (_a = reviewQueueKickTimer.unref) == null ? void 0 : _a.call(reviewQueueKickTimer);
346
+ }
347
+ async function runReviewQueueTick(app) {
348
+ if (reviewQueueProcessing || !isGitReviewWorker(app)) return;
349
+ reviewQueueProcessing = true;
350
+ try {
351
+ const redisMessages = await drainRedisReviewQueue(app, REVIEW_QUEUE_CONCURRENCY);
352
+ await processReviewQueueMessages(app, redisMessages);
353
+ const remaining = Math.max(1, REVIEW_QUEUE_CONCURRENCY - redisMessages.length);
354
+ await processPendingReviews(app, remaining);
355
+ } finally {
356
+ reviewQueueProcessing = false;
357
+ }
358
+ }
359
+ async function drainRedisReviewQueue(app, count) {
360
+ var _a, _b;
361
+ const redis = await getReviewQueueRedis(app);
362
+ if (!redis) return [];
363
+ const key = getReviewQueueRedisKey(app);
364
+ const messages = [];
365
+ for (let i = 0; i < count; i += 1) {
366
+ const raw = await redis.sendCommand(["LPOP", key]);
367
+ if (!raw) break;
368
+ try {
369
+ messages.push(JSON.parse(String(raw)));
370
+ } catch (err) {
371
+ (_b = (_a = app.log) == null ? void 0 : _a.warn) == null ? void 0 : _b.call(_a, `git review queue: dropped invalid Redis message: ${(err == null ? void 0 : err.message) || err}`);
372
+ }
373
+ }
374
+ return messages;
375
+ }
376
+ function getQueuedReviewMetadata(review) {
377
+ var _a;
378
+ const raw = (_a = review == null ? void 0 : review.get) == null ? void 0 : _a.call(review, "metadata");
379
+ if (!raw) return {};
380
+ if (typeof raw === "string") {
381
+ try {
382
+ return JSON.parse(raw) || {};
383
+ } catch {
384
+ return {};
385
+ }
386
+ }
387
+ return typeof raw === "object" ? raw : {};
388
+ }
389
+ function toNullableNumber(value) {
390
+ if (value === null || value === void 0 || value === "") return null;
391
+ const parsed = Number(value);
392
+ return Number.isFinite(parsed) ? parsed : null;
393
+ }
394
+ function createReviewQueueMessageFromReview(review) {
395
+ const metadata = getQueuedReviewMetadata(review);
396
+ const targetType = review.get("targetType");
397
+ return {
398
+ reviewId: Number(review.get("id")),
399
+ repositoryId: Number(review.get("repositoryId")),
400
+ targetType,
401
+ mrIid: targetType === "mr" ? toNullableNumber(review.get("mrIid")) : null,
402
+ commitSha: targetType === "commit" ? review.get("commitSha") : null,
403
+ branch: targetType === "branch" ? review.get("branch") : null,
404
+ headSha: review.get("headSha"),
405
+ aiEmployeeUsername: metadata.aiEmployeeUsername || "",
406
+ extraInstructions: metadata.extraInstructions || void 0,
407
+ userId: metadata.userId ?? null,
408
+ flowSnapshot: metadata.flowSnapshot
409
+ };
410
+ }
411
+ async function processPendingReviews(app, count) {
412
+ const pending = await app.db.getRepository("gitCodeReviews").find({
413
+ filter: { status: "pending" },
414
+ sort: ["createdAt"],
415
+ limit: count
416
+ });
417
+ if (!(pending == null ? void 0 : pending.length)) return;
418
+ await processReviewQueueMessages(app, pending.map(createReviewQueueMessageFromReview));
419
+ }
420
+ async function processReviewQueueMessages(app, messages) {
421
+ if (!messages.length) return;
422
+ await Promise.all(messages.map((message) => processQueuedReview(app, message)));
423
+ }
424
+ async function withReviewProcessLock(app, reviewId, fn) {
425
+ const lockKey = `git-review:process:${reviewId}`;
426
+ return app.lockManager.runExclusive(lockKey, fn, REVIEW_PROCESS_LOCK_TTL_MS);
427
+ }
428
+ async function enqueueReview(app, message) {
429
+ var _a, _b;
430
+ try {
431
+ const queuedInRedis = await enqueueReviewToRedis(app, message);
432
+ if (queuedInRedis) {
433
+ await publishReviewQueueWake(app, message.reviewId);
434
+ return;
435
+ }
436
+ await publishReviewQueueWake(app, message.reviewId);
437
+ if (isGitReviewWorker(app)) {
438
+ await app.eventQueue.publish(REVIEW_QUEUE_CHANNEL, message, {
439
+ timeout: REVIEW_QUEUE_TIMEOUT_MS,
440
+ maxRetries: 1
441
+ });
442
+ return;
443
+ }
444
+ (_b = (_a = app.log) == null ? void 0 : _a.warn) == null ? void 0 : _b.call(
445
+ _a,
446
+ `git review queue: Redis queue is unavailable; review ${message.reviewId} will remain pending until a worker DB poller picks it up`
447
+ );
239
448
  } catch (err) {
240
449
  const safeMessage = (0, import_redact.redactPat)((err == null ? void 0 : err.message) || String(err));
241
450
  await app.db.getRepository("gitCodeReviews").update({
@@ -261,46 +470,51 @@ async function failQueuedReview(app, reviewId, err) {
261
470
  });
262
471
  }
263
472
  async function processQueuedReview(app, message) {
264
- var _a, _b, _c, _d, _e, _f, _g;
265
- const db = app.db;
266
- const reviewsRepo = db.getRepository("gitCodeReviews");
267
- const review = await reviewsRepo.findOne({ filterByTk: message.reviewId });
268
- if (!review) {
269
- (_b = (_a = app.log) == null ? void 0 : _a.warn) == null ? void 0 : _b.call(_a, `git review queue: review ${message.reviewId} not found, skipping`);
270
- return;
271
- }
272
- if (review.get("status") !== "pending") {
273
- (_d = (_c = app.log) == null ? void 0 : _c.info) == null ? void 0 : _d.call(_c, `git review queue: review ${message.reviewId} is ${review.get("status")}, skipping`);
274
- return;
275
- }
276
- try {
277
- const repo = await db.getRepository("gitRepositories").findOne({
278
- filterByTk: message.repositoryId || review.get("repositoryId")
279
- });
280
- if (!repo) throw new Error("Repository not found");
281
- const storedFlow = await db.getRepository("gitReviewFlows").findOne({
282
- filterByTk: ((_e = message.flowSnapshot) == null ? void 0 : _e.id) || review.get("flowId")
283
- });
284
- const flow = createFlowFromSnapshot(message.flowSnapshot, storedFlow);
285
- const aiEmployeeUsername = message.aiEmployeeUsername || flow.get("aiEmployeeUsername");
286
- if (!aiEmployeeUsername) throw new Error("Flow has no AI employee configured");
287
- await runReview(app, {
288
- reviewId: message.reviewId,
289
- flow,
290
- repo,
291
- targetType: message.targetType || review.get("targetType"),
292
- mrIid: message.targetType === "mr" ? message.mrIid ?? Number(review.get("mrIid")) : null,
293
- commitSha: message.targetType === "commit" ? message.commitSha || review.get("commitSha") : null,
294
- branch: message.branch || review.get("branch"),
295
- headSha: message.headSha || review.get("headSha"),
296
- aiEmployeeUsername,
297
- extraInstructions: message.extraInstructions,
298
- userId: message.userId ?? null
299
- });
300
- } catch (err) {
301
- (_g = (_f = app.log) == null ? void 0 : _f.error) == null ? void 0 : _g.call(_f, "git review queue: failed before review execution", err);
302
- await failQueuedReview(app, message.reviewId, err);
303
- }
473
+ await withReviewProcessLock(app, message.reviewId, async () => {
474
+ var _a, _b, _c, _d, _e, _f;
475
+ const db = app.db;
476
+ const reviewsRepo = db.getRepository("gitCodeReviews");
477
+ const review = await reviewsRepo.findOne({ filterByTk: message.reviewId });
478
+ if (!review) {
479
+ (_b = (_a = app.log) == null ? void 0 : _a.warn) == null ? void 0 : _b.call(_a, `git review queue: review ${message.reviewId} not found, skipping`);
480
+ return;
481
+ }
482
+ if (review.get("status") !== "pending") {
483
+ (_d = (_c = app.log) == null ? void 0 : _c.info) == null ? void 0 : _d.call(_c, `git review queue: review ${message.reviewId} is ${review.get("status")}, skipping`);
484
+ return;
485
+ }
486
+ const metadata = getQueuedReviewMetadata(review);
487
+ const targetType = message.targetType || review.get("targetType");
488
+ try {
489
+ const repo = await db.getRepository("gitRepositories").findOne({
490
+ filterByTk: message.repositoryId || review.get("repositoryId")
491
+ });
492
+ if (!repo) throw new Error("Repository not found");
493
+ const flowSnapshot = message.flowSnapshot || metadata.flowSnapshot;
494
+ const storedFlow = await db.getRepository("gitReviewFlows").findOne({
495
+ filterByTk: (flowSnapshot == null ? void 0 : flowSnapshot.id) || review.get("flowId")
496
+ });
497
+ const flow = createFlowFromSnapshot(flowSnapshot, storedFlow);
498
+ const aiEmployeeUsername = message.aiEmployeeUsername || metadata.aiEmployeeUsername || flow.get("aiEmployeeUsername");
499
+ if (!aiEmployeeUsername) throw new Error("Flow has no AI employee configured");
500
+ await runReview(app, {
501
+ reviewId: message.reviewId,
502
+ flow,
503
+ repo,
504
+ targetType,
505
+ mrIid: targetType === "mr" ? message.mrIid ?? toNullableNumber(review.get("mrIid")) : null,
506
+ commitSha: targetType === "commit" ? message.commitSha || review.get("commitSha") : null,
507
+ branch: message.branch || review.get("branch"),
508
+ headSha: message.headSha || review.get("headSha"),
509
+ aiEmployeeUsername,
510
+ extraInstructions: message.extraInstructions ?? metadata.extraInstructions ?? void 0,
511
+ userId: message.userId ?? metadata.userId ?? null
512
+ });
513
+ } catch (err) {
514
+ (_f = (_e = app.log) == null ? void 0 : _e.error) == null ? void 0 : _f.call(_e, "git review queue: failed before review execution", err);
515
+ await failQueuedReview(app, message.reviewId, err);
516
+ }
517
+ });
304
518
  }
305
519
  async function reviewApprovePost(ctx, next) {
306
520
  var _a, _b;
@@ -440,7 +654,8 @@ async function runReview(app, args) {
440
654
  } catch {
441
655
  }
442
656
  }
443
- if (!AIEmployee) throw new Error("AIEmployee class not found \u2014 plugin-ai may not be installed or its exports changed");
657
+ if (!AIEmployee)
658
+ throw new Error("AIEmployee class not found \u2014 plugin-ai may not be installed or its exports changed");
444
659
  const llmService = args.flow.get("llmService");
445
660
  const model = args.flow.get("model");
446
661
  const modelRef = llmService && model ? { llmService, model } : void 0;
@@ -465,7 +680,7 @@ async function runReview(app, args) {
465
680
  ]
466
681
  }),
467
682
  new Promise(
468
- (_, reject) => setTimeout(() => reject(new Error("AI review timed out after 5 minutes")), REVIEW_TIMEOUT_MS)
683
+ (_resolve, reject) => setTimeout(() => reject(new Error("AI review timed out after 5 minutes")), REVIEW_TIMEOUT_MS)
469
684
  )
470
685
  ]);
471
686
  const content = extractLastAiMessageContent(result);
@@ -541,19 +756,29 @@ function buildReviewPrompt(args) {
541
756
  lines.push("");
542
757
  if (args.targetType === "mr") {
543
758
  lines.push(`Target: Merge Request !${args.mrIid}.`);
544
- lines.push(`Use the \`git_get_merge_request\` tool with repositoryId=${args.repo.get("id")} and mrIid=${args.mrIid} to fetch the diff and metadata.`);
759
+ lines.push(
760
+ `Use the \`git_get_merge_request\` tool with repositoryId=${args.repo.get("id")} and mrIid=${args.mrIid} to fetch the diff and metadata.`
761
+ );
545
762
  lines.push("Optionally call `git_get_merge_request_notes` to avoid duplicating prior comments.");
546
763
  } else if (args.targetType === "commit") {
547
764
  lines.push(`Target: Commit ${args.commitSha}.`);
548
- lines.push(`Use the \`git_get_commit\` tool with repositoryId=${args.repo.get("id")} and commitHash=${args.commitSha} to fetch the diff.`);
765
+ lines.push(
766
+ `Use the \`git_get_commit\` tool with repositoryId=${args.repo.get("id")} and commitHash=${args.commitSha} to fetch the diff.`
767
+ );
549
768
  } else {
550
769
  lines.push(`Target: Branch ${args.branch}.`);
551
- lines.push(`Use \`git_list_commits\`, \`git_get_diff\`, and \`git_get_file_content\` (with repositoryId=${args.repo.get("id")}) to inspect recent changes on this branch.`);
770
+ lines.push(
771
+ `Use \`git_list_commits\`, \`git_get_diff\`, and \`git_get_file_content\` (with repositoryId=${args.repo.get(
772
+ "id"
773
+ )}) to inspect recent changes on this branch.`
774
+ );
552
775
  }
553
776
  lines.push("");
554
777
  lines.push("Produce a thorough but concise code review report in Markdown. Required sections:");
555
778
  lines.push("1. **Summary** \u2014 overall assessment.");
556
- lines.push("2. **Findings** \u2014 issues grouped by severity (`Critical`, `High`, `Medium`, `Low`, `Info`). For each finding include the file path, line/range when possible, the problem, and a suggested fix.");
779
+ lines.push(
780
+ "2. **Findings** \u2014 issues grouped by severity (`Critical`, `High`, `Medium`, `Low`, `Info`). For each finding include the file path, line/range when possible, the problem, and a suggested fix."
781
+ );
557
782
  lines.push("3. **Suggestions** \u2014 non-blocking improvements.");
558
783
  lines.push("4. **Verdict** \u2014 one of: `LGTM`, `Approve with comments`, `Request changes`, `Block`.");
559
784
  lines.push("");
@@ -620,7 +845,7 @@ async function fetchMrHeadSha(repo, mrIid) {
620
845
  if (isGitHub) {
621
846
  const { projectPath } = (0, import_gitlab_url.parseGitLabProject)(repoUrl);
622
847
  const response = await fetch(`https://api.github.com/repos/${projectPath}/pulls/${mrIid}`, {
623
- headers: { "Authorization": `Bearer ${pat}`, Accept: "application/vnd.github.v3+json" }
848
+ headers: { Authorization: `Bearer ${pat}`, Accept: "application/vnd.github.v3+json" }
624
849
  });
625
850
  if (!response.ok) return null;
626
851
  const data = await response.json();
@@ -648,9 +873,9 @@ async function postNoteToGitLab(repo, mrIid, body) {
648
873
  const response = await fetch(`https://api.github.com/repos/${projectPath}/issues/${mrIid}/comments`, {
649
874
  method: "POST",
650
875
  headers: {
651
- "Authorization": `Bearer ${pat}`,
876
+ Authorization: `Bearer ${pat}`,
652
877
  "Content-Type": "application/json",
653
- "Accept": "application/vnd.github.v3+json"
878
+ Accept: "application/vnd.github.v3+json"
654
879
  },
655
880
  body: JSON.stringify({ body })
656
881
  });
@@ -668,7 +893,7 @@ async function postNoteToGitLab(repo, mrIid, body) {
668
893
  headers: {
669
894
  "PRIVATE-TOKEN": pat,
670
895
  "Content-Type": "application/json",
671
- "Accept": "application/json"
896
+ Accept: "application/json"
672
897
  },
673
898
  body: JSON.stringify({ body })
674
899
  });
@@ -703,7 +928,9 @@ function warnInvalidBranchFilter(filter, reason) {
703
928
  if (loggedBadFilters.has(filter)) return;
704
929
  loggedBadFilters.add(filter);
705
930
  console.warn(
706
- `[plugin-git-manager] branchFilter rejected (${reason}): ${JSON.stringify(filter)}. Flow will not match any branch.`
931
+ `[plugin-git-manager] branchFilter rejected (${reason}): ${JSON.stringify(
932
+ filter
933
+ )}. Flow will not match any branch.`
707
934
  );
708
935
  }
709
936
  function branchMatches(flow, branch) {
@@ -1,12 +1,3 @@
1
- /**
2
- * This file is part of the NocoBase (R) project.
3
- * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
- * Authors: NocoBase Team.
5
- *
6
- * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
- * For more information, please refer to: https://www.nocobase.com/agreement.
8
- */
9
-
10
1
  var __create = Object.create;
11
2
  var __defProp = Object.defineProperty;
12
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -1,12 +1,3 @@
1
- /**
2
- * This file is part of the NocoBase (R) project.
3
- * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
- * Authors: NocoBase Team.
5
- *
6
- * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
- * For more information, please refer to: https://www.nocobase.com/agreement.
8
- */
9
-
10
1
  var __defProp = Object.defineProperty;
11
2
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
12
3
  var __getOwnPropNames = Object.getOwnPropertyNames;
@@ -1,12 +1,3 @@
1
- /**
2
- * This file is part of the NocoBase (R) project.
3
- * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
- * Authors: NocoBase Team.
5
- *
6
- * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
- * For more information, please refer to: https://www.nocobase.com/agreement.
8
- */
9
-
10
1
  var __defProp = Object.defineProperty;
11
2
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
12
3
  var __getOwnPropNames = Object.getOwnPropertyNames;
@@ -1,12 +1,3 @@
1
- /**
2
- * This file is part of the NocoBase (R) project.
3
- * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
- * Authors: NocoBase Team.
5
- *
6
- * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
- * For more information, please refer to: https://www.nocobase.com/agreement.
8
- */
9
-
10
1
  var __defProp = Object.defineProperty;
11
2
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
12
3
  var __getOwnPropNames = Object.getOwnPropertyNames;
@@ -1,12 +1,3 @@
1
- /**
2
- * This file is part of the NocoBase (R) project.
3
- * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
- * Authors: NocoBase Team.
5
- *
6
- * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
- * For more information, please refer to: https://www.nocobase.com/agreement.
8
- */
9
-
10
1
  var __create = Object.create;
11
2
  var __defProp = Object.defineProperty;
12
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -1,12 +1,3 @@
1
- /**
2
- * This file is part of the NocoBase (R) project.
3
- * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
- * Authors: NocoBase Team.
5
- *
6
- * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
- * For more information, please refer to: https://www.nocobase.com/agreement.
8
- */
9
-
10
1
  var __defProp = Object.defineProperty;
11
2
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
12
3
  var __getOwnPropNames = Object.getOwnPropertyNames;
@@ -1,12 +1,3 @@
1
- /**
2
- * This file is part of the NocoBase (R) project.
3
- * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
- * Authors: NocoBase Team.
5
- *
6
- * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
- * For more information, please refer to: https://www.nocobase.com/agreement.
8
- */
9
-
10
1
  var __create = Object.create;
11
2
  var __defProp = Object.defineProperty;
12
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -1,12 +1,3 @@
1
- /**
2
- * This file is part of the NocoBase (R) project.
3
- * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
- * Authors: NocoBase Team.
5
- *
6
- * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
- * For more information, please refer to: https://www.nocobase.com/agreement.
8
- */
9
-
10
1
  var __defProp = Object.defineProperty;
11
2
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
12
3
  var __getOwnPropNames = Object.getOwnPropertyNames;
@@ -1,12 +1,3 @@
1
- /**
2
- * This file is part of the NocoBase (R) project.
3
- * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
- * Authors: NocoBase Team.
5
- *
6
- * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
- * For more information, please refer to: https://www.nocobase.com/agreement.
8
- */
9
-
10
1
  var __defProp = Object.defineProperty;
11
2
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
12
3
  var __getOwnPropNames = Object.getOwnPropertyNames;
@@ -1,12 +1,3 @@
1
- /**
2
- * This file is part of the NocoBase (R) project.
3
- * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
- * Authors: NocoBase Team.
5
- *
6
- * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
- * For more information, please refer to: https://www.nocobase.com/agreement.
8
- */
9
-
10
1
  var __defProp = Object.defineProperty;
11
2
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
12
3
  var __getOwnPropNames = Object.getOwnPropertyNames;
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "displayName": "Git Manager",
4
4
  "displayName.zh-CN": "Git 管理器",
5
5
  "description": "Manage Git repositories with PAT authentication - pull, push, fetch, diff, file browsing",
6
- "version": "1.1.12",
6
+ "version": "1.2.1",
7
7
  "license": "Apache-2.0",
8
8
  "main": "dist/server/index.js",
9
9
  "files": [
@@ -34,4 +34,4 @@
34
34
  "dependencies": {
35
35
  "simple-git": "^3.27.0"
36
36
  }
37
- }
37
+ }