@shaohui_jin/git-cockpit-mcp-server 0.1.13 → 0.1.15

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.
@@ -3,9 +3,11 @@ import {
3
3
  McpHttpHandler,
4
4
  TOOL_DEFS,
5
5
  TOOL_DEF_MAP,
6
+ collectRepoOverviews,
6
7
  executeTool,
7
- toolSummaries
8
- } from "./chunk-R2D6JZ6H.js";
8
+ toolSummaries,
9
+ version
10
+ } from "./chunk-4LUNMJTB.js";
9
11
 
10
12
  // src/webServer.ts
11
13
  import * as path3 from "path";
@@ -19,6 +21,7 @@ import {
19
21
  BackupManager,
20
22
  PermissionManager as PermissionManager2,
21
23
  detectMrPlatform,
24
+ enrichPrepareMr,
22
25
  findMrHost,
23
26
  hostnameOf,
24
27
  methodForRepo,
@@ -32,14 +35,15 @@ import {
32
35
  toHttpsRemoteUrl,
33
36
  upsertMrHost,
34
37
  maskToken,
35
- validateMrToken,
36
- JobStore as JobStore2
38
+ validateMrToken
37
39
  } from "@shaohui_jin/git-cockpit-core";
38
40
 
39
41
  // src/runtime.ts
40
42
  import { EventEmitter as EventEmitter2 } from "events";
41
43
  import {
42
44
  AuditLogger,
45
+ JobEngine,
46
+ JobStore,
43
47
  PermissionManager,
44
48
  RepoStore as RepoStore2,
45
49
  openDatabase,
@@ -117,8 +121,11 @@ var ConfigStore = class {
117
121
  const out = {};
118
122
  for (const [k, val] of Object.entries(v)) {
119
123
  const lower = k.toLowerCase();
120
- if (/password|token|secret|authorization/i.test(lower)) out[k] = "[REDACTED]";
121
- else out[k] = redact(val);
124
+ if (/password|token|secret|authorization/i.test(lower)) {
125
+ out[k] = typeof val === "string" && val.length > 0 ? "[REDACTED]" : val;
126
+ } else {
127
+ out[k] = redact(val);
128
+ }
122
129
  }
123
130
  return out;
124
131
  }
@@ -277,6 +284,16 @@ function createRuntime(options = {}) {
277
284
  const permissions = new PermissionManager(config);
278
285
  const repoStore = new RepoStore2(db);
279
286
  const repoManager = new RepoManager({ repoStore, eventBus, getConfig: () => configStore.get() });
287
+ const jobs = new JobEngine(eventBus, new JobStore(db), {
288
+ resolveGit: async (repoPath) => {
289
+ try {
290
+ return repoManager.getByPath(repoPath).service;
291
+ } catch {
292
+ const handle = await repoManager.open(repoPath);
293
+ return handle.service;
294
+ }
295
+ }
296
+ });
280
297
  return {
281
298
  configStore,
282
299
  config,
@@ -285,6 +302,7 @@ function createRuntime(options = {}) {
285
302
  permissions,
286
303
  repoStore,
287
304
  repoManager,
305
+ jobs,
288
306
  eventBus
289
307
  };
290
308
  }
@@ -304,14 +322,11 @@ function disposeRuntime(runtime) {
304
322
  import swagger from "@fastify/swagger";
305
323
  import swaggerUi from "@fastify/swagger-ui";
306
324
  import { zodToJsonSchema } from "zod-to-json-schema";
307
-
308
- // package.json
309
- var version = "0.1.13";
310
-
311
- // src/openapi.ts
312
325
  var REST_META = {
313
326
  "get /api/health": { summary: "\u63A2\u6D3B", tags: ["\u7CFB\u7EDF"] },
314
327
  "get /api/repos": { summary: "\u5DF2\u6253\u5F00\u4ED3\u5E93\u5217\u8868", tags: ["\u4ED3\u5E93"] },
328
+ "get /api/repos/overview": { summary: "\u5DF2\u6253\u5F00\u4ED3\u5E93\u8109\u640F\uFF08\u5DE5\u4F5C\u53F0\uFF09", tags: ["\u4ED3\u5E93"] },
329
+ "post /api/jobs": { summary: "\u63D0\u4EA4\u540E\u53F0\u4EFB\u52A1\uFF08clone / survey / fetch\uFF09", tags: ["\u4ED3\u5E93"] },
315
330
  "post /api/repos/open": { summary: "\u6253\u5F00\u672C\u5730\u4ED3\u5E93", tags: ["\u4ED3\u5E93"] },
316
331
  "delete /api/repos/{id}": { summary: "\u5173\u95ED\u5E76\u79FB\u9664\u4ED3\u5E93", tags: ["\u4ED3\u5E93"] },
317
332
  "post /api/repos/{id}/activate": { summary: "\u6FC0\u6D3B\u4ED3\u5E93\uFF08\u7F6E\u9876\uFF09", tags: ["\u4ED3\u5E93"] },
@@ -326,10 +341,18 @@ var REST_META = {
326
341
  "get /api/repos/{id}/branch-graph": { summary: "\u5206\u652F tip DAG\uFF08\u72B6\u6001\u9875 G6\uFF09", tags: ["\u53EA\u8BFB"] },
327
342
  "get /api/repos/{id}/file": { summary: "\u8BFB\u53D6\u67D0\u63D0\u4EA4\u4E2D\u7684\u6587\u4EF6", tags: ["\u53EA\u8BFB"] },
328
343
  "get /api/repos/{id}/stashes": { summary: "stash \u5217\u8868", tags: ["\u53EA\u8BFB"] },
344
+ "get /api/repos/{id}/workspace-conflicts": { summary: "\u5DE5\u4F5C\u533A merge/rebase \u51B2\u7A81\uFF08index \u4E09\u9636\u6BB5\uFF09", tags: ["\u53EA\u8BFB"] },
345
+ "get /api/repos/{id}/merge/preview": { summary: "merge-tree \u9884\u6F14\uFF08\u4E0D\u8FDB\u5BA1\u8BA1\uFF09", tags: ["\u53EA\u8BFB"] },
346
+ "get /api/repos/{id}/merge/rehearse": { summary: "\u9884\u6F14 + \u51B2\u7A81\u6B63\u6587\uFF08\u4E0D\u8FDB\u5BA1\u8BA1\uFF09", tags: ["\u53EA\u8BFB"] },
347
+ "get /api/repos/{id}/merge/blame": { summary: "\u51B2\u7A81\u6587\u4EF6\u4E24\u4FA7 blame", tags: ["\u53EA\u8BFB"] },
348
+ "get /api/repos/{id}/merge/survey": { summary: "\u5408\u5E76\u77E9\u9635\u6279\u91CF\u9884\u6F14", tags: ["\u53EA\u8BFB"] },
349
+ "get /api/repos/{id}/merge/order": { summary: "\u5EFA\u8BAE\u5408\u5165\u987A\u5E8F", tags: ["\u53EA\u8BFB"] },
350
+ "get /api/repos/{id}/mr/prepare": { summary: "\u5F00 PR/MR \u524D\u53EA\u8BFB\u89E3\u6790", tags: ["\u53EA\u8BFB"] },
329
351
  "get /api/repos/{id}/backups": { summary: "\u9AD8\u5371\u64CD\u4F5C\u5907\u4EFD\u5206\u652F / stash", tags: ["\u53EA\u8BFB"] },
330
352
  "get /api/repos/{id}/reflog": { summary: "reflog", tags: ["\u53EA\u8BFB"] },
331
353
  "get /api/jobs": { summary: "\u540E\u53F0\u4EFB\u52A1\u5217\u8868\uFF08\u514B\u9686\u7B49\uFF09", tags: ["\u4ED3\u5E93"] },
332
354
  "get /api/jobs/{id}": { summary: "\u540E\u53F0\u4EFB\u52A1\u8BE6\u60C5\u4E0E\u65E5\u5FD7", tags: ["\u4ED3\u5E93"] },
355
+ "post /api/jobs/{id}/cancel": { summary: "\u53D6\u6D88\u8FDB\u884C\u4E2D\u7684\u540E\u53F0\u4EFB\u52A1", tags: ["\u4ED3\u5E93"] },
333
356
  "post /api/jobs/clone": { summary: "\u540E\u53F0\u514B\u9686\u8FDC\u7A0B\u4ED3\u5E93", tags: ["\u4ED3\u5E93"] },
334
357
  "get /api/tools": { summary: "\u5DE5\u5177\u6CE8\u518C\u8868\uFF08\u542B\u98CE\u9669\u4E0E\u662F\u5426\u542F\u7528\uFF09", tags: ["\u7CFB\u7EDF"] },
335
358
  "get /api/logs": { summary: "\u64CD\u4F5C\u5BA1\u8BA1\u65E5\u5FD7", tags: ["\u7CFB\u7EDF"] },
@@ -421,184 +444,6 @@ async function registerApiDocs(app) {
421
444
  });
422
445
  }
423
446
 
424
- // src/jobs.ts
425
- import { randomUUID } from "crypto";
426
- import { assertCloneDest, assertSafeCloneUrl, spawnClone } from "@shaohui_jin/git-cockpit-core";
427
- var MAX_JOBS = 30;
428
- var MAX_LOG_LINES = 800;
429
- var INTERRUPT_MESSAGE = "\u670D\u52A1\u91CD\u542F\uFF0C\u4EFB\u52A1\u4E2D\u65AD";
430
- function splitLines(text) {
431
- return text.replace(/\r\n/g, "\n").replace(/\r/g, "\n").split("\n");
432
- }
433
- function appendPendingChunk(buf, jobId, chunk) {
434
- if (!chunk) return;
435
- buf.set(jobId, (buf.get(jobId) ?? "") + chunk);
436
- }
437
- function takePendingChunk(buf, jobId) {
438
- const text = buf.get(jobId) ?? "";
439
- buf.delete(jobId);
440
- return text.length ? text : void 0;
441
- }
442
- var JobManager = class {
443
- constructor(eventBus, store) {
444
- this.eventBus = eventBus;
445
- this.store = store;
446
- this.restore();
447
- }
448
- eventBus;
449
- store;
450
- jobs = /* @__PURE__ */ new Map();
451
- lastEmit = 0;
452
- pending = null;
453
- flushTimer = null;
454
- pendingChunks = /* @__PURE__ */ new Map();
455
- list() {
456
- return [...this.jobs.values()].sort((a, b) => a.startedAt < b.startedAt ? 1 : -1);
457
- }
458
- get(id) {
459
- return this.jobs.get(id);
460
- }
461
- summary(job) {
462
- return {
463
- id: job.id,
464
- kind: job.kind,
465
- status: job.status,
466
- url: job.url,
467
- destDir: job.destDir,
468
- error: job.error,
469
- startedAt: job.startedAt,
470
- finishedAt: job.finishedAt,
471
- repoId: job.repoId,
472
- logCount: job.logs.length,
473
- tail: job.logs.slice(-3).join("\n")
474
- };
475
- }
476
- startClone(opts) {
477
- const url = assertSafeCloneUrl(opts.url);
478
- const destDir = assertCloneDest(opts.destDir, opts.allowedRepos);
479
- const running = this.list().find((j) => j.status === "running" && j.destDir === destDir);
480
- if (running) {
481
- throw new Error(`\u5DF2\u6709\u514B\u9686\u4EFB\u52A1\u6B63\u5728\u5199\u5165 ${destDir}`);
482
- }
483
- const job = {
484
- id: `clone-${randomUUID()}`,
485
- kind: "clone",
486
- status: "running",
487
- url,
488
- destDir,
489
- logs: [`$ git clone --progress -- ${url} ${destDir}`],
490
- startedAt: (/* @__PURE__ */ new Date()).toISOString()
491
- };
492
- this.jobs.set(job.id, job);
493
- this.persist(job);
494
- this.prune();
495
- this.emit(job);
496
- void this.runClone(job, opts.onSuccess);
497
- return job;
498
- }
499
- restore() {
500
- const saved = this.store.list();
501
- for (const job of saved) {
502
- if (job.status === "running") {
503
- job.status = "error";
504
- job.error = INTERRUPT_MESSAGE;
505
- job.finishedAt = (/* @__PURE__ */ new Date()).toISOString();
506
- job.logs.push(INTERRUPT_MESSAGE);
507
- while (job.logs.length > MAX_LOG_LINES) job.logs.shift();
508
- this.persist(job);
509
- }
510
- this.jobs.set(job.id, job);
511
- }
512
- this.prune();
513
- }
514
- persist(job) {
515
- try {
516
- this.store.upsert(job);
517
- } catch {
518
- }
519
- }
520
- remove(id) {
521
- this.jobs.delete(id);
522
- try {
523
- this.store.remove(id);
524
- } catch {
525
- }
526
- }
527
- async runClone(job, onSuccess) {
528
- try {
529
- await spawnClone(job.url, job.destDir, (chunk) => this.append(job, chunk));
530
- if (onSuccess) {
531
- const repoId = await onSuccess(job.destDir);
532
- if (typeof repoId === "number") job.repoId = repoId;
533
- }
534
- job.status = "ok";
535
- this.append(job, "\n\u514B\u9686\u5B8C\u6210\n");
536
- } catch (err) {
537
- job.status = "error";
538
- job.error = err instanceof Error ? err.message : String(err);
539
- this.append(job, `
540
- \u5931\u8D25: ${job.error}
541
- `);
542
- } finally {
543
- job.finishedAt = (/* @__PURE__ */ new Date()).toISOString();
544
- this.emit(job, true);
545
- }
546
- }
547
- append(job, chunk) {
548
- const lines = splitLines(chunk);
549
- if (!lines.length) return;
550
- const last = job.logs[job.logs.length - 1] ?? "";
551
- if (lines[0] !== void 0 && job.logs.length && !last.endsWith("\n") && chunk[0] !== "\n") {
552
- job.logs[job.logs.length - 1] = last + lines[0];
553
- job.logs.push(...lines.slice(1));
554
- } else {
555
- job.logs.push(...lines);
556
- }
557
- while (job.logs.length > MAX_LOG_LINES) job.logs.shift();
558
- this.emit(job, false, chunk);
559
- }
560
- emit(job, force = false, chunk) {
561
- appendPendingChunk(this.pendingChunks, job.id, chunk);
562
- const now = Date.now();
563
- if (!force && now - this.lastEmit < 200) {
564
- this.pending = job;
565
- this.flushTimer ??= setTimeout(() => {
566
- this.flushTimer = null;
567
- if (this.pending) this.emit(this.pending, true);
568
- }, 200);
569
- return;
570
- }
571
- this.lastEmit = now;
572
- this.pending = null;
573
- if (this.flushTimer) {
574
- clearTimeout(this.flushTimer);
575
- this.flushTimer = null;
576
- }
577
- this.persist(job);
578
- const payload = {
579
- id: job.id,
580
- kind: job.kind,
581
- status: job.status,
582
- url: job.url,
583
- destDir: job.destDir,
584
- chunk: takePendingChunk(this.pendingChunks, job.id),
585
- error: job.error,
586
- startedAt: job.startedAt,
587
- finishedAt: job.finishedAt,
588
- repoId: job.repoId,
589
- logCount: job.logs.length
590
- };
591
- this.eventBus.emit("job-progress", payload);
592
- }
593
- prune() {
594
- const all = this.list();
595
- if (all.length <= MAX_JOBS) return;
596
- for (const j of all.slice(MAX_JOBS)) {
597
- if (j.status !== "running") this.remove(j.id);
598
- }
599
- }
600
- };
601
-
602
447
  // src/webServer.ts
603
448
  function resolveWebDist() {
604
449
  const here = path3.resolve(path3.dirname(fileURLToPath(import.meta.url)));
@@ -620,6 +465,16 @@ function resolveWebDist() {
620
465
  }
621
466
  return null;
622
467
  }
468
+ function queryFlag(v) {
469
+ if (v === void 0 || v === "") return void 0;
470
+ return v === "1" || v === "true";
471
+ }
472
+ function queryList(q, key) {
473
+ const v = q[key];
474
+ if (v == null || v === "") return [];
475
+ const parts = Array.isArray(v) ? v : [v];
476
+ return parts.flatMap((s) => String(s).split(",")).map((s) => s.trim()).filter(Boolean);
477
+ }
623
478
  async function createWebServer(runtime, options = {}) {
624
479
  const app = Fastify({ logger: false, bodyLimit: 2 * 1024 * 1024 });
625
480
  await app.register(cors, {
@@ -633,11 +488,11 @@ async function createWebServer(runtime, options = {}) {
633
488
  await app.register(fastifyStatic, { root: staticDir, prefix: "/" });
634
489
  }
635
490
  const mcpHttp = new McpHttpHandler(runtime);
636
- const jobs = new JobManager(runtime.eventBus, new JobStore2(runtime.db));
491
+ const jobs = runtime.jobs;
637
492
  app.get("/api/health", async () => ({
638
493
  ok: true,
639
494
  service: "git-cockpit",
640
- version: "0.1.6",
495
+ version,
641
496
  uptimeMs: process.uptime() * 1e3
642
497
  }));
643
498
  app.get("/api/jobs", async () => ({
@@ -646,7 +501,17 @@ async function createWebServer(runtime, options = {}) {
646
501
  app.get("/api/jobs/:id", async (req, reply) => {
647
502
  const job = jobs.get(req.params.id);
648
503
  if (!job) return reply.code(404).send({ error: "\u4EFB\u52A1\u4E0D\u5B58\u5728" });
649
- return { job };
504
+ return { job: jobs.detail(job) };
505
+ });
506
+ app.post("/api/jobs/:id/cancel", async (req, reply) => {
507
+ try {
508
+ const job = jobs.cancel(req.params.id);
509
+ return { job: jobs.summary(job) };
510
+ } catch (err) {
511
+ const msg = err instanceof Error ? err.message : String(err);
512
+ const code = msg === "\u4EFB\u52A1\u4E0D\u5B58\u5728" ? 404 : 400;
513
+ return reply.code(code).send({ error: msg });
514
+ }
650
515
  });
651
516
  app.post("/api/jobs/clone", async (req, reply) => {
652
517
  const url = req.body?.url?.trim();
@@ -669,6 +534,56 @@ async function createWebServer(runtime, options = {}) {
669
534
  return reply.code(400).send({ error: toError(err) });
670
535
  }
671
536
  });
537
+ app.post("/api/jobs", async (req, reply) => {
538
+ const kind = req.body?.kind?.trim();
539
+ const payload = req.body?.payload ?? {};
540
+ try {
541
+ if (kind === "clone") {
542
+ const job = jobs.startClone({
543
+ url: String(payload.url ?? ""),
544
+ destDir: String(payload.destDir ?? ""),
545
+ allowedRepos: runtime.configStore.get().git.allowedRepos,
546
+ onSuccess: async (dest) => {
547
+ const handle = await runtime.repoManager.open(dest);
548
+ return handle.record.id;
549
+ }
550
+ });
551
+ return { job: jobs.summary(job) };
552
+ }
553
+ if (kind === "survey" || kind === "fetch") {
554
+ let repoPath = typeof req.body?.repoPath === "string" ? req.body.repoPath.trim() : "";
555
+ if (!repoPath && req.body?.repoId != null) {
556
+ const handle2 = await runtime.repoManager.getById(Number(req.body.repoId));
557
+ repoPath = handle2?.service.repoPath ?? "";
558
+ }
559
+ if (!repoPath) {
560
+ const current = await runtime.repoManager.getCurrent();
561
+ repoPath = current?.service.repoPath ?? "";
562
+ }
563
+ if (!repoPath) return reply.code(400).send({ error: "survey/fetch \u9700\u8981\u4ED3\u5E93" });
564
+ const handle = await runtime.repoManager.open(repoPath);
565
+ const job = kind === "survey" ? jobs.startSurvey({
566
+ repoPath: handle.service.repoPath,
567
+ intos: payload.intos ?? [],
568
+ froms: payload.froms ?? [],
569
+ fetch: payload.fetch,
570
+ remote: payload.remote,
571
+ git: handle.service
572
+ }) : jobs.startFetch({
573
+ repoPath: handle.service.repoPath,
574
+ remote: payload.remote,
575
+ git: handle.service
576
+ });
577
+ return { job: jobs.summary(job) };
578
+ }
579
+ return reply.code(400).send({ error: "\u4E0D\u652F\u6301\u7684 kind\uFF0C\u4F7F\u7528 clone / survey / fetch" });
580
+ } catch (err) {
581
+ return reply.code(400).send({ error: toError(err) });
582
+ }
583
+ });
584
+ app.get("/api/repos/overview", async () => ({
585
+ repos: await collectRepoOverviews(runtime)
586
+ }));
672
587
  app.get("/api/repos", async () => ({
673
588
  repos: runtime.repoManager.list()
674
589
  }));
@@ -793,7 +708,11 @@ async function createWebServer(runtime, options = {}) {
793
708
  async (req, reply) => withRepo(
794
709
  req,
795
710
  reply,
796
- async ({ service }) => service.getBranchGraph(req.query.maxNodes ? Number(req.query.maxNodes) : 200)
711
+ async ({ service }) => service.getBranchGraph({
712
+ maxNodes: req.query.maxNodes ? Number(req.query.maxNodes) : 200,
713
+ into: req.query.into,
714
+ from: req.query.from
715
+ })
797
716
  )
798
717
  );
799
718
  app.get(
@@ -817,6 +736,94 @@ async function createWebServer(runtime, options = {}) {
817
736
  "/api/repos/:id/stashes",
818
737
  async (req, reply) => withRepo(req, reply, async ({ service }) => service.listStashes())
819
738
  );
739
+ app.get(
740
+ "/api/repos/:id/workspace-conflicts",
741
+ async (req, reply) => withRepo(req, reply, async ({ service }) => service.listWorkspaceConflicts())
742
+ );
743
+ app.get(
744
+ "/api/repos/:id/merge/preview",
745
+ async (req, reply) => withRepo(
746
+ req,
747
+ reply,
748
+ async ({ service }) => service.previewMerge({
749
+ into: req.query.into ?? "",
750
+ from: req.query.from ?? "",
751
+ fetch: queryFlag(req.query.fetch),
752
+ remote: req.query.remote,
753
+ path: req.query.path
754
+ })
755
+ )
756
+ );
757
+ app.get(
758
+ "/api/repos/:id/merge/rehearse",
759
+ async (req, reply) => withRepo(
760
+ req,
761
+ reply,
762
+ async ({ service }) => service.rehearseMerge({
763
+ into: req.query.into ?? "",
764
+ from: req.query.from ?? "",
765
+ fetch: queryFlag(req.query.fetch),
766
+ remote: req.query.remote,
767
+ path: req.query.path,
768
+ maxFiles: req.query.maxFiles ? Number(req.query.maxFiles) : void 0
769
+ })
770
+ )
771
+ );
772
+ app.get(
773
+ "/api/repos/:id/merge/blame",
774
+ async (req, reply) => withRepo(req, reply, async ({ service }) => {
775
+ if (!req.query.into || !req.query.from || !req.query.path) {
776
+ throw new GitOperationError("\u9700\u8981 into\u3001from \u4E0E path", "INVALID_REF");
777
+ }
778
+ return service.blameConflictFile({
779
+ into: req.query.into,
780
+ from: req.query.from,
781
+ path: req.query.path,
782
+ fetch: queryFlag(req.query.fetch),
783
+ remote: req.query.remote
784
+ });
785
+ })
786
+ );
787
+ app.get(
788
+ "/api/repos/:id/merge/survey",
789
+ async (req, reply) => withRepo(
790
+ req,
791
+ reply,
792
+ async ({ service }) => service.surveyMerges({
793
+ intos: queryList(req.query, "intos"),
794
+ froms: queryList(req.query, "froms"),
795
+ fetch: queryFlag(typeof req.query.fetch === "string" ? req.query.fetch : void 0),
796
+ remote: typeof req.query.remote === "string" ? req.query.remote : void 0
797
+ })
798
+ )
799
+ );
800
+ app.get(
801
+ "/api/repos/:id/merge/order",
802
+ async (req, reply) => withRepo(req, reply, async ({ service }) => {
803
+ const branches = queryList(req.query, "branches");
804
+ return service.suggestMergeOrder({
805
+ into: typeof req.query.into === "string" ? req.query.into : "",
806
+ branches,
807
+ fetch: queryFlag(typeof req.query.fetch === "string" ? req.query.fetch : void 0),
808
+ remote: typeof req.query.remote === "string" ? req.query.remote : void 0
809
+ });
810
+ })
811
+ );
812
+ app.get(
813
+ "/api/repos/:id/mr/prepare",
814
+ async (req, reply) => withRepo(req, reply, async ({ service }) => {
815
+ if (!req.query.into || !req.query.from) {
816
+ throw new GitOperationError("\u9700\u8981 into \u4E0E from", "INVALID_REF");
817
+ }
818
+ const prep = await service.prepareMr({
819
+ into: req.query.into,
820
+ from: req.query.from,
821
+ remote: req.query.remote?.trim() || void 0,
822
+ sourceBranch: req.query.sourceBranch
823
+ });
824
+ return enrichPrepareMr({ prep, mr: runtime.config.mr, cwd: service.repoPath });
825
+ })
826
+ );
820
827
  app.post(
821
828
  "/api/repos/:id/tools/:tool",
822
829
  { schema: { hide: true } },
@@ -1167,7 +1174,6 @@ export {
1167
1174
  RepoManager,
1168
1175
  createRuntime,
1169
1176
  disposeRuntime,
1170
- version,
1171
1177
  createWebServer
1172
1178
  };
1173
- //# sourceMappingURL=chunk-VL3ONHTJ.js.map
1179
+ //# sourceMappingURL=chunk-7ZLJEU2E.js.map