@shaohui_jin/git-cockpit-mcp-server 0.1.27 → 0.1.29
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/dist/{chunk-3ALI2CBW.js → chunk-DGQHHNPC.js} +3 -3
- package/dist/{chunk-G6SEOLMU.js → chunk-ML64BPIL.js} +246 -25
- package/dist/chunk-ML64BPIL.js.map +1 -0
- package/dist/{chunk-HWO2V3M5.js → chunk-WT4GTWHD.js} +2 -2
- package/dist/{chunk-HWO2V3M5.js.map → chunk-WT4GTWHD.js.map} +1 -1
- 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 +3 -3
- package/dist/index.js +3 -3
- package/dist/{mcpServer-5C8WQYy6.d.ts → mcpServer-D_ee0o_0.d.ts} +1 -1
- package/dist/mcpServer.d.ts +2 -2
- package/dist/mcpServer.js +1 -1
- package/dist/{runtime-BHX-b-Hx.d.ts → runtime-jfih-vGV.d.ts} +2 -1
- package/dist/web/assets/{abnfDiagram-O67JEVCF-Cpmc29Vo.js → abnfDiagram-O67JEVCF-BvLOOVMp.js} +1 -1
- package/dist/web/assets/{arc-C4CdJ3cz.js → arc-BTJdMR9U.js} +1 -1
- package/dist/web/assets/{architectureDiagram-NJMV4G6O-D-3EH44b.js → architectureDiagram-NJMV4G6O-Cuu0BD8t.js} +1 -1
- package/dist/web/assets/{blockDiagram-BEXU5L5S-4o8DaZHq.js → blockDiagram-BEXU5L5S-jSaqNPDC.js} +1 -1
- package/dist/web/assets/{c4Diagram-YGBWAQC7-DLufKbff.js → c4Diagram-YGBWAQC7-0PABaygh.js} +1 -1
- package/dist/web/assets/channel-CH0mBqDy.js +1 -0
- package/dist/web/assets/{chunk-2Q5K7J3B-dEtvq-Sm.js → chunk-2Q5K7J3B-Bx3ShJLs.js} +1 -1
- package/dist/web/assets/{chunk-3FUC2YCW-D8IY6i0n.js → chunk-3FUC2YCW-npJuWQgM.js} +2 -2
- package/dist/web/assets/{chunk-5VM5RSS4-DTtnT10M.js → chunk-5VM5RSS4-sUx0MLUK.js} +1 -1
- package/dist/web/assets/{chunk-GTNCS2PH-CRKiRt85.js → chunk-GTNCS2PH-BO6MsgyZ.js} +1 -1
- package/dist/web/assets/{chunk-GWA4HPMP-CapkHNd2.js → chunk-GWA4HPMP-CS_7AIEI.js} +1 -1
- package/dist/web/assets/{chunk-JWPE2WC7-D1qG9232.js → chunk-JWPE2WC7-BIEqnMSy.js} +1 -1
- package/dist/web/assets/{chunk-NETBCI7D-Cf5bzyqy.js → chunk-NETBCI7D-DWDPVhzE.js} +1 -1
- package/dist/web/assets/{chunk-WEXAMYUT-aMK135IE.js → chunk-WEXAMYUT-CZmF6ztf.js} +1 -1
- package/dist/web/assets/{chunk-XXDRQBXY-DKObcU_j.js → chunk-XXDRQBXY-C7ux97rA.js} +1 -1
- package/dist/web/assets/{classDiagram-v2-NBCMYWYE-BFKjdANY.js → classDiagram-v2-NBCMYWYE-DMFHgo6y.js} +1 -1
- package/dist/web/assets/{cose-bilkent-JH36ORCC-Bbl702qf.js → cose-bilkent-JH36ORCC-CHcf0ChD.js} +1 -1
- package/dist/web/assets/{cynefin-OW5HDTMX-BwkqOigD.js → cynefin-OW5HDTMX-BVOPFxoX.js} +1 -1
- package/dist/web/assets/{cynefinDiagram-VND7K2PF-C032B141.js → cynefinDiagram-VND7K2PF-D3MWGh5_.js} +1 -1
- package/dist/web/assets/{dagre-6A5THRUB-mtU2etOs.js → dagre-6A5THRUB-BBXhvs_s.js} +1 -1
- package/dist/web/assets/{diagram-22UHCM2B-Bhef_gli.js → diagram-22UHCM2B-BpXFmuft.js} +1 -1
- package/dist/web/assets/{diagram-3UASUU5V-Bt5jGMJj.js → diagram-3UASUU5V-BQvfr6_4.js} +1 -1
- package/dist/web/assets/{diagram-ATOU4E4O-E9OEgrvO.js → diagram-ATOU4E4O-DpVGu2ct.js} +1 -1
- package/dist/web/assets/{diagram-CDSNMT55-Ev4KURRW.js → diagram-CDSNMT55-CMhnvQ9p.js} +1 -1
- package/dist/web/assets/{diagram-MLGK6HIB-VyRxPiEM.js → diagram-MLGK6HIB-CMUiUB5V.js} +1 -1
- package/dist/web/assets/{diagram-MPIPVDR6-NZUHIzSK.js → diagram-MPIPVDR6-DAEDT1M_.js} +1 -1
- package/dist/web/assets/{ebnfDiagram-ZINNZB2B-BWrpXmAB.js → ebnfDiagram-ZINNZB2B--teB4gEh.js} +1 -1
- package/dist/web/assets/{elk-276RUBZZ-BGHyKt3X.js → elk-276RUBZZ-DTJ8porF.js} +1 -1
- package/dist/web/assets/{erDiagram-OPXOYQCR-GrSAUtcQ.js → erDiagram-OPXOYQCR-Cu8sQHj7.js} +1 -1
- package/dist/web/assets/{flowDiagram-KWPJA3E3-B_WVUUVf.js → flowDiagram-KWPJA3E3-C3YlGYFe.js} +1 -1
- package/dist/web/assets/{ganttDiagram-FUAMR5RP-DajvFrX3.js → ganttDiagram-FUAMR5RP-InE3Qjdk.js} +1 -1
- package/dist/web/assets/{gitGraphDiagram-X574FWY7-CrHV5Rvk.js → gitGraphDiagram-X574FWY7-W9cDxWIt.js} +1 -1
- package/dist/web/assets/{index-COls5qGF.css → index-D6wYxAVF.css} +1 -1
- package/dist/web/assets/{index-DNSP9H_v.js → index-z64JVqEI.js} +167 -166
- package/dist/web/assets/{infoDiagram-VRGFBTTK-BVr7SUMq.js → infoDiagram-VRGFBTTK-Cs_MZzVX.js} +1 -1
- package/dist/web/assets/{ishikawaDiagram-OU5B5YK6-Clo1T4Ou.js → ishikawaDiagram-OU5B5YK6-CYNBwCgu.js} +1 -1
- package/dist/web/assets/{journeyDiagram-ZHPQQLJL-BJJiqW1W.js → journeyDiagram-ZHPQQLJL-M_8xlDc6.js} +1 -1
- package/dist/web/assets/{kanban-definition-PNTS6WVX-FIP6aaWx.js → kanban-definition-PNTS6WVX-DJM9NnPd.js} +1 -1
- package/dist/web/assets/{linear-gNF2RYPF.js → linear-D2pugD8L.js} +1 -1
- package/dist/web/assets/{mindmap-definition-NLK3R4M7-U9ZgUluP.js → mindmap-definition-NLK3R4M7-Ej_zTWtJ.js} +1 -1
- package/dist/web/assets/{pegDiagram-GJSIUBJH-kqET45uW.js → pegDiagram-GJSIUBJH-C1eyhBDj.js} +1 -1
- package/dist/web/assets/{pieDiagram-5QR66LMP-0Vfqg8YJ.js → pieDiagram-5QR66LMP-ciGhrblI.js} +1 -1
- package/dist/web/assets/{quadrantDiagram-O4NWA36T-BwbgrFii.js → quadrantDiagram-O4NWA36T-8MJ_CUFe.js} +1 -1
- package/dist/web/assets/{railroadDiagram-XR7U4H2S-AQGvMbOL.js → railroadDiagram-XR7U4H2S-CrBQOwD0.js} +1 -1
- package/dist/web/assets/{requirementDiagram-PLB6GJNP-WJNa_ucq.js → requirementDiagram-PLB6GJNP-glZ4Tl5M.js} +1 -1
- package/dist/web/assets/{sankeyDiagram-IPEJSGJF-DTOl4R33.js → sankeyDiagram-IPEJSGJF-C87eVSmR.js} +1 -1
- package/dist/web/assets/{sequenceDiagram-PO4LG4MO-4xQidS78.js → sequenceDiagram-PO4LG4MO-C4kD0n6_.js} +1 -1
- package/dist/web/assets/{sizeCapture-INFHLROL--JObXzuK.js → sizeCapture-INFHLROL-C3egfWS7.js} +1 -1
- package/dist/web/assets/{stateDiagram-v2-GCMORJYK-DO54xQHQ.js → stateDiagram-v2-GCMORJYK-miD15x9p.js} +1 -1
- package/dist/web/assets/{swimlanes-2SLR337P-D2RfEaDP.js → swimlanes-2SLR337P-RFbVR5iD.js} +1 -1
- package/dist/web/assets/swimlanesDiagram-TC7HE7FX-DQeW6-o5.js +8 -0
- package/dist/web/assets/{timeline-definition-EJHVYXUP-CjEGHstB.js → timeline-definition-EJHVYXUP-DjpYQNiI.js} +1 -1
- package/dist/web/assets/{usecaseDiagram-POWQR4AR-B_QSF3HN.js → usecaseDiagram-POWQR4AR-BIo58LtF.js} +1 -1
- package/dist/web/assets/{vennDiagram-UO4OBE2U-DaXBK4lA.js → vennDiagram-UO4OBE2U-D7wQezYC.js} +1 -1
- package/dist/web/assets/{wardleyDiagram-VNRHLVJA-DAcGG1ul.js → wardleyDiagram-VNRHLVJA-DwhQUOY8.js} +1 -1
- package/dist/web/assets/{xychartDiagram-PMCCYNJV-C9NMkFcl.js → xychartDiagram-PMCCYNJV-B0cVFGsf.js} +1 -1
- package/dist/web/index.html +2 -2
- package/dist/webServer.d.ts +1 -1
- package/dist/webServer.js +2 -2
- package/package.json +2 -2
- package/dist/chunk-G6SEOLMU.js.map +0 -1
- package/dist/web/assets/channel-D3CmON_0.js +0 -1
- package/dist/web/assets/swimlanesDiagram-TC7HE7FX-BTVqf00K.js +0 -8
- /package/dist/{chunk-3ALI2CBW.js.map → chunk-DGQHHNPC.js.map} +0 -0
|
@@ -4,13 +4,13 @@ import {
|
|
|
4
4
|
createRuntime,
|
|
5
5
|
createWebServer,
|
|
6
6
|
disposeRuntime
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-ML64BPIL.js";
|
|
8
8
|
import {
|
|
9
9
|
formatDaemonUrl,
|
|
10
10
|
resolveDaemonEndpoint,
|
|
11
11
|
startMcpStdio,
|
|
12
12
|
version
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-WT4GTWHD.js";
|
|
14
14
|
|
|
15
15
|
// src/mcpBridge.ts
|
|
16
16
|
var SECRET_HEADER = "X-Git-Cockpit-Secret";
|
|
@@ -403,4 +403,4 @@ async function main(argv) {
|
|
|
403
403
|
export {
|
|
404
404
|
main
|
|
405
405
|
};
|
|
406
|
-
//# sourceMappingURL=chunk-
|
|
406
|
+
//# sourceMappingURL=chunk-DGQHHNPC.js.map
|
|
@@ -10,11 +10,11 @@ import {
|
|
|
10
10
|
summarizeForAgent,
|
|
11
11
|
toolSummaries,
|
|
12
12
|
version
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-WT4GTWHD.js";
|
|
14
14
|
|
|
15
15
|
// src/webServer.ts
|
|
16
|
-
import * as
|
|
17
|
-
import * as
|
|
16
|
+
import * as path4 from "path";
|
|
17
|
+
import * as fs3 from "fs";
|
|
18
18
|
import { fileURLToPath } from "url";
|
|
19
19
|
import Fastify from "fastify";
|
|
20
20
|
import { timingSafeEqual } from "crypto";
|
|
@@ -38,7 +38,7 @@ import {
|
|
|
38
38
|
probeAllMrCli,
|
|
39
39
|
readCliAuthToken,
|
|
40
40
|
renderMrTemplate,
|
|
41
|
-
RepoNotFoundError as
|
|
41
|
+
RepoNotFoundError as RepoNotFoundError4,
|
|
42
42
|
toHttpsRemoteUrl,
|
|
43
43
|
upsertMrHost,
|
|
44
44
|
maskToken,
|
|
@@ -55,6 +55,7 @@ import {
|
|
|
55
55
|
import { EventEmitter as EventEmitter2 } from "events";
|
|
56
56
|
import {
|
|
57
57
|
AuditLogger,
|
|
58
|
+
ChatLogStore,
|
|
58
59
|
JobEngine,
|
|
59
60
|
JobStore,
|
|
60
61
|
PermissionManager,
|
|
@@ -335,6 +336,7 @@ function createRuntime(options = {}) {
|
|
|
335
336
|
const eventBus = new EventEmitter2();
|
|
336
337
|
eventBus.setMaxListeners(200);
|
|
337
338
|
const auditLogger = new AuditLogger(db, config.logging);
|
|
339
|
+
const chatLog = new ChatLogStore(db);
|
|
338
340
|
const permissions = new PermissionManager(config);
|
|
339
341
|
const repoStore = new RepoStore2(db);
|
|
340
342
|
const repoManager = new RepoManager({ repoStore, eventBus, getConfig: () => configStore.get() });
|
|
@@ -353,6 +355,7 @@ function createRuntime(options = {}) {
|
|
|
353
355
|
config,
|
|
354
356
|
db,
|
|
355
357
|
auditLogger,
|
|
358
|
+
chatLog,
|
|
356
359
|
permissions,
|
|
357
360
|
repoStore,
|
|
358
361
|
repoManager,
|
|
@@ -378,7 +381,13 @@ import swaggerUi from "@fastify/swagger-ui";
|
|
|
378
381
|
import { zodToJsonSchema } from "zod-to-json-schema";
|
|
379
382
|
var REST_META = {
|
|
380
383
|
"get /api/health": { summary: "\u63A2\u6D3B", tags: ["\u7CFB\u7EDF"] },
|
|
381
|
-
"
|
|
384
|
+
"get /api/service-update": { summary: "\u670D\u52A1\u7AEF\u662F\u5426\u6709\u66F4\u65B0\uFF08npm \u6700\u65B0\u7248\uFF0C\u5E26\u7F13\u5B58\uFF09", tags: ["\u7CFB\u7EDF"] },
|
|
385
|
+
"post /api/jobs/desktop-download": { summary: "\u767B\u8BB0\u684C\u9762\u5B89\u88C5\u5305\u4E0B\u8F7D\u4EFB\u52A1\uFF08\u7531\u58F3\u5B50\u56DE\u62A5\u8FDB\u5EA6\uFF09", tags: ["\u4ED3\u5E93"] },
|
|
386
|
+
"post /api/jobs/{id}/desktop-progress": { summary: "\u66F4\u65B0\u684C\u9762\u4E0B\u8F7D\u8FDB\u5EA6\uFF1B\u5B8C\u6210\u540E\u4E0D\u518D\u5360\u7740\u8FDB\u884C\u4E2D", tags: ["\u4ED3\u5E93"] },
|
|
387
|
+
"post /api/shutdown": {
|
|
388
|
+
summary: "\u4F18\u96C5\u9000\u51FA daemon\uFF08\u672C\u673A\u5BC6\u94A5\uFF1B\u6709 running \u4EFB\u52A1\u65F6 409\uFF0Cforce \u786E\u8BA4\u540E\u4ECD\u9000\u51FA\uFF09",
|
|
389
|
+
tags: ["\u7CFB\u7EDF"]
|
|
390
|
+
},
|
|
382
391
|
"get /api/repos": { summary: "\u5DF2\u6253\u5F00\u4ED3\u5E93\u5217\u8868", tags: ["\u4ED3\u5E93"] },
|
|
383
392
|
"get /api/repos/overview": { summary: "\u5DF2\u6253\u5F00\u4ED3\u5E93\u8109\u640F\uFF08\u5DE5\u4F5C\u53F0\uFF0C\u5168\u91CF\uFF09", tags: ["\u4ED3\u5E93"] },
|
|
384
393
|
"get /api/repos/{id}/overview": { summary: "\u5355\u4E2A\u4ED3\u5E93\u8109\u640F\uFF08\u5DE5\u4F5C\u53F0\u589E\u91CF\uFF09", tags: ["\u4ED3\u5E93"] },
|
|
@@ -414,6 +423,10 @@ var REST_META = {
|
|
|
414
423
|
"post /api/jobs/clone": { summary: "\u540E\u53F0\u514B\u9686\u8FDC\u7A0B\u4ED3\u5E93", tags: ["\u4ED3\u5E93"] },
|
|
415
424
|
"get /api/tools": { summary: "\u5DE5\u5177\u6CE8\u518C\u8868\uFF08\u542B\u98CE\u9669\u4E0E\u662F\u5426\u542F\u7528\uFF09", tags: ["\u7CFB\u7EDF"] },
|
|
416
425
|
"get /api/logs": { summary: "\u64CD\u4F5C\u5BA1\u8BA1\u65E5\u5FD7", tags: ["\u7CFB\u7EDF"] },
|
|
426
|
+
"get /api/chat/conversations": { summary: "\u5BF9\u8BDD\u8BB0\u5F55\u5217\u8868", tags: ["\u804A\u5929"] },
|
|
427
|
+
"get /api/chat/conversations/{id}": { summary: "\u4E00\u7EC4\u5BF9\u8BDD\u7684\u5168\u6587", tags: ["\u804A\u5929"] },
|
|
428
|
+
"delete /api/chat/conversations/{id}": { summary: "\u5220\u9664\u4E00\u7EC4\u5BF9\u8BDD", tags: ["\u804A\u5929"] },
|
|
429
|
+
"post /api/chat/conversations/{id}/messages": { summary: "\u8FFD\u52A0\u4E00\u8F6E\u5BF9\u8BDD\uFF08\u542B\u672C\u5730\u9884\u89C8\uFF09", tags: ["\u804A\u5929"] },
|
|
417
430
|
"get /api/settings": { summary: "\u914D\u7F6E\u4E0E\u6743\u9650", tags: ["\u8BBE\u7F6E"] },
|
|
418
431
|
"put /api/settings": { summary: "\u66F4\u65B0\u6743\u9650\u6216 MR \u914D\u7F6E\uFF08Token \u660E\u6587\u4E0D\u56DE\u8BFB\uFF0C\u4FDD\u5B58\u524D\u6821\u9A8C\uFF09", tags: ["\u8BBE\u7F6E"] },
|
|
419
432
|
"post /api/settings/mr-template/parse": { summary: "\u5BFC\u5165 Markdown \u4E3A MR \u6B63\u6587\u6A21\u677F\u5B57\u6BB5\uFF08\u4E0D\u843D\u76D8\uFF09", tags: ["\u8BBE\u7F6E"] },
|
|
@@ -421,12 +434,12 @@ var REST_META = {
|
|
|
421
434
|
"get /api/events": { summary: "SSE\uFF1A\u4ED3\u5E93\u53D8\u5316\u3001\u65E5\u5FD7\u3001\u540E\u53F0\u4EFB\u52A1\u8FDB\u5EA6", tags: ["\u7CFB\u7EDF"] }
|
|
422
435
|
};
|
|
423
436
|
function applyRestMeta(spec) {
|
|
424
|
-
for (const [
|
|
437
|
+
for (const [path5, item] of Object.entries(spec.paths ?? {})) {
|
|
425
438
|
if (!item) continue;
|
|
426
439
|
for (const method of Object.keys(item)) {
|
|
427
440
|
const op = item[method];
|
|
428
441
|
if (!op || typeof op !== "object") continue;
|
|
429
|
-
const meta = REST_META[`${method} ${
|
|
442
|
+
const meta = REST_META[`${method} ${path5}`];
|
|
430
443
|
if (meta) {
|
|
431
444
|
if (!op.summary) op.summary = meta.summary;
|
|
432
445
|
if (!op.tags) op.tags = meta.tags;
|
|
@@ -507,7 +520,12 @@ async function registerApiDocs(app) {
|
|
|
507
520
|
// src/chat/chatRoute.ts
|
|
508
521
|
import { streamText, tool, stepCountIs } from "ai";
|
|
509
522
|
import { createOpenAI } from "@ai-sdk/openai";
|
|
510
|
-
import {
|
|
523
|
+
import {
|
|
524
|
+
applyLlmEnvOverrides,
|
|
525
|
+
isChatLogRole,
|
|
526
|
+
llmBaseUrl,
|
|
527
|
+
RepoNotFoundError as RepoNotFoundError3
|
|
528
|
+
} from "@shaohui_jin/git-cockpit-core";
|
|
511
529
|
|
|
512
530
|
// src/chat/confirmGate.ts
|
|
513
531
|
import { createHash, randomUUID } from "crypto";
|
|
@@ -904,26 +922,205 @@ function registerChatRoutes(app, runtime) {
|
|
|
904
922
|
if (!out.ok) return reply.code(409).send(out);
|
|
905
923
|
return out;
|
|
906
924
|
});
|
|
925
|
+
app.get("/api/chat/conversations", async (req) => {
|
|
926
|
+
let repoPath = typeof req.query.repoPath === "string" ? req.query.repoPath.trim() : "";
|
|
927
|
+
if (repoPath) repoPath = openedRepoPath(runtime, repoPath) ?? repoPath;
|
|
928
|
+
return {
|
|
929
|
+
conversations: runtime.chatLog.list({
|
|
930
|
+
repoPath: repoPath || void 0,
|
|
931
|
+
limit: clampLimit(req.query.limit)
|
|
932
|
+
})
|
|
933
|
+
};
|
|
934
|
+
});
|
|
935
|
+
app.get("/api/chat/conversations/:id", async (req, reply) => {
|
|
936
|
+
const id = validConversationId(req.params.id);
|
|
937
|
+
if (!id) return reply.code(400).send({ error: "\u5BF9\u8BDD id \u65E0\u6548" });
|
|
938
|
+
const found = runtime.chatLog.get(id);
|
|
939
|
+
if (!found) return reply.code(404).send({ error: "\u5BF9\u8BDD\u4E0D\u5B58\u5728" });
|
|
940
|
+
return found;
|
|
941
|
+
});
|
|
942
|
+
app.delete("/api/chat/conversations/:id", async (req, reply) => {
|
|
943
|
+
const id = validConversationId(req.params.id);
|
|
944
|
+
if (!id) return reply.code(400).send({ error: "\u5BF9\u8BDD id \u65E0\u6548" });
|
|
945
|
+
if (!runtime.chatLog.remove(id)) return reply.code(404).send({ error: "\u5BF9\u8BDD\u4E0D\u5B58\u5728" });
|
|
946
|
+
return { ok: true };
|
|
947
|
+
});
|
|
948
|
+
app.post("/api/chat/conversations/:id/messages", async (req, reply) => {
|
|
949
|
+
const id = validConversationId(req.params.id);
|
|
950
|
+
if (!id) return reply.code(400).send({ error: "\u5BF9\u8BDD id \u65E0\u6548" });
|
|
951
|
+
const requested = typeof req.body?.repoPath === "string" ? req.body.repoPath.trim() : "";
|
|
952
|
+
if (!requested) return reply.code(400).send({ error: "\u8BF7\u5148\u9009\u62E9\u4ED3\u5E93", code: "NO_ACTIVE_REPO" });
|
|
953
|
+
const repoPath = openedRepoPath(runtime, requested);
|
|
954
|
+
if (!repoPath) {
|
|
955
|
+
return reply.code(400).send({ error: "\u8BF7\u5148\u5728\u5DE5\u4F5C\u53F0\u6253\u5F00\u8BE5\u4ED3\u5E93", code: "REPO_NOT_OPEN" });
|
|
956
|
+
}
|
|
957
|
+
const parsed = parseChatLogMessages(req.body?.messages);
|
|
958
|
+
if (!parsed.ok) return reply.code(400).send({ error: parsed.error });
|
|
959
|
+
const saved = runtime.chatLog.append(id, repoPath, parsed.messages);
|
|
960
|
+
if (!saved.ok) {
|
|
961
|
+
return reply.code(409).send({ error: "\u8FD9\u7EC4\u5BF9\u8BDD\u5C5E\u4E8E\u53E6\u4E00\u4E2A\u4ED3\u5E93", code: "CONVERSATION_REPO_MISMATCH" });
|
|
962
|
+
}
|
|
963
|
+
return { conversation: saved.conversation };
|
|
964
|
+
});
|
|
965
|
+
}
|
|
966
|
+
var CONVERSATION_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
967
|
+
var MAX_MESSAGES = 20;
|
|
968
|
+
var MAX_TEXT = 1e5;
|
|
969
|
+
function validConversationId(raw) {
|
|
970
|
+
const id = raw.trim();
|
|
971
|
+
return CONVERSATION_ID.test(id) ? id : null;
|
|
972
|
+
}
|
|
973
|
+
function clampLimit(raw) {
|
|
974
|
+
const n = raw == null || raw === "" ? 100 : Number(raw);
|
|
975
|
+
if (!Number.isFinite(n)) return 100;
|
|
976
|
+
return Math.min(Math.max(Math.floor(n), 1), 200);
|
|
977
|
+
}
|
|
978
|
+
function openedRepoPath(runtime, repoPath) {
|
|
979
|
+
try {
|
|
980
|
+
return runtime.repoManager.getByPath(repoPath).service.repoPath;
|
|
981
|
+
} catch (err) {
|
|
982
|
+
if (err instanceof RepoNotFoundError3) return null;
|
|
983
|
+
throw err;
|
|
984
|
+
}
|
|
985
|
+
}
|
|
986
|
+
function parseChatLogMessages(raw) {
|
|
987
|
+
if (!Array.isArray(raw) || raw.length === 0) return { ok: false, error: "messages \u4E0D\u80FD\u4E3A\u7A7A" };
|
|
988
|
+
if (raw.length > MAX_MESSAGES) return { ok: false, error: "\u4E00\u6B21\u6700\u591A\u8FFD\u52A0 20 \u6761\u6D88\u606F" };
|
|
989
|
+
const messages = [];
|
|
990
|
+
for (const item of raw) {
|
|
991
|
+
if (!item || typeof item !== "object") return { ok: false, error: "\u6D88\u606F\u683C\u5F0F\u65E0\u6548" };
|
|
992
|
+
const row = item;
|
|
993
|
+
if (typeof row.role !== "string" || !isChatLogRole(row.role)) return { ok: false, error: "\u6D88\u606F\u89D2\u8272\u65E0\u6548" };
|
|
994
|
+
if (typeof row.text !== "string" || row.text.length > MAX_TEXT) return { ok: false, error: "\u6D88\u606F\u6B63\u6587\u65E0\u6548" };
|
|
995
|
+
if (row.tool != null && typeof row.tool !== "string") return { ok: false, error: "\u5DE5\u5177\u540D\u65E0\u6548" };
|
|
996
|
+
if (row.success != null && typeof row.success !== "boolean") return { ok: false, error: "\u5DE5\u5177\u7ED3\u679C\u65E0\u6548" };
|
|
997
|
+
messages.push({
|
|
998
|
+
role: row.role,
|
|
999
|
+
text: row.text,
|
|
1000
|
+
tool: typeof row.tool === "string" ? row.tool : null,
|
|
1001
|
+
success: typeof row.success === "boolean" ? row.success : null
|
|
1002
|
+
});
|
|
1003
|
+
}
|
|
1004
|
+
return { ok: true, messages };
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
// src/serviceUpdate.ts
|
|
1008
|
+
import { spawn } from "child_process";
|
|
1009
|
+
import fs2 from "fs";
|
|
1010
|
+
import path3 from "path";
|
|
1011
|
+
var PKG = "@shaohui_jin/git-cockpit-mcp-server";
|
|
1012
|
+
var TTL_MS3 = 30 * 60 * 1e3;
|
|
1013
|
+
var FAIL_TTL_MS = 60 * 1e3;
|
|
1014
|
+
var lookup = npmViewLatest;
|
|
1015
|
+
var cache = null;
|
|
1016
|
+
async function readServiceUpdate(current) {
|
|
1017
|
+
const latest = await cachedLatest();
|
|
1018
|
+
const updateAvailable = Boolean(latest && compareVersions(latest, current) > 0);
|
|
1019
|
+
return {
|
|
1020
|
+
version: current,
|
|
1021
|
+
latestVersion: latest,
|
|
1022
|
+
updateAvailable,
|
|
1023
|
+
command: updateAvailable && latest ? `npm i -g ${PKG}@${latest}` : null
|
|
1024
|
+
};
|
|
1025
|
+
}
|
|
1026
|
+
async function cachedLatest() {
|
|
1027
|
+
const now = Date.now();
|
|
1028
|
+
if (cache && now - cache.at < cache.ttl) return cache.latest;
|
|
1029
|
+
let latest = null;
|
|
1030
|
+
let ttl = FAIL_TTL_MS;
|
|
1031
|
+
try {
|
|
1032
|
+
latest = await lookup();
|
|
1033
|
+
if (latest) ttl = TTL_MS3;
|
|
1034
|
+
} catch {
|
|
1035
|
+
latest = null;
|
|
1036
|
+
}
|
|
1037
|
+
cache = { at: now, latest, ttl };
|
|
1038
|
+
return latest;
|
|
1039
|
+
}
|
|
1040
|
+
function parseVersion(raw) {
|
|
1041
|
+
const matched = raw.trim().match(/(\d+)\.(\d+)\.(\d+)/);
|
|
1042
|
+
if (!matched) return null;
|
|
1043
|
+
return [Number(matched[1]), Number(matched[2]), Number(matched[3])];
|
|
1044
|
+
}
|
|
1045
|
+
function compareVersions(a, b) {
|
|
1046
|
+
const left = parseVersion(a);
|
|
1047
|
+
const right = parseVersion(b);
|
|
1048
|
+
if (!left || !right) return 0;
|
|
1049
|
+
for (let i = 0; i < 3; i += 1) {
|
|
1050
|
+
const av = left[i] ?? 0;
|
|
1051
|
+
const bv = right[i] ?? 0;
|
|
1052
|
+
if (av !== bv) return av - bv;
|
|
1053
|
+
}
|
|
1054
|
+
return 0;
|
|
1055
|
+
}
|
|
1056
|
+
function resolveNpmCli(nodePath) {
|
|
1057
|
+
const dir = path3.dirname(nodePath);
|
|
1058
|
+
const candidates = [
|
|
1059
|
+
path3.join(dir, "node_modules", "npm", "bin", "npm-cli.js"),
|
|
1060
|
+
path3.resolve(dir, "..", "lib", "node_modules", "npm", "bin", "npm-cli.js")
|
|
1061
|
+
];
|
|
1062
|
+
return candidates.find((item) => fs2.existsSync(item)) ?? null;
|
|
1063
|
+
}
|
|
1064
|
+
function parseNpmVersion(raw) {
|
|
1065
|
+
const quoted = raw.match(/"(\d+\.\d+\.\d+)"/);
|
|
1066
|
+
if (quoted?.[1]) return quoted[1];
|
|
1067
|
+
const plain = parseVersion(raw);
|
|
1068
|
+
return plain ? plain.join(".") : null;
|
|
1069
|
+
}
|
|
1070
|
+
function npmViewLatest() {
|
|
1071
|
+
const nodePath = process.execPath;
|
|
1072
|
+
const npmCli = resolveNpmCli(nodePath);
|
|
1073
|
+
const cmd = npmCli ? nodePath : process.platform === "win32" ? "npm.cmd" : "npm";
|
|
1074
|
+
const args = npmCli ? [npmCli, "view", PKG, "version", "--json"] : ["view", PKG, "version", "--json"];
|
|
1075
|
+
return new Promise((resolve3) => {
|
|
1076
|
+
const child = spawn(cmd, args, {
|
|
1077
|
+
windowsHide: true,
|
|
1078
|
+
shell: !npmCli && process.platform === "win32"
|
|
1079
|
+
});
|
|
1080
|
+
let output = "";
|
|
1081
|
+
const timer = setTimeout(() => {
|
|
1082
|
+
child.kill();
|
|
1083
|
+
resolve3(null);
|
|
1084
|
+
}, 15e3);
|
|
1085
|
+
child.stdout?.on("data", (chunk) => {
|
|
1086
|
+
output += chunk.toString();
|
|
1087
|
+
});
|
|
1088
|
+
child.stderr?.on("data", (chunk) => {
|
|
1089
|
+
output += chunk.toString();
|
|
1090
|
+
});
|
|
1091
|
+
child.on("error", () => {
|
|
1092
|
+
clearTimeout(timer);
|
|
1093
|
+
resolve3(null);
|
|
1094
|
+
});
|
|
1095
|
+
child.on("close", (code) => {
|
|
1096
|
+
clearTimeout(timer);
|
|
1097
|
+
if (code !== 0) {
|
|
1098
|
+
resolve3(null);
|
|
1099
|
+
return;
|
|
1100
|
+
}
|
|
1101
|
+
resolve3(parseNpmVersion(output));
|
|
1102
|
+
});
|
|
1103
|
+
});
|
|
907
1104
|
}
|
|
908
1105
|
|
|
909
1106
|
// src/webServer.ts
|
|
910
1107
|
function resolveWebDist() {
|
|
911
|
-
const here =
|
|
1108
|
+
const here = path4.resolve(path4.dirname(fileURLToPath(import.meta.url)));
|
|
912
1109
|
const candidates = [
|
|
913
|
-
|
|
1110
|
+
path4.resolve(here, "..", "..", "web", "dist"),
|
|
914
1111
|
// 源码布局:packages/mcp-server/dist → packages/web/dist
|
|
915
|
-
|
|
1112
|
+
path4.resolve(here, "web"),
|
|
916
1113
|
// 发布布局:产物由 copy-web.mjs 打入 dist/web(含 index.html)
|
|
917
|
-
|
|
1114
|
+
path4.resolve(here, "web", "dist"),
|
|
918
1115
|
// 兼容旧式 dist/web/dist 布局
|
|
919
|
-
|
|
1116
|
+
path4.resolve(here, "..", "web", "dist"),
|
|
920
1117
|
// 兼容 npm 全局安装目录的旧式布局
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
1118
|
+
path4.resolve(process.cwd(), "dist", "web"),
|
|
1119
|
+
path4.resolve(process.cwd(), "..", "web", "dist"),
|
|
1120
|
+
path4.resolve(process.cwd(), "node_modules", "@shaohui_jin", "git-cockpit-web", "dist")
|
|
924
1121
|
];
|
|
925
1122
|
for (const c of candidates) {
|
|
926
|
-
if (
|
|
1123
|
+
if (fs3.existsSync(path4.join(c, "index.html"))) return c;
|
|
927
1124
|
}
|
|
928
1125
|
return null;
|
|
929
1126
|
}
|
|
@@ -978,7 +1175,7 @@ async function createWebServer(runtime, options = {}) {
|
|
|
978
1175
|
await registerApiDocs(app);
|
|
979
1176
|
registerChatRoutes(app, runtime);
|
|
980
1177
|
const staticDir = options.staticDir !== void 0 ? options.staticDir : resolveWebDist();
|
|
981
|
-
if (staticDir &&
|
|
1178
|
+
if (staticDir && fs3.existsSync(staticDir)) {
|
|
982
1179
|
await app.register(fastifyStatic, { root: staticDir, prefix: "/" });
|
|
983
1180
|
}
|
|
984
1181
|
const mcpHttp = new McpHttpHandler(runtime);
|
|
@@ -989,14 +1186,16 @@ async function createWebServer(runtime, options = {}) {
|
|
|
989
1186
|
version,
|
|
990
1187
|
uptimeMs: process.uptime() * 1e3
|
|
991
1188
|
}));
|
|
1189
|
+
app.get("/api/service-update", async () => readServiceUpdate(version));
|
|
992
1190
|
app.get("/api/bootstrap", async (req, reply) => {
|
|
993
1191
|
if (req.headers.origin) {
|
|
994
1192
|
return reply.code(403).send({ error: "bootstrap \u4E0D\u7ED9\u8DE8\u7AD9\u9875\u9762" });
|
|
995
1193
|
}
|
|
996
1194
|
return { secret: runtime.config.auth.localSecret };
|
|
997
1195
|
});
|
|
998
|
-
app.post("/api/shutdown", async (
|
|
999
|
-
|
|
1196
|
+
app.post("/api/shutdown", async (req, reply) => {
|
|
1197
|
+
const force = req.body?.force === true;
|
|
1198
|
+
if (!force && jobs.list().some((j) => j.status === "running")) {
|
|
1000
1199
|
return reply.code(409).send({ error: "\u6709\u4EFB\u52A1\u8FDB\u884C\u4E2D\uFF0C\u8BF7\u5148\u7B49\u5F85\u7ED3\u675F" });
|
|
1001
1200
|
}
|
|
1002
1201
|
await reply.code(204).send();
|
|
@@ -1017,6 +1216,28 @@ async function createWebServer(runtime, options = {}) {
|
|
|
1017
1216
|
if (!job) return reply.code(404).send({ error: "\u4EFB\u52A1\u4E0D\u5B58\u5728" });
|
|
1018
1217
|
return { job: jobs.detail(job) };
|
|
1019
1218
|
});
|
|
1219
|
+
app.post("/api/jobs/desktop-download", async (req, reply) => {
|
|
1220
|
+
const current = req.body?.version?.trim() ?? "";
|
|
1221
|
+
const latest = req.body?.latest?.trim() ?? "";
|
|
1222
|
+
if (!current || !latest) {
|
|
1223
|
+
return reply.code(400).send({ error: "\u9700\u8981 version \u4E0E latest" });
|
|
1224
|
+
}
|
|
1225
|
+
const job = jobs.beginDesktopDownload({ version: current, latest });
|
|
1226
|
+
return { job: jobs.summary(job) };
|
|
1227
|
+
});
|
|
1228
|
+
app.post("/api/jobs/:id/desktop-progress", async (req, reply) => {
|
|
1229
|
+
try {
|
|
1230
|
+
const job = jobs.reportDesktopDownload(req.params.id, {
|
|
1231
|
+
phase: req.body?.phase,
|
|
1232
|
+
percent: req.body?.percent,
|
|
1233
|
+
error: req.body?.error
|
|
1234
|
+
});
|
|
1235
|
+
return { job: jobs.summary(job) };
|
|
1236
|
+
} catch (err) {
|
|
1237
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1238
|
+
return reply.code(msg === "\u4EFB\u52A1\u4E0D\u5B58\u5728" ? 404 : 400).send({ error: msg });
|
|
1239
|
+
}
|
|
1240
|
+
});
|
|
1020
1241
|
app.post("/api/jobs/:id/cancel", async (req, reply) => {
|
|
1021
1242
|
try {
|
|
1022
1243
|
const job = jobs.cancel(req.params.id);
|
|
@@ -1619,9 +1840,9 @@ data: ${JSON.stringify(payload)}
|
|
|
1619
1840
|
if (req.url.startsWith("/api") || req.url.startsWith("/mcp") || req.url.startsWith("/docs")) {
|
|
1620
1841
|
return reply.code(404).send({ error: "Not Found" });
|
|
1621
1842
|
}
|
|
1622
|
-
const index =
|
|
1623
|
-
if (
|
|
1624
|
-
reply.type("text/html").send(
|
|
1843
|
+
const index = path4.join(staticDir, "index.html");
|
|
1844
|
+
if (fs3.existsSync(index)) {
|
|
1845
|
+
reply.type("text/html").send(fs3.readFileSync(index, "utf8"));
|
|
1625
1846
|
return;
|
|
1626
1847
|
}
|
|
1627
1848
|
return reply.code(404).send({ error: "Not Found" });
|
|
@@ -1643,7 +1864,7 @@ data: ${JSON.stringify(payload)}
|
|
|
1643
1864
|
}
|
|
1644
1865
|
function toError(err) {
|
|
1645
1866
|
if (err instanceof GitOperationError) return { code: err.code, message: err.message };
|
|
1646
|
-
if (err instanceof
|
|
1867
|
+
if (err instanceof RepoNotFoundError4) return { code: "REPO_NOT_FOUND", message: err.message };
|
|
1647
1868
|
if (err instanceof Error) return { code: "INTERNAL_ERROR", message: err.message.slice(0, 500) };
|
|
1648
1869
|
return { code: "INTERNAL_ERROR", message: String(err) };
|
|
1649
1870
|
}
|
|
@@ -1794,4 +2015,4 @@ export {
|
|
|
1794
2015
|
disposeRuntime,
|
|
1795
2016
|
createWebServer
|
|
1796
2017
|
};
|
|
1797
|
-
//# sourceMappingURL=chunk-
|
|
2018
|
+
//# sourceMappingURL=chunk-ML64BPIL.js.map
|