@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.
- package/README.md +2 -1
- package/dist/{chunk-R2D6JZ6H.js → chunk-4LUNMJTB.js} +353 -52
- package/dist/chunk-4LUNMJTB.js.map +1 -0
- package/dist/{chunk-VL3ONHTJ.js → chunk-7ZLJEU2E.js} +201 -195
- package/dist/chunk-7ZLJEU2E.js.map +1 -0
- package/dist/{chunk-HT2AZIFG.js → chunk-Q3ZIYY54.js} +6 -6
- package/dist/cli-entry.js +3 -3
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +3 -3
- package/dist/index.d.ts +14 -4
- package/dist/index.js +3 -3
- package/dist/mcpServer.d.ts +2 -2
- package/dist/mcpServer.js +1 -1
- package/dist/{runtime-CPS9xtHk.d.ts → runtime-B0PyJ-YT.d.ts} +2 -1
- package/dist/web/assets/{element-plus-CTNf5dQ0.js → element-plus-C8u1uXZM.js} +2 -2
- package/dist/web/assets/index-BUkraY9q.js +344 -0
- package/dist/web/assets/{index-D_T0fvkc.css → index-CcBjvlvI.css} +1 -1
- package/dist/web/assets/vue-ICXx-m1J.js +30 -0
- package/dist/web/index.html +4 -4
- package/dist/webServer.d.ts +1 -1
- package/dist/webServer.js +2 -2
- package/package.json +2 -2
- package/dist/chunk-R2D6JZ6H.js.map +0 -1
- package/dist/chunk-VL3ONHTJ.js.map +0 -1
- package/dist/web/assets/index-phqW9_ys.js +0 -344
- package/dist/web/assets/vue-BLng4iTN.js +0 -30
- /package/dist/{chunk-HT2AZIFG.js.map → chunk-Q3ZIYY54.js.map} +0 -0
|
@@ -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
|
-
|
|
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))
|
|
121
|
-
|
|
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 =
|
|
491
|
+
const jobs = runtime.jobs;
|
|
637
492
|
app.get("/api/health", async () => ({
|
|
638
493
|
ok: true,
|
|
639
494
|
service: "git-cockpit",
|
|
640
|
-
version
|
|
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(
|
|
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-
|
|
1179
|
+
//# sourceMappingURL=chunk-7ZLJEU2E.js.map
|