@yinuo-ngm/mcp-server 0.1.2 → 0.1.3
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 +191 -208
- package/lib/audit/audit-event.d.ts +14 -0
- package/lib/audit/audit-event.js +2 -0
- package/lib/audit/audit-log.service.d.ts +7 -0
- package/lib/audit/audit-log.service.js +187 -0
- package/lib/audit/redact.d.ts +3 -0
- package/lib/audit/redact.js +28 -0
- package/lib/catalog/capabilities/blocked-local-actions.d.ts +1 -0
- package/lib/catalog/capabilities/blocked-local-actions.js +18 -0
- package/lib/catalog/capabilities/frontend-standard.d.ts +2 -0
- package/lib/catalog/capabilities/frontend-standard.js +36 -0
- package/lib/catalog/capabilities/hub-v2.d.ts +2 -0
- package/lib/catalog/capabilities/hub-v2.js +34 -0
- package/lib/catalog/capabilities/nginx.d.ts +2 -0
- package/lib/catalog/capabilities/nginx.js +23 -0
- package/lib/catalog/capabilities/project.d.ts +2 -0
- package/lib/catalog/capabilities/project.js +23 -0
- package/lib/catalog/capabilities/router.d.ts +2 -0
- package/lib/catalog/capabilities/router.js +11 -0
- package/lib/catalog/capabilities/runtime.d.ts +2 -0
- package/lib/catalog/capabilities/runtime.js +17 -0
- package/lib/catalog/capabilities/workspace.d.ts +2 -0
- package/lib/catalog/capabilities/workspace.js +23 -0
- package/lib/catalog/helpers.d.ts +3 -0
- package/lib/catalog/helpers.js +42 -0
- package/lib/catalog/index.d.ts +4 -0
- package/lib/catalog/index.js +23 -0
- package/lib/catalog/tools/frontend-standard.d.ts +2 -0
- package/lib/catalog/tools/frontend-standard.js +166 -0
- package/lib/catalog/tools/hub-v2-api.d.ts +2 -0
- package/lib/catalog/tools/hub-v2-api.js +124 -0
- package/lib/catalog/tools/hub-v2-docs.d.ts +2 -0
- package/lib/catalog/tools/hub-v2-docs.js +40 -0
- package/lib/catalog/tools/nginx.d.ts +2 -0
- package/lib/catalog/tools/nginx.js +96 -0
- package/lib/catalog/tools/project.d.ts +2 -0
- package/lib/catalog/tools/project.js +138 -0
- package/lib/catalog/tools/router.d.ts +2 -0
- package/lib/catalog/tools/router.js +26 -0
- package/lib/catalog/tools/runtime.d.ts +2 -0
- package/lib/catalog/tools/runtime.js +47 -0
- package/lib/catalog/tools/workspace.d.ts +2 -0
- package/lib/catalog/tools/workspace.js +75 -0
- package/lib/catalog/types.d.ts +15 -0
- package/lib/catalog/types.js +2 -0
- package/lib/context/create-tool-context.js +11 -10
- package/lib/context/local-server-client.d.ts +2 -0
- package/lib/context/local-server-client.js +174 -0
- package/lib/context/tool-context.d.ts +36 -0
- package/lib/doctor.d.ts +8 -0
- package/lib/doctor.js +221 -0
- package/lib/errors/error-codes.d.ts +12 -0
- package/lib/errors/error-codes.js +14 -0
- package/lib/errors/mcp-tool-error.d.ts +8 -0
- package/lib/errors/mcp-tool-error.js +14 -0
- package/lib/filesystem/project-files.d.ts +18 -0
- package/lib/filesystem/project-files.js +112 -0
- package/lib/git/local-git-read-service.d.ts +2 -0
- package/lib/git/local-git-read-service.js +96 -0
- package/lib/index.d.ts +1 -0
- package/lib/index.js +4 -0
- package/lib/policy/assert-tool-policy.js +10 -1
- package/lib/register-tools.js +67 -10
- package/lib/registry/tool-names.d.ts +95 -0
- package/lib/registry/tool-names.js +97 -0
- package/lib/services/path-guard.service.d.ts +4 -0
- package/lib/services/path-guard.service.js +75 -0
- package/lib/services/permission.service.d.ts +5 -0
- package/lib/services/permission.service.js +38 -0
- package/lib/services/project-resolver.service.d.ts +32 -0
- package/lib/services/project-resolver.service.js +95 -0
- package/lib/standard/frontend-standard.default.d.ts +2 -0
- package/lib/standard/frontend-standard.default.js +51 -0
- package/lib/standard/frontend-standard.schema.d.ts +196 -0
- package/lib/standard/frontend-standard.schema.js +61 -0
- package/lib/standard/frontend-standard.service.d.ts +79 -0
- package/lib/standard/frontend-standard.service.js +115 -0
- package/lib/standard/project-scan.d.ts +9 -0
- package/lib/standard/project-scan.js +91 -0
- package/lib/standard/validators/angular-structure.validator.d.ts +4 -0
- package/lib/standard/validators/angular-structure.validator.js +75 -0
- package/lib/standard/validators/component.validator.d.ts +4 -0
- package/lib/standard/validators/component.validator.js +94 -0
- package/lib/standard/validators/git.validator.d.ts +8 -0
- package/lib/standard/validators/git.validator.js +32 -0
- package/lib/standard/validators/review.validator.d.ts +15 -0
- package/lib/standard/validators/review.validator.js +67 -0
- package/lib/standard/validators/test.validator.d.ts +19 -0
- package/lib/standard/validators/test.validator.js +89 -0
- package/lib/tool-catalog.d.ts +2 -0
- package/lib/tool-catalog.js +6 -0
- package/lib/tools/angular/angular-standard.tools.d.ts +2 -0
- package/lib/tools/angular/angular-standard.tools.js +53 -0
- package/lib/tools/angular/index.d.ts +1 -0
- package/lib/tools/angular/index.js +5 -0
- package/lib/tools/capability.tools.d.ts +2 -0
- package/lib/tools/capability.tools.js +205 -0
- package/lib/tools/controlled/index.d.ts +2 -0
- package/lib/tools/controlled/index.js +13 -0
- package/lib/tools/controlled/local-server.d.ts +6 -0
- package/lib/tools/controlled/local-server.js +17 -0
- package/lib/tools/controlled/operation-policy.d.ts +22 -0
- package/lib/tools/controlled/operation-policy.js +50 -0
- package/lib/tools/controlled/operation-result.d.ts +30 -0
- package/lib/tools/controlled/operation-result.js +33 -0
- package/lib/tools/controlled/schemas.d.ts +159 -0
- package/lib/tools/controlled/schemas.js +49 -0
- package/lib/tools/controlled.tools.d.ts +1 -0
- package/lib/tools/controlled.tools.js +5 -0
- package/lib/tools/file-write.tools.d.ts +2 -0
- package/lib/tools/file-write.tools.js +70 -0
- package/lib/tools/git.tools.js +109 -8
- package/lib/tools/hub-v2/client.d.ts +6 -1
- package/lib/tools/hub-v2/client.js +15 -0
- package/lib/tools/hub-v2/config/config-paths.d.ts +2 -0
- package/lib/tools/hub-v2/config/config-paths.js +17 -0
- package/lib/tools/hub-v2/config/env.d.ts +1 -0
- package/lib/tools/hub-v2/config/env.js +12 -0
- package/lib/tools/hub-v2/config/index.d.ts +8 -0
- package/lib/tools/hub-v2/config/index.js +18 -0
- package/lib/tools/hub-v2/config/jsonc.d.ts +5 -0
- package/lib/tools/hub-v2/config/jsonc.js +86 -0
- package/lib/tools/hub-v2/config/load-config.d.ts +18 -0
- package/lib/tools/hub-v2/config/load-config.js +93 -0
- package/lib/tools/hub-v2/config/project-selector.d.ts +5 -0
- package/lib/tools/hub-v2/config/project-selector.js +92 -0
- package/lib/tools/hub-v2/config/resolve-context.d.ts +13 -0
- package/lib/tools/hub-v2/config/resolve-context.js +33 -0
- package/lib/tools/hub-v2/docs.tools.js +138 -4
- package/lib/tools/hub-v2/index.js +2 -0
- package/lib/tools/hub-v2/issues-workflow.tools.d.ts +2 -0
- package/lib/tools/hub-v2/issues-workflow.tools.js +199 -0
- package/lib/tools/hub-v2/issues.tools.js +96 -6
- package/lib/tools/hub-v2/projects.tools.js +16 -3
- package/lib/tools/hub-v2/raw.d.ts +8 -0
- package/lib/tools/hub-v2/raw.js +33 -0
- package/lib/tools/hub-v2/rd.tools.js +167 -8
- package/lib/tools/hub-v2/schemas.d.ts +668 -71
- package/lib/tools/hub-v2/schemas.js +152 -1
- package/lib/tools/hub-v2/upload.tools.js +53 -5
- package/lib/tools/index.d.ts +1 -0
- package/lib/tools/index.js +22 -0
- package/lib/tools/log.tools.js +33 -6
- package/lib/tools/nginx/index.d.ts +1 -0
- package/lib/tools/nginx/index.js +5 -0
- package/lib/tools/nginx/nginx-control.tools.d.ts +2 -0
- package/lib/tools/nginx/nginx-control.tools.js +133 -0
- package/lib/tools/nginx/nginx-proxy.d.ts +24 -0
- package/lib/tools/nginx/nginx-proxy.js +154 -0
- package/lib/tools/nginx.tools.d.ts +2 -0
- package/lib/tools/nginx.tools.js +111 -0
- package/lib/tools/project/index.d.ts +2 -0
- package/lib/tools/project/index.js +7 -0
- package/lib/tools/project/launch-status.d.ts +10 -0
- package/lib/tools/project/launch-status.js +78 -0
- package/lib/tools/project/local-diagnostics.d.ts +19 -0
- package/lib/tools/project/local-diagnostics.js +97 -0
- package/lib/tools/project/observe-redaction.d.ts +3 -0
- package/lib/tools/project/observe-redaction.js +25 -0
- package/lib/tools/project/observe-runtime.d.ts +72 -0
- package/lib/tools/project/observe-runtime.js +147 -0
- package/lib/tools/project/project-control.tools.d.ts +2 -0
- package/lib/tools/project/project-control.tools.js +216 -0
- package/lib/tools/project/project-observe.tools.d.ts +2 -0
- package/lib/tools/project/project-observe.tools.js +191 -0
- package/lib/tools/project/runtime-config.d.ts +7 -0
- package/lib/tools/project/runtime-config.js +50 -0
- package/lib/tools/project-observe.tools.d.ts +1 -0
- package/lib/tools/project-observe.tools.js +5 -0
- package/lib/tools/project.tools.d.ts +8 -0
- package/lib/tools/project.tools.js +97 -6
- package/lib/tools/proxy.tools.js +4 -4
- package/lib/tools/review/index.d.ts +1 -0
- package/lib/tools/review/index.js +5 -0
- package/lib/tools/review/review.tools.d.ts +2 -0
- package/lib/tools/review/review.tools.js +152 -0
- package/lib/tools/runtime/index.d.ts +1 -0
- package/lib/tools/runtime/index.js +5 -0
- package/lib/tools/runtime/runtime-control.tools.d.ts +2 -0
- package/lib/tools/runtime/runtime-control.tools.js +89 -0
- package/lib/tools/runtime.tools.js +41 -4
- package/lib/tools/standard/index.d.ts +1 -0
- package/lib/tools/standard/index.js +5 -0
- package/lib/tools/standard/standard.tools.d.ts +2 -0
- package/lib/tools/standard/standard.tools.js +91 -0
- package/lib/tools/task.tools.js +44 -9
- package/lib/tools/test/index.d.ts +1 -0
- package/lib/tools/test/index.js +5 -0
- package/lib/tools/test/test-standard.tools.d.ts +2 -0
- package/lib/tools/test/test-standard.tools.js +51 -0
- package/lib/tools/tool-catalog.d.ts +2 -0
- package/lib/tools/tool-catalog.js +7 -0
- package/lib/tools/workflow/frontend-workflow.tools.d.ts +2 -0
- package/lib/tools/workflow/frontend-workflow.tools.js +364 -0
- package/lib/tools/workflow/index.d.ts +1 -0
- package/lib/tools/workflow/index.js +5 -0
- package/lib/tools/workspace-package.d.ts +22 -0
- package/lib/tools/workspace-package.js +130 -0
- package/lib/tools/workspace.tools.d.ts +7 -0
- package/lib/tools/workspace.tools.js +336 -0
- package/lib/utils/errors.js +6 -1
- package/lib/utils/result.d.ts +9 -0
- package/lib/utils/result.js +9 -0
- package/lib/workflow/frontend-task.schema.d.ts +83 -0
- package/lib/workflow/frontend-task.schema.js +25 -0
- package/lib/workflow/frontend-task.service.d.ts +57 -0
- package/lib/workflow/frontend-task.service.js +195 -0
- package/lib/workflow/workflow-status.d.ts +2 -0
- package/lib/workflow/workflow-status.js +14 -0
- package/lib/workflow/workflow-transition.d.ts +9 -0
- package/lib/workflow/workflow-transition.js +38 -0
- package/package.json +5 -3
- package/lib/tools/hub-v2/config.d.ts +0 -34
- package/lib/tools/hub-v2/config.js +0 -297
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { ResolvedProjectRoot } from "../filesystem/project-files";
|
|
2
|
+
import type { FrontendTask, WorkflowChecks } from "./frontend-task.schema";
|
|
3
|
+
import type { FrontendWorkflowStatus } from "./workflow-status";
|
|
4
|
+
export declare function createTaskId(title: string): string;
|
|
5
|
+
export declare function taskDir(projectRoot: string, taskId: string): string;
|
|
6
|
+
export declare function taskFile(projectRoot: string, taskId: string, fileName: string): string;
|
|
7
|
+
export declare function pendingWorkflowChecks(): WorkflowChecks;
|
|
8
|
+
export declare function readFrontendTask(project: ResolvedProjectRoot, taskId: string): Promise<FrontendTask>;
|
|
9
|
+
export declare function writeFrontendTask(project: ResolvedProjectRoot, task: FrontendTask): Promise<string>;
|
|
10
|
+
export declare function createFrontendTask(project: ResolvedProjectRoot, input: {
|
|
11
|
+
taskId?: string;
|
|
12
|
+
title: string;
|
|
13
|
+
description?: string;
|
|
14
|
+
}): Promise<{
|
|
15
|
+
status: "executed";
|
|
16
|
+
task: FrontendTask;
|
|
17
|
+
changedFiles: string[];
|
|
18
|
+
} | {
|
|
19
|
+
status: "blocked";
|
|
20
|
+
taskId: string;
|
|
21
|
+
reason: string;
|
|
22
|
+
}>;
|
|
23
|
+
export declare function updateTaskStatus(project: ResolvedProjectRoot, taskId: string, status: FrontendWorkflowStatus): Promise<FrontendTask>;
|
|
24
|
+
export declare function updateFrontendTask(project: ResolvedProjectRoot, taskId: string, patch: Partial<Omit<FrontendTask, "taskId" | "createdAt">>): Promise<FrontendTask>;
|
|
25
|
+
export declare function writeTaskMarkdown(project: ResolvedProjectRoot, taskId: string, fileName: string, content: string, nextStatus: FrontendWorkflowStatus): Promise<{
|
|
26
|
+
task: {
|
|
27
|
+
status: "failed" | "draft" | "context-ready" | "plan-ready" | "patch-ready" | "applied" | "verified" | "review-ready" | "delivered";
|
|
28
|
+
projectRoot: string;
|
|
29
|
+
changedFiles: string[];
|
|
30
|
+
taskId: string;
|
|
31
|
+
description: string;
|
|
32
|
+
createdAt: string;
|
|
33
|
+
updatedAt: string;
|
|
34
|
+
title: string;
|
|
35
|
+
designContextPath: string | null;
|
|
36
|
+
checks: {
|
|
37
|
+
standard: "warning" | "passed" | "failed" | "blocked" | "pending";
|
|
38
|
+
review: "warning" | "passed" | "failed" | "blocked" | "pending";
|
|
39
|
+
test: "warning" | "passed" | "failed" | "blocked" | "pending";
|
|
40
|
+
build: "warning" | "passed" | "failed" | "blocked" | "pending";
|
|
41
|
+
};
|
|
42
|
+
projectId?: string | undefined;
|
|
43
|
+
};
|
|
44
|
+
changedFiles: string[];
|
|
45
|
+
}>;
|
|
46
|
+
export declare function devPlanMarkdown(input: {
|
|
47
|
+
taskId: string;
|
|
48
|
+
title: string;
|
|
49
|
+
context?: string;
|
|
50
|
+
acceptance?: string[];
|
|
51
|
+
}): string;
|
|
52
|
+
export declare function deliveryReportMarkdown(input: {
|
|
53
|
+
taskId: string;
|
|
54
|
+
summary: string;
|
|
55
|
+
verification?: string[];
|
|
56
|
+
risks?: string[];
|
|
57
|
+
}): string;
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.createTaskId = createTaskId;
|
|
37
|
+
exports.taskDir = taskDir;
|
|
38
|
+
exports.taskFile = taskFile;
|
|
39
|
+
exports.pendingWorkflowChecks = pendingWorkflowChecks;
|
|
40
|
+
exports.readFrontendTask = readFrontendTask;
|
|
41
|
+
exports.writeFrontendTask = writeFrontendTask;
|
|
42
|
+
exports.createFrontendTask = createFrontendTask;
|
|
43
|
+
exports.updateTaskStatus = updateTaskStatus;
|
|
44
|
+
exports.updateFrontendTask = updateFrontendTask;
|
|
45
|
+
exports.writeTaskMarkdown = writeTaskMarkdown;
|
|
46
|
+
exports.devPlanMarkdown = devPlanMarkdown;
|
|
47
|
+
exports.deliveryReportMarkdown = deliveryReportMarkdown;
|
|
48
|
+
const fs = __importStar(require("fs/promises"));
|
|
49
|
+
const project_files_1 = require("../filesystem/project-files");
|
|
50
|
+
const frontend_task_schema_1 = require("./frontend-task.schema");
|
|
51
|
+
const workflow_transition_1 = require("./workflow-transition");
|
|
52
|
+
function timestampSlug(date = new Date()) {
|
|
53
|
+
const pad = (value) => String(value).padStart(2, "0");
|
|
54
|
+
return [
|
|
55
|
+
date.getFullYear(),
|
|
56
|
+
pad(date.getMonth() + 1),
|
|
57
|
+
pad(date.getDate()),
|
|
58
|
+
pad(date.getHours()),
|
|
59
|
+
pad(date.getMinutes()),
|
|
60
|
+
pad(date.getSeconds()),
|
|
61
|
+
].join("");
|
|
62
|
+
}
|
|
63
|
+
function slugify(value) {
|
|
64
|
+
return value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").slice(0, 32) || "task";
|
|
65
|
+
}
|
|
66
|
+
function createTaskId(title) {
|
|
67
|
+
return `fe-${timestampSlug()}-${slugify(title)}`;
|
|
68
|
+
}
|
|
69
|
+
function taskDir(projectRoot, taskId) {
|
|
70
|
+
(0, project_files_1.validateSafeId)("taskId", taskId);
|
|
71
|
+
return (0, project_files_1.resolveNgManagerPath)(projectRoot, "frontend-tasks", taskId);
|
|
72
|
+
}
|
|
73
|
+
function taskFile(projectRoot, taskId, fileName) {
|
|
74
|
+
(0, project_files_1.validateSafeId)("taskId", taskId);
|
|
75
|
+
(0, project_files_1.validateSafeId)("fileName", fileName.replace(/\.(json|md)$/, ""));
|
|
76
|
+
return (0, project_files_1.resolveNgManagerPath)(projectRoot, "frontend-tasks", taskId, fileName);
|
|
77
|
+
}
|
|
78
|
+
function pendingWorkflowChecks() {
|
|
79
|
+
return {
|
|
80
|
+
standard: "pending",
|
|
81
|
+
test: "pending",
|
|
82
|
+
review: "pending",
|
|
83
|
+
build: "pending",
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
async function readFrontendTask(project, taskId) {
|
|
87
|
+
const raw = await fs.readFile(taskFile(project.projectRoot, taskId, "task.json"), "utf-8");
|
|
88
|
+
return frontend_task_schema_1.frontendTaskSchema.parse(JSON.parse(raw));
|
|
89
|
+
}
|
|
90
|
+
async function writeFrontendTask(project, task) {
|
|
91
|
+
const filePath = taskFile(project.projectRoot, task.taskId, "task.json");
|
|
92
|
+
await (0, project_files_1.writeJsonFile)(filePath, task);
|
|
93
|
+
return (0, project_files_1.projectRelativePath)(project.projectRoot, filePath);
|
|
94
|
+
}
|
|
95
|
+
async function createFrontendTask(project, input) {
|
|
96
|
+
const now = new Date().toISOString();
|
|
97
|
+
const task = {
|
|
98
|
+
taskId: input.taskId || createTaskId(input.title),
|
|
99
|
+
status: "draft",
|
|
100
|
+
projectId: project.projectId,
|
|
101
|
+
projectRoot: project.projectRoot,
|
|
102
|
+
title: input.title,
|
|
103
|
+
description: input.description ?? "",
|
|
104
|
+
createdAt: now,
|
|
105
|
+
updatedAt: now,
|
|
106
|
+
designContextPath: null,
|
|
107
|
+
changedFiles: [],
|
|
108
|
+
checks: pendingWorkflowChecks(),
|
|
109
|
+
};
|
|
110
|
+
(0, project_files_1.validateSafeId)("taskId", task.taskId);
|
|
111
|
+
const dir = taskDir(project.projectRoot, task.taskId);
|
|
112
|
+
try {
|
|
113
|
+
await fs.access(taskFile(project.projectRoot, task.taskId, "task.json"));
|
|
114
|
+
return {
|
|
115
|
+
status: "blocked",
|
|
116
|
+
taskId: task.taskId,
|
|
117
|
+
reason: "frontend task already exists",
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
catch {
|
|
121
|
+
}
|
|
122
|
+
await fs.mkdir(dir, { recursive: true });
|
|
123
|
+
const changedFiles = [await writeFrontendTask(project, task)];
|
|
124
|
+
return { status: "executed", task, changedFiles };
|
|
125
|
+
}
|
|
126
|
+
async function updateTaskStatus(project, taskId, status) {
|
|
127
|
+
const task = await readFrontendTask(project, taskId);
|
|
128
|
+
(0, workflow_transition_1.assertWorkflowTransition)(task.status, status);
|
|
129
|
+
const updated = { ...task, status, updatedAt: new Date().toISOString() };
|
|
130
|
+
await writeFrontendTask(project, updated);
|
|
131
|
+
return updated;
|
|
132
|
+
}
|
|
133
|
+
async function updateFrontendTask(project, taskId, patch) {
|
|
134
|
+
const task = await readFrontendTask(project, taskId);
|
|
135
|
+
if (patch.status) {
|
|
136
|
+
(0, workflow_transition_1.assertWorkflowTransition)(task.status, patch.status);
|
|
137
|
+
}
|
|
138
|
+
const updated = frontend_task_schema_1.frontendTaskSchema.parse({
|
|
139
|
+
...task,
|
|
140
|
+
...patch,
|
|
141
|
+
taskId: task.taskId,
|
|
142
|
+
createdAt: task.createdAt,
|
|
143
|
+
updatedAt: new Date().toISOString(),
|
|
144
|
+
});
|
|
145
|
+
await writeFrontendTask(project, updated);
|
|
146
|
+
return updated;
|
|
147
|
+
}
|
|
148
|
+
async function writeTaskMarkdown(project, taskId, fileName, content, nextStatus) {
|
|
149
|
+
const current = await readFrontendTask(project, taskId);
|
|
150
|
+
(0, workflow_transition_1.assertWorkflowTransition)(current.status, nextStatus);
|
|
151
|
+
const filePath = taskFile(project.projectRoot, taskId, fileName);
|
|
152
|
+
await (0, project_files_1.writeTextFile)(filePath, content);
|
|
153
|
+
const task = await updateTaskStatus(project, taskId, nextStatus);
|
|
154
|
+
return {
|
|
155
|
+
task,
|
|
156
|
+
changedFiles: [
|
|
157
|
+
(0, project_files_1.projectRelativePath)(project.projectRoot, filePath),
|
|
158
|
+
(0, project_files_1.projectRelativePath)(project.projectRoot, taskFile(project.projectRoot, taskId, "task.json")),
|
|
159
|
+
],
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
function devPlanMarkdown(input) {
|
|
163
|
+
const lines = [
|
|
164
|
+
`# Dev Plan ${input.taskId}`,
|
|
165
|
+
"",
|
|
166
|
+
`## Title`,
|
|
167
|
+
input.title,
|
|
168
|
+
"",
|
|
169
|
+
"## Context",
|
|
170
|
+
input.context || "No design context provided.",
|
|
171
|
+
"",
|
|
172
|
+
"## Implementation",
|
|
173
|
+
"- Inspect related Angular routes, services, stores, and API clients.",
|
|
174
|
+
"- Make the smallest maintainable change that satisfies the task.",
|
|
175
|
+
"- Keep write/execute operations previewable and auditable when adding MCP behavior.",
|
|
176
|
+
"",
|
|
177
|
+
"## Acceptance",
|
|
178
|
+
...(input.acceptance?.length ? input.acceptance.map((item) => `- ${item}`) : ["- Relevant build or package tests pass.", "- Review checklist has no unresolved high-risk item."]),
|
|
179
|
+
];
|
|
180
|
+
return lines.join("\n");
|
|
181
|
+
}
|
|
182
|
+
function deliveryReportMarkdown(input) {
|
|
183
|
+
return [
|
|
184
|
+
`# Delivery Report ${input.taskId}`,
|
|
185
|
+
"",
|
|
186
|
+
"## Summary",
|
|
187
|
+
input.summary,
|
|
188
|
+
"",
|
|
189
|
+
"## Verification",
|
|
190
|
+
...(input.verification?.length ? input.verification.map((item) => `- ${item}`) : ["- Not recorded."]),
|
|
191
|
+
"",
|
|
192
|
+
"## Remaining Risks",
|
|
193
|
+
...(input.risks?.length ? input.risks.map((item) => `- ${item}`) : ["- No remaining risks recorded."]),
|
|
194
|
+
].join("\n");
|
|
195
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.frontendWorkflowStatuses = void 0;
|
|
4
|
+
exports.frontendWorkflowStatuses = [
|
|
5
|
+
"draft",
|
|
6
|
+
"context-ready",
|
|
7
|
+
"plan-ready",
|
|
8
|
+
"patch-ready",
|
|
9
|
+
"applied",
|
|
10
|
+
"verified",
|
|
11
|
+
"review-ready",
|
|
12
|
+
"delivered",
|
|
13
|
+
"failed",
|
|
14
|
+
];
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { FrontendWorkflowStatus } from "./workflow-status";
|
|
2
|
+
export declare class WorkflowTransitionError extends Error {
|
|
3
|
+
readonly from: FrontendWorkflowStatus;
|
|
4
|
+
readonly to: FrontendWorkflowStatus;
|
|
5
|
+
constructor(from: FrontendWorkflowStatus, to: FrontendWorkflowStatus);
|
|
6
|
+
}
|
|
7
|
+
export declare function canTransitionWorkflowStatus(from: FrontendWorkflowStatus, to: FrontendWorkflowStatus): boolean;
|
|
8
|
+
export declare function assertWorkflowTransition(from: FrontendWorkflowStatus, to: FrontendWorkflowStatus): void;
|
|
9
|
+
export declare function workflowTransitionReason(from: FrontendWorkflowStatus, to: FrontendWorkflowStatus): string;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.WorkflowTransitionError = void 0;
|
|
4
|
+
exports.canTransitionWorkflowStatus = canTransitionWorkflowStatus;
|
|
5
|
+
exports.assertWorkflowTransition = assertWorkflowTransition;
|
|
6
|
+
exports.workflowTransitionReason = workflowTransitionReason;
|
|
7
|
+
class WorkflowTransitionError extends Error {
|
|
8
|
+
constructor(from, to) {
|
|
9
|
+
super(`Illegal workflow status transition: ${from} -> ${to}`);
|
|
10
|
+
this.from = from;
|
|
11
|
+
this.to = to;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
exports.WorkflowTransitionError = WorkflowTransitionError;
|
|
15
|
+
const allowedTransitions = {
|
|
16
|
+
draft: ["context-ready", "plan-ready", "failed"],
|
|
17
|
+
"context-ready": ["plan-ready", "failed"],
|
|
18
|
+
"plan-ready": ["patch-ready", "applied", "failed"],
|
|
19
|
+
"patch-ready": ["applied", "failed"],
|
|
20
|
+
applied: ["verified", "failed"],
|
|
21
|
+
verified: ["review-ready", "delivered", "failed"],
|
|
22
|
+
"review-ready": ["delivered", "failed"],
|
|
23
|
+
delivered: [],
|
|
24
|
+
failed: ["draft"],
|
|
25
|
+
};
|
|
26
|
+
function canTransitionWorkflowStatus(from, to) {
|
|
27
|
+
if (from === to)
|
|
28
|
+
return true;
|
|
29
|
+
return allowedTransitions[from].includes(to);
|
|
30
|
+
}
|
|
31
|
+
function assertWorkflowTransition(from, to) {
|
|
32
|
+
if (!canTransitionWorkflowStatus(from, to)) {
|
|
33
|
+
throw new WorkflowTransitionError(from, to);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function workflowTransitionReason(from, to) {
|
|
37
|
+
return `illegal workflow status transition: ${from} -> ${to}`;
|
|
38
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yinuo-ngm/mcp-server",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "Local MCP stdio server for ng-manager core capabilities.",
|
|
5
5
|
"author": "ZhangJing <892295834@qq.com>",
|
|
6
6
|
"license": "ISC",
|
|
@@ -25,13 +25,15 @@
|
|
|
25
25
|
"inspect": "npm run build && mcp-inspector node lib/index.js",
|
|
26
26
|
"inspect:dev": "mcp-inspector tsx src/index.ts",
|
|
27
27
|
"dev": "tsx watch src/index.ts",
|
|
28
|
-
"build": "tsc -b tsconfig.json",
|
|
28
|
+
"build": "rimraf lib tsconfig.tsbuildinfo && tsc -b tsconfig.json",
|
|
29
|
+
"lint:tool-names": "tsx scripts/lint-tool-names.ts",
|
|
29
30
|
"test": "npm run build && node --test test",
|
|
30
31
|
"start": "node lib/index.js"
|
|
31
32
|
},
|
|
32
33
|
"dependencies": {
|
|
33
34
|
"@modelcontextprotocol/sdk": "^1.26.0",
|
|
34
35
|
"@yinuo-ngm/core": "^0.1.15",
|
|
36
|
+
"@yinuo-ngm/runtime": "^0.1.3",
|
|
35
37
|
"zod": "^3.25.76"
|
|
36
38
|
},
|
|
37
39
|
"devDependencies": {
|
|
@@ -41,5 +43,5 @@
|
|
|
41
43
|
"publishConfig": {
|
|
42
44
|
"access": "public"
|
|
43
45
|
},
|
|
44
|
-
"gitHead": "
|
|
46
|
+
"gitHead": "425cb641977ad61c5f535a068f736b8970f79086"
|
|
45
47
|
}
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
export type HubV2ProjectConfig = {
|
|
2
|
-
name?: string;
|
|
3
|
-
alias?: string;
|
|
4
|
-
id?: string;
|
|
5
|
-
base_url?: string;
|
|
6
|
-
project_key?: string;
|
|
7
|
-
project_name?: string;
|
|
8
|
-
project_token?: string;
|
|
9
|
-
personal_token?: string;
|
|
10
|
-
source?: string;
|
|
11
|
-
};
|
|
12
|
-
export type HubV2Config = HubV2ProjectConfig & {
|
|
13
|
-
default_project?: string;
|
|
14
|
-
projects?: Record<string, HubV2ProjectConfig>;
|
|
15
|
-
};
|
|
16
|
-
export type HubV2ResolveOptions = {
|
|
17
|
-
project?: string;
|
|
18
|
-
projectKey?: string;
|
|
19
|
-
};
|
|
20
|
-
export type HubV2ResolvedContext = {
|
|
21
|
-
baseUrl: string;
|
|
22
|
-
projectKey: string;
|
|
23
|
-
token: string;
|
|
24
|
-
source: string;
|
|
25
|
-
};
|
|
26
|
-
type TokenKind = "project" | "personal";
|
|
27
|
-
export declare function parseJsonObject(content: string): Record<string, unknown>;
|
|
28
|
-
export declare function loadJsonFile(path: string): Record<string, unknown>;
|
|
29
|
-
export declare function normalizeConfig(rawValue: unknown): HubV2Config;
|
|
30
|
-
export declare function loadConfig(pathValue?: string): HubV2Config;
|
|
31
|
-
export declare function resolveHubV2Context(options: HubV2ResolveOptions, tokenKind: TokenKind, pathValue?: string): HubV2ResolvedContext;
|
|
32
|
-
export declare function listConfiguredProjects(project?: string, pathValue?: string): Record<string, unknown>;
|
|
33
|
-
export declare function getConfiguredProject(options: HubV2ResolveOptions, pathValue?: string): Record<string, unknown>;
|
|
34
|
-
export {};
|
|
@@ -1,297 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.parseJsonObject = parseJsonObject;
|
|
4
|
-
exports.loadJsonFile = loadJsonFile;
|
|
5
|
-
exports.normalizeConfig = normalizeConfig;
|
|
6
|
-
exports.loadConfig = loadConfig;
|
|
7
|
-
exports.resolveHubV2Context = resolveHubV2Context;
|
|
8
|
-
exports.listConfiguredProjects = listConfiguredProjects;
|
|
9
|
-
exports.getConfiguredProject = getConfiguredProject;
|
|
10
|
-
const fs_1 = require("fs");
|
|
11
|
-
const os_1 = require("os");
|
|
12
|
-
const path_1 = require("path");
|
|
13
|
-
function asRecord(value) {
|
|
14
|
-
return value && typeof value === "object" && !Array.isArray(value)
|
|
15
|
-
? value
|
|
16
|
-
: {};
|
|
17
|
-
}
|
|
18
|
-
function getString(record, ...keys) {
|
|
19
|
-
for (const key of keys) {
|
|
20
|
-
const value = record[key];
|
|
21
|
-
if (value !== undefined && value !== null && String(value).trim()) {
|
|
22
|
-
return String(value).trim();
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
return undefined;
|
|
26
|
-
}
|
|
27
|
-
function putIfValue(target, key, value) {
|
|
28
|
-
if (value !== undefined && value !== null && String(value).trim()) {
|
|
29
|
-
target[key] = String(value).trim();
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
function envValue(...names) {
|
|
33
|
-
for (const name of names) {
|
|
34
|
-
const value = process.env[name];
|
|
35
|
-
if (value !== undefined && value !== null && String(value).trim()) {
|
|
36
|
-
return String(value).trim();
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
return undefined;
|
|
40
|
-
}
|
|
41
|
-
function stripJsonComments(input) {
|
|
42
|
-
let output = "";
|
|
43
|
-
let inString = false;
|
|
44
|
-
let stringQuote = "";
|
|
45
|
-
let escaped = false;
|
|
46
|
-
for (let index = 0; index < input.length; index += 1) {
|
|
47
|
-
const char = input[index];
|
|
48
|
-
const next = input[index + 1];
|
|
49
|
-
if (inString) {
|
|
50
|
-
output += char;
|
|
51
|
-
if (escaped) {
|
|
52
|
-
escaped = false;
|
|
53
|
-
}
|
|
54
|
-
else if (char === "\\") {
|
|
55
|
-
escaped = true;
|
|
56
|
-
}
|
|
57
|
-
else if (char === stringQuote) {
|
|
58
|
-
inString = false;
|
|
59
|
-
}
|
|
60
|
-
continue;
|
|
61
|
-
}
|
|
62
|
-
if (char === '"' || char === "'") {
|
|
63
|
-
inString = true;
|
|
64
|
-
stringQuote = char;
|
|
65
|
-
output += char;
|
|
66
|
-
continue;
|
|
67
|
-
}
|
|
68
|
-
if (char === "/" && next === "/") {
|
|
69
|
-
while (index < input.length && input[index] !== "\n") {
|
|
70
|
-
index += 1;
|
|
71
|
-
}
|
|
72
|
-
output += "\n";
|
|
73
|
-
continue;
|
|
74
|
-
}
|
|
75
|
-
if (char === "/" && next === "*") {
|
|
76
|
-
index += 2;
|
|
77
|
-
while (index < input.length && !(input[index] === "*" && input[index + 1] === "/")) {
|
|
78
|
-
index += 1;
|
|
79
|
-
}
|
|
80
|
-
index += 1;
|
|
81
|
-
continue;
|
|
82
|
-
}
|
|
83
|
-
output += char;
|
|
84
|
-
}
|
|
85
|
-
return output;
|
|
86
|
-
}
|
|
87
|
-
function parseJsonObject(content) {
|
|
88
|
-
const parsed = JSON.parse(stripJsonComments(content));
|
|
89
|
-
return asRecord(parsed);
|
|
90
|
-
}
|
|
91
|
-
function loadJsonFile(path) {
|
|
92
|
-
if (!(0, fs_1.existsSync)(path)) {
|
|
93
|
-
return {};
|
|
94
|
-
}
|
|
95
|
-
return parseJsonObject((0, fs_1.readFileSync)(path, "utf8"));
|
|
96
|
-
}
|
|
97
|
-
function mergeHubObject(target, value) {
|
|
98
|
-
const source = asRecord(value);
|
|
99
|
-
putIfValue(target, "base_url", getString(source, "base_url", "baseUrl"));
|
|
100
|
-
putIfValue(target, "project_key", getString(source, "project_key", "projectKey"));
|
|
101
|
-
putIfValue(target, "project_name", getString(source, "project_name", "projectName"));
|
|
102
|
-
putIfValue(target, "project_token", getString(source, "project_token", "projectToken", "token"));
|
|
103
|
-
putIfValue(target, "personal_token", getString(source, "personal_token", "personalToken"));
|
|
104
|
-
putIfValue(target, "source", getString(source, "source"));
|
|
105
|
-
putIfValue(target, "default_project", getString(source, "default_project", "defaultProject", "project"));
|
|
106
|
-
}
|
|
107
|
-
function mergeEnvObject(target, value) {
|
|
108
|
-
const env = asRecord(value);
|
|
109
|
-
putIfValue(target, "base_url", getString(env, "HUB_V2_BASE_URL"));
|
|
110
|
-
putIfValue(target, "project_key", getString(env, "HUB_V2_PROJECT_KEY"));
|
|
111
|
-
putIfValue(target, "project_token", getString(env, "HUB_V2_PROJECT_TOKEN"));
|
|
112
|
-
putIfValue(target, "personal_token", getString(env, "HUB_V2_PERSONAL_TOKEN"));
|
|
113
|
-
putIfValue(target, "source", getString(env, "HUB_V2_SOURCE"));
|
|
114
|
-
putIfValue(target, "default_project", getString(env, "HUB_V2_PROJECT"));
|
|
115
|
-
}
|
|
116
|
-
function normalizeProject(raw) {
|
|
117
|
-
const config = normalizeConfig(raw);
|
|
118
|
-
const record = asRecord(raw);
|
|
119
|
-
putIfValue(config, "name", record.name);
|
|
120
|
-
putIfValue(config, "alias", record.alias);
|
|
121
|
-
putIfValue(config, "id", record.id);
|
|
122
|
-
delete config.projects;
|
|
123
|
-
delete config.default_project;
|
|
124
|
-
return config;
|
|
125
|
-
}
|
|
126
|
-
function normalizeProjects(raw) {
|
|
127
|
-
const value = raw.projects;
|
|
128
|
-
const projects = {};
|
|
129
|
-
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
130
|
-
for (const [name, projectValue] of Object.entries(value)) {
|
|
131
|
-
const project = normalizeProject(projectValue);
|
|
132
|
-
const projectName = project.name ?? project.alias ?? name.trim();
|
|
133
|
-
if (projectName) {
|
|
134
|
-
projects[projectName] = project;
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
if (Array.isArray(value)) {
|
|
139
|
-
for (const projectValue of value) {
|
|
140
|
-
const project = normalizeProject(projectValue);
|
|
141
|
-
const projectName = project.name ?? project.alias ?? project.id;
|
|
142
|
-
if (projectName) {
|
|
143
|
-
projects[projectName] = project;
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
return projects;
|
|
148
|
-
}
|
|
149
|
-
function mergeProjects(...maps) {
|
|
150
|
-
const merged = {};
|
|
151
|
-
for (const map of maps) {
|
|
152
|
-
for (const [name, project] of Object.entries(map)) {
|
|
153
|
-
merged[name] = { ...(merged[name] ?? {}), ...project };
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
return merged;
|
|
157
|
-
}
|
|
158
|
-
function normalizeConfig(rawValue) {
|
|
159
|
-
const raw = asRecord(rawValue);
|
|
160
|
-
const normalized = {};
|
|
161
|
-
mergeHubObject(normalized, raw);
|
|
162
|
-
mergeHubObject(normalized, raw.hubV2);
|
|
163
|
-
mergeEnvObject(normalized, raw.env);
|
|
164
|
-
const projects = mergeProjects(normalizeProjects(raw), normalizeProjects(asRecord(raw.hubV2)));
|
|
165
|
-
if (Object.keys(projects).length) {
|
|
166
|
-
normalized.projects = projects;
|
|
167
|
-
}
|
|
168
|
-
return normalized;
|
|
169
|
-
}
|
|
170
|
-
function configSearchPaths() {
|
|
171
|
-
const envConfig = envValue("HUB_V2_CONFIG");
|
|
172
|
-
if (envConfig) {
|
|
173
|
-
return [(0, path_1.resolve)(envConfig)];
|
|
174
|
-
}
|
|
175
|
-
return [(0, path_1.join)((0, os_1.homedir)(), ".ng-manager", "agent-connections.json")];
|
|
176
|
-
}
|
|
177
|
-
function loadConfig(pathValue) {
|
|
178
|
-
const paths = pathValue ? [(0, path_1.resolve)(pathValue)] : configSearchPaths();
|
|
179
|
-
for (const path of paths) {
|
|
180
|
-
const config = normalizeConfig(loadJsonFile(path));
|
|
181
|
-
if (Object.keys(config).length) {
|
|
182
|
-
return config;
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
return {};
|
|
186
|
-
}
|
|
187
|
-
function selectedProjectConfig(config, options) {
|
|
188
|
-
const projects = config.projects ?? {};
|
|
189
|
-
const entries = Object.entries(projects);
|
|
190
|
-
if (!entries.length) {
|
|
191
|
-
return {};
|
|
192
|
-
}
|
|
193
|
-
const selected = options.project ?? envValue("HUB_V2_PROJECT") ?? config.default_project;
|
|
194
|
-
if (selected) {
|
|
195
|
-
const project = projects[selected];
|
|
196
|
-
if (!project) {
|
|
197
|
-
throw new Error(`project config not found: ${selected}. Available projects: ${entries.map(([name]) => name).sort().join(", ")}`);
|
|
198
|
-
}
|
|
199
|
-
return project;
|
|
200
|
-
}
|
|
201
|
-
if (entries.length === 1) {
|
|
202
|
-
return entries[0][1];
|
|
203
|
-
}
|
|
204
|
-
throw new Error(`multiple projects configured; pass project. Available projects: ${entries.map(([name]) => name).sort().join(", ")}`);
|
|
205
|
-
}
|
|
206
|
-
function configValue(config, projectConfig, key) {
|
|
207
|
-
return projectConfig[key] ?? config[key];
|
|
208
|
-
}
|
|
209
|
-
function resolveHubV2Context(options, tokenKind, pathValue) {
|
|
210
|
-
const config = loadConfig(pathValue);
|
|
211
|
-
const projectConfig = selectedProjectConfig(config, options);
|
|
212
|
-
const baseUrl = (envValue("HUB_V2_BASE_URL") ??
|
|
213
|
-
configValue(config, projectConfig, "base_url"))?.replace(/\/+$/, "");
|
|
214
|
-
const projectKey = options.projectKey ??
|
|
215
|
-
envValue("HUB_V2_PROJECT_KEY") ??
|
|
216
|
-
configValue(config, projectConfig, "project_key");
|
|
217
|
-
const projectToken = envValue("HUB_V2_PROJECT_TOKEN") ??
|
|
218
|
-
configValue(config, projectConfig, "project_token");
|
|
219
|
-
const personalToken = envValue("HUB_V2_PERSONAL_TOKEN") ??
|
|
220
|
-
configValue(config, projectConfig, "personal_token");
|
|
221
|
-
const source = envValue("HUB_V2_SOURCE") ??
|
|
222
|
-
configValue(config, projectConfig, "source") ??
|
|
223
|
-
"ngm-mcp";
|
|
224
|
-
if (!baseUrl) {
|
|
225
|
-
throw new Error("HUB_V2_BASE_URL is required");
|
|
226
|
-
}
|
|
227
|
-
if (!projectKey) {
|
|
228
|
-
throw new Error("HUB_V2_PROJECT_KEY is required");
|
|
229
|
-
}
|
|
230
|
-
const token = tokenKind === "project" ? projectToken : personalToken;
|
|
231
|
-
if (!token) {
|
|
232
|
-
throw new Error(tokenKind === "project" ? "HUB_V2_PROJECT_TOKEN is required" : "HUB_V2_PERSONAL_TOKEN is required");
|
|
233
|
-
}
|
|
234
|
-
return { baseUrl, projectKey, token, source };
|
|
235
|
-
}
|
|
236
|
-
function projectSummary(name, config, project) {
|
|
237
|
-
return {
|
|
238
|
-
name,
|
|
239
|
-
projectName: project.project_name,
|
|
240
|
-
projectKey: project.project_key,
|
|
241
|
-
baseUrl: project.base_url ?? config.base_url,
|
|
242
|
-
hasProjectToken: Boolean(project.project_token ?? config.project_token),
|
|
243
|
-
hasPersonalToken: Boolean(project.personal_token ?? config.personal_token),
|
|
244
|
-
isDefault: name === config.default_project,
|
|
245
|
-
};
|
|
246
|
-
}
|
|
247
|
-
function listConfiguredProjects(project, pathValue) {
|
|
248
|
-
const config = loadConfig(pathValue);
|
|
249
|
-
const envProjectKey = envValue("HUB_V2_PROJECT_KEY") ?? config.project_key;
|
|
250
|
-
let items;
|
|
251
|
-
if (envProjectKey) {
|
|
252
|
-
items = [
|
|
253
|
-
{
|
|
254
|
-
name: envValue("HUB_V2_PROJECT") ?? config.default_project ?? "default",
|
|
255
|
-
projectName: config.project_name,
|
|
256
|
-
projectKey: envProjectKey,
|
|
257
|
-
baseUrl: envValue("HUB_V2_BASE_URL") ?? config.base_url,
|
|
258
|
-
hasProjectToken: Boolean(envValue("HUB_V2_PROJECT_TOKEN") ?? config.project_token),
|
|
259
|
-
hasPersonalToken: Boolean(envValue("HUB_V2_PERSONAL_TOKEN") ?? config.personal_token),
|
|
260
|
-
isDefault: true,
|
|
261
|
-
},
|
|
262
|
-
];
|
|
263
|
-
}
|
|
264
|
-
else {
|
|
265
|
-
const projects = config.projects ?? {};
|
|
266
|
-
items = Object.entries(projects).map(([name, item]) => projectSummary(name, config, item));
|
|
267
|
-
}
|
|
268
|
-
const filtered = project
|
|
269
|
-
? items.filter((item) => item.name === project || item.projectName === project || item.projectKey === project)
|
|
270
|
-
: items;
|
|
271
|
-
return {
|
|
272
|
-
items: filtered,
|
|
273
|
-
total: filtered.length,
|
|
274
|
-
};
|
|
275
|
-
}
|
|
276
|
-
function getConfiguredProject(options, pathValue) {
|
|
277
|
-
const config = loadConfig(pathValue);
|
|
278
|
-
const selected = options.project ?? options.projectKey ?? envValue("HUB_V2_PROJECT") ?? config.default_project;
|
|
279
|
-
if (selected) {
|
|
280
|
-
const projects = listConfiguredProjects(selected, pathValue).items;
|
|
281
|
-
if (projects.length === 1) {
|
|
282
|
-
return projects[0];
|
|
283
|
-
}
|
|
284
|
-
if (!projects.length) {
|
|
285
|
-
throw new Error("Hub V2 project config not found");
|
|
286
|
-
}
|
|
287
|
-
throw new Error("multiple Hub V2 project configs matched");
|
|
288
|
-
}
|
|
289
|
-
const projects = listConfiguredProjects(options.project ?? options.projectKey, pathValue).items;
|
|
290
|
-
if (projects.length === 1) {
|
|
291
|
-
return projects[0];
|
|
292
|
-
}
|
|
293
|
-
if (!projects.length) {
|
|
294
|
-
throw new Error("Hub V2 project config not found");
|
|
295
|
-
}
|
|
296
|
-
throw new Error("multiple Hub V2 project configs matched");
|
|
297
|
-
}
|