@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.
Files changed (214) hide show
  1. package/README.md +191 -208
  2. package/lib/audit/audit-event.d.ts +14 -0
  3. package/lib/audit/audit-event.js +2 -0
  4. package/lib/audit/audit-log.service.d.ts +7 -0
  5. package/lib/audit/audit-log.service.js +187 -0
  6. package/lib/audit/redact.d.ts +3 -0
  7. package/lib/audit/redact.js +28 -0
  8. package/lib/catalog/capabilities/blocked-local-actions.d.ts +1 -0
  9. package/lib/catalog/capabilities/blocked-local-actions.js +18 -0
  10. package/lib/catalog/capabilities/frontend-standard.d.ts +2 -0
  11. package/lib/catalog/capabilities/frontend-standard.js +36 -0
  12. package/lib/catalog/capabilities/hub-v2.d.ts +2 -0
  13. package/lib/catalog/capabilities/hub-v2.js +34 -0
  14. package/lib/catalog/capabilities/nginx.d.ts +2 -0
  15. package/lib/catalog/capabilities/nginx.js +23 -0
  16. package/lib/catalog/capabilities/project.d.ts +2 -0
  17. package/lib/catalog/capabilities/project.js +23 -0
  18. package/lib/catalog/capabilities/router.d.ts +2 -0
  19. package/lib/catalog/capabilities/router.js +11 -0
  20. package/lib/catalog/capabilities/runtime.d.ts +2 -0
  21. package/lib/catalog/capabilities/runtime.js +17 -0
  22. package/lib/catalog/capabilities/workspace.d.ts +2 -0
  23. package/lib/catalog/capabilities/workspace.js +23 -0
  24. package/lib/catalog/helpers.d.ts +3 -0
  25. package/lib/catalog/helpers.js +42 -0
  26. package/lib/catalog/index.d.ts +4 -0
  27. package/lib/catalog/index.js +23 -0
  28. package/lib/catalog/tools/frontend-standard.d.ts +2 -0
  29. package/lib/catalog/tools/frontend-standard.js +166 -0
  30. package/lib/catalog/tools/hub-v2-api.d.ts +2 -0
  31. package/lib/catalog/tools/hub-v2-api.js +124 -0
  32. package/lib/catalog/tools/hub-v2-docs.d.ts +2 -0
  33. package/lib/catalog/tools/hub-v2-docs.js +40 -0
  34. package/lib/catalog/tools/nginx.d.ts +2 -0
  35. package/lib/catalog/tools/nginx.js +96 -0
  36. package/lib/catalog/tools/project.d.ts +2 -0
  37. package/lib/catalog/tools/project.js +138 -0
  38. package/lib/catalog/tools/router.d.ts +2 -0
  39. package/lib/catalog/tools/router.js +26 -0
  40. package/lib/catalog/tools/runtime.d.ts +2 -0
  41. package/lib/catalog/tools/runtime.js +47 -0
  42. package/lib/catalog/tools/workspace.d.ts +2 -0
  43. package/lib/catalog/tools/workspace.js +75 -0
  44. package/lib/catalog/types.d.ts +15 -0
  45. package/lib/catalog/types.js +2 -0
  46. package/lib/context/create-tool-context.js +11 -10
  47. package/lib/context/local-server-client.d.ts +2 -0
  48. package/lib/context/local-server-client.js +174 -0
  49. package/lib/context/tool-context.d.ts +36 -0
  50. package/lib/doctor.d.ts +8 -0
  51. package/lib/doctor.js +221 -0
  52. package/lib/errors/error-codes.d.ts +12 -0
  53. package/lib/errors/error-codes.js +14 -0
  54. package/lib/errors/mcp-tool-error.d.ts +8 -0
  55. package/lib/errors/mcp-tool-error.js +14 -0
  56. package/lib/filesystem/project-files.d.ts +18 -0
  57. package/lib/filesystem/project-files.js +112 -0
  58. package/lib/git/local-git-read-service.d.ts +2 -0
  59. package/lib/git/local-git-read-service.js +96 -0
  60. package/lib/index.d.ts +1 -0
  61. package/lib/index.js +4 -0
  62. package/lib/policy/assert-tool-policy.js +10 -1
  63. package/lib/register-tools.js +67 -10
  64. package/lib/registry/tool-names.d.ts +95 -0
  65. package/lib/registry/tool-names.js +97 -0
  66. package/lib/services/path-guard.service.d.ts +4 -0
  67. package/lib/services/path-guard.service.js +75 -0
  68. package/lib/services/permission.service.d.ts +5 -0
  69. package/lib/services/permission.service.js +38 -0
  70. package/lib/services/project-resolver.service.d.ts +32 -0
  71. package/lib/services/project-resolver.service.js +95 -0
  72. package/lib/standard/frontend-standard.default.d.ts +2 -0
  73. package/lib/standard/frontend-standard.default.js +51 -0
  74. package/lib/standard/frontend-standard.schema.d.ts +196 -0
  75. package/lib/standard/frontend-standard.schema.js +61 -0
  76. package/lib/standard/frontend-standard.service.d.ts +79 -0
  77. package/lib/standard/frontend-standard.service.js +115 -0
  78. package/lib/standard/project-scan.d.ts +9 -0
  79. package/lib/standard/project-scan.js +91 -0
  80. package/lib/standard/validators/angular-structure.validator.d.ts +4 -0
  81. package/lib/standard/validators/angular-structure.validator.js +75 -0
  82. package/lib/standard/validators/component.validator.d.ts +4 -0
  83. package/lib/standard/validators/component.validator.js +94 -0
  84. package/lib/standard/validators/git.validator.d.ts +8 -0
  85. package/lib/standard/validators/git.validator.js +32 -0
  86. package/lib/standard/validators/review.validator.d.ts +15 -0
  87. package/lib/standard/validators/review.validator.js +67 -0
  88. package/lib/standard/validators/test.validator.d.ts +19 -0
  89. package/lib/standard/validators/test.validator.js +89 -0
  90. package/lib/tool-catalog.d.ts +2 -0
  91. package/lib/tool-catalog.js +6 -0
  92. package/lib/tools/angular/angular-standard.tools.d.ts +2 -0
  93. package/lib/tools/angular/angular-standard.tools.js +53 -0
  94. package/lib/tools/angular/index.d.ts +1 -0
  95. package/lib/tools/angular/index.js +5 -0
  96. package/lib/tools/capability.tools.d.ts +2 -0
  97. package/lib/tools/capability.tools.js +205 -0
  98. package/lib/tools/controlled/index.d.ts +2 -0
  99. package/lib/tools/controlled/index.js +13 -0
  100. package/lib/tools/controlled/local-server.d.ts +6 -0
  101. package/lib/tools/controlled/local-server.js +17 -0
  102. package/lib/tools/controlled/operation-policy.d.ts +22 -0
  103. package/lib/tools/controlled/operation-policy.js +50 -0
  104. package/lib/tools/controlled/operation-result.d.ts +30 -0
  105. package/lib/tools/controlled/operation-result.js +33 -0
  106. package/lib/tools/controlled/schemas.d.ts +159 -0
  107. package/lib/tools/controlled/schemas.js +49 -0
  108. package/lib/tools/controlled.tools.d.ts +1 -0
  109. package/lib/tools/controlled.tools.js +5 -0
  110. package/lib/tools/file-write.tools.d.ts +2 -0
  111. package/lib/tools/file-write.tools.js +70 -0
  112. package/lib/tools/git.tools.js +109 -8
  113. package/lib/tools/hub-v2/client.d.ts +6 -1
  114. package/lib/tools/hub-v2/client.js +15 -0
  115. package/lib/tools/hub-v2/config/config-paths.d.ts +2 -0
  116. package/lib/tools/hub-v2/config/config-paths.js +17 -0
  117. package/lib/tools/hub-v2/config/env.d.ts +1 -0
  118. package/lib/tools/hub-v2/config/env.js +12 -0
  119. package/lib/tools/hub-v2/config/index.d.ts +8 -0
  120. package/lib/tools/hub-v2/config/index.js +18 -0
  121. package/lib/tools/hub-v2/config/jsonc.d.ts +5 -0
  122. package/lib/tools/hub-v2/config/jsonc.js +86 -0
  123. package/lib/tools/hub-v2/config/load-config.d.ts +18 -0
  124. package/lib/tools/hub-v2/config/load-config.js +93 -0
  125. package/lib/tools/hub-v2/config/project-selector.d.ts +5 -0
  126. package/lib/tools/hub-v2/config/project-selector.js +92 -0
  127. package/lib/tools/hub-v2/config/resolve-context.d.ts +13 -0
  128. package/lib/tools/hub-v2/config/resolve-context.js +33 -0
  129. package/lib/tools/hub-v2/docs.tools.js +138 -4
  130. package/lib/tools/hub-v2/index.js +2 -0
  131. package/lib/tools/hub-v2/issues-workflow.tools.d.ts +2 -0
  132. package/lib/tools/hub-v2/issues-workflow.tools.js +199 -0
  133. package/lib/tools/hub-v2/issues.tools.js +96 -6
  134. package/lib/tools/hub-v2/projects.tools.js +16 -3
  135. package/lib/tools/hub-v2/raw.d.ts +8 -0
  136. package/lib/tools/hub-v2/raw.js +33 -0
  137. package/lib/tools/hub-v2/rd.tools.js +167 -8
  138. package/lib/tools/hub-v2/schemas.d.ts +668 -71
  139. package/lib/tools/hub-v2/schemas.js +152 -1
  140. package/lib/tools/hub-v2/upload.tools.js +53 -5
  141. package/lib/tools/index.d.ts +1 -0
  142. package/lib/tools/index.js +22 -0
  143. package/lib/tools/log.tools.js +33 -6
  144. package/lib/tools/nginx/index.d.ts +1 -0
  145. package/lib/tools/nginx/index.js +5 -0
  146. package/lib/tools/nginx/nginx-control.tools.d.ts +2 -0
  147. package/lib/tools/nginx/nginx-control.tools.js +133 -0
  148. package/lib/tools/nginx/nginx-proxy.d.ts +24 -0
  149. package/lib/tools/nginx/nginx-proxy.js +154 -0
  150. package/lib/tools/nginx.tools.d.ts +2 -0
  151. package/lib/tools/nginx.tools.js +111 -0
  152. package/lib/tools/project/index.d.ts +2 -0
  153. package/lib/tools/project/index.js +7 -0
  154. package/lib/tools/project/launch-status.d.ts +10 -0
  155. package/lib/tools/project/launch-status.js +78 -0
  156. package/lib/tools/project/local-diagnostics.d.ts +19 -0
  157. package/lib/tools/project/local-diagnostics.js +97 -0
  158. package/lib/tools/project/observe-redaction.d.ts +3 -0
  159. package/lib/tools/project/observe-redaction.js +25 -0
  160. package/lib/tools/project/observe-runtime.d.ts +72 -0
  161. package/lib/tools/project/observe-runtime.js +147 -0
  162. package/lib/tools/project/project-control.tools.d.ts +2 -0
  163. package/lib/tools/project/project-control.tools.js +216 -0
  164. package/lib/tools/project/project-observe.tools.d.ts +2 -0
  165. package/lib/tools/project/project-observe.tools.js +191 -0
  166. package/lib/tools/project/runtime-config.d.ts +7 -0
  167. package/lib/tools/project/runtime-config.js +50 -0
  168. package/lib/tools/project-observe.tools.d.ts +1 -0
  169. package/lib/tools/project-observe.tools.js +5 -0
  170. package/lib/tools/project.tools.d.ts +8 -0
  171. package/lib/tools/project.tools.js +97 -6
  172. package/lib/tools/proxy.tools.js +4 -4
  173. package/lib/tools/review/index.d.ts +1 -0
  174. package/lib/tools/review/index.js +5 -0
  175. package/lib/tools/review/review.tools.d.ts +2 -0
  176. package/lib/tools/review/review.tools.js +152 -0
  177. package/lib/tools/runtime/index.d.ts +1 -0
  178. package/lib/tools/runtime/index.js +5 -0
  179. package/lib/tools/runtime/runtime-control.tools.d.ts +2 -0
  180. package/lib/tools/runtime/runtime-control.tools.js +89 -0
  181. package/lib/tools/runtime.tools.js +41 -4
  182. package/lib/tools/standard/index.d.ts +1 -0
  183. package/lib/tools/standard/index.js +5 -0
  184. package/lib/tools/standard/standard.tools.d.ts +2 -0
  185. package/lib/tools/standard/standard.tools.js +91 -0
  186. package/lib/tools/task.tools.js +44 -9
  187. package/lib/tools/test/index.d.ts +1 -0
  188. package/lib/tools/test/index.js +5 -0
  189. package/lib/tools/test/test-standard.tools.d.ts +2 -0
  190. package/lib/tools/test/test-standard.tools.js +51 -0
  191. package/lib/tools/tool-catalog.d.ts +2 -0
  192. package/lib/tools/tool-catalog.js +7 -0
  193. package/lib/tools/workflow/frontend-workflow.tools.d.ts +2 -0
  194. package/lib/tools/workflow/frontend-workflow.tools.js +364 -0
  195. package/lib/tools/workflow/index.d.ts +1 -0
  196. package/lib/tools/workflow/index.js +5 -0
  197. package/lib/tools/workspace-package.d.ts +22 -0
  198. package/lib/tools/workspace-package.js +130 -0
  199. package/lib/tools/workspace.tools.d.ts +7 -0
  200. package/lib/tools/workspace.tools.js +336 -0
  201. package/lib/utils/errors.js +6 -1
  202. package/lib/utils/result.d.ts +9 -0
  203. package/lib/utils/result.js +9 -0
  204. package/lib/workflow/frontend-task.schema.d.ts +83 -0
  205. package/lib/workflow/frontend-task.schema.js +25 -0
  206. package/lib/workflow/frontend-task.service.d.ts +57 -0
  207. package/lib/workflow/frontend-task.service.js +195 -0
  208. package/lib/workflow/workflow-status.d.ts +2 -0
  209. package/lib/workflow/workflow-status.js +14 -0
  210. package/lib/workflow/workflow-transition.d.ts +9 -0
  211. package/lib/workflow/workflow-transition.js +38 -0
  212. package/package.json +5 -3
  213. package/lib/tools/hub-v2/config.d.ts +0 -34
  214. package/lib/tools/hub-v2/config.js +0 -297
@@ -1,4 +1,7 @@
1
1
  import type { CoreApp } from "@yinuo-ngm/core";
2
+ import type { PathGuardService } from "../services/path-guard.service";
3
+ import type { PermissionService } from "../services/permission.service";
4
+ import type { ProjectResolverService } from "../services/project-resolver.service";
2
5
  export type GitReadService = {
3
6
  status(input: {
4
7
  projectId?: string;
@@ -9,10 +12,43 @@ export type GitReadService = {
9
12
  projectPath?: string;
10
13
  maxBytes?: number;
11
14
  }): Promise<unknown>;
15
+ changedFiles?(input: {
16
+ projectId?: string;
17
+ projectPath?: string;
18
+ }): Promise<string[]>;
19
+ currentBranch?(input: {
20
+ projectId?: string;
21
+ projectPath?: string;
22
+ }): Promise<string>;
23
+ latestLog?(input: {
24
+ projectId?: string;
25
+ projectPath?: string;
26
+ }): Promise<string>;
27
+ };
28
+ export type LocalServerAvailability = {
29
+ available: boolean;
30
+ url?: string;
31
+ reason?: string;
32
+ };
33
+ export type LocalServerClient = {
34
+ availability(): Promise<LocalServerAvailability>;
35
+ refreshTaskProject(projectId: string): Promise<any[]>;
36
+ refreshProjectScripts(projectId: string): Promise<any>;
37
+ updateProjectRuntime(projectId: string, runtime: unknown): Promise<any>;
38
+ listTaskViews(projectId: string): Promise<any[]>;
39
+ listActiveTasks(): Promise<any[]>;
40
+ startTask(taskId: string): Promise<any>;
41
+ stopTask(taskId: string): Promise<any>;
42
+ getTaskStatus(taskId: string): Promise<any>;
43
+ getTaskLogTail(runId: string, tail: number): Promise<any[]>;
12
44
  };
13
45
  export type ToolServices = {
14
46
  core: CoreApp;
15
47
  git: GitReadService;
48
+ pathGuard: PathGuardService;
49
+ permission: PermissionService;
50
+ projectResolver: ProjectResolverService;
51
+ localServer?: LocalServerClient;
16
52
  };
17
53
  export type ToolContext = {
18
54
  workspaceRoot: string;
@@ -0,0 +1,8 @@
1
+ type DoctorStatus = "OK" | "WARN" | "ERROR";
2
+ type DoctorReport = {
3
+ status: DoctorStatus;
4
+ text: string;
5
+ };
6
+ export declare function createDoctorReport(): DoctorReport;
7
+ export declare function doctor(write?: (text: string) => void): Promise<void>;
8
+ export {};
package/lib/doctor.js ADDED
@@ -0,0 +1,221 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createDoctorReport = createDoctorReport;
4
+ exports.doctor = doctor;
5
+ const fs_1 = require("fs");
6
+ const os_1 = require("os");
7
+ const path_1 = require("path");
8
+ const tool_policy_1 = require("./policy/tool-policy");
9
+ const tools_1 = require("./tools");
10
+ const index_1 = require("./tools/hub-v2/config/index");
11
+ function envValue(name) {
12
+ const value = process.env[name];
13
+ return value !== undefined && value !== null && String(value).trim()
14
+ ? String(value).trim()
15
+ : undefined;
16
+ }
17
+ function statusRank(status) {
18
+ return status === "ERROR" ? 2 : status === "WARN" ? 1 : 0;
19
+ }
20
+ function maxStatus(...statuses) {
21
+ return statuses.reduce((current, next) => (statusRank(next) > statusRank(current) ? next : current), "OK");
22
+ }
23
+ function defaultDataDir() {
24
+ return envValue("NGM_DATA_DIR") ?? (0, path_1.join)((0, os_1.homedir)(), ".ng-manager");
25
+ }
26
+ function readPackageInfo() {
27
+ try {
28
+ const packagePath = (0, path_1.join)(__dirname, "..", "package.json");
29
+ const parsed = JSON.parse((0, fs_1.readFileSync)(packagePath, "utf8"));
30
+ const name = parsed.name ?? "@yinuo-ngm/mcp-server";
31
+ const version = parsed.version ?? "unknown";
32
+ return { text: `${name} ${version}`, status: version === "unknown" ? "WARN" : "OK" };
33
+ }
34
+ catch {
35
+ return { text: "@yinuo-ngm/mcp-server unknown", status: "WARN" };
36
+ }
37
+ }
38
+ function configured(value) {
39
+ return value ? "configured" : "missing";
40
+ }
41
+ function displayValue(value) {
42
+ return value || "missing";
43
+ }
44
+ function selectedProject(config) {
45
+ const projects = config.projects ?? {};
46
+ const entries = Object.entries(projects);
47
+ const selected = envValue("HUB_V2_PROJECT") ?? config.default_project;
48
+ if (selected) {
49
+ return {
50
+ name: selected,
51
+ project: projects[selected] ?? {},
52
+ status: projects[selected] || !entries.length ? "OK" : "WARN",
53
+ };
54
+ }
55
+ if (entries.length === 1) {
56
+ return { name: entries[0][0], project: entries[0][1], status: "OK" };
57
+ }
58
+ if (entries.length > 1) {
59
+ return { name: undefined, project: {}, status: "WARN" };
60
+ }
61
+ return { name: undefined, project: {}, status: "WARN" };
62
+ }
63
+ function configValue(config, project, key) {
64
+ return project[key] ?? config[key];
65
+ }
66
+ function hubV2Section() {
67
+ const path = (0, index_1.resolveAgentConnectionsPath)();
68
+ if (!(0, fs_1.existsSync)(path)) {
69
+ return {
70
+ status: "WARN",
71
+ lines: [
72
+ "Hub V2:",
73
+ " config: missing",
74
+ ` path: ${path}`,
75
+ ],
76
+ };
77
+ }
78
+ let config;
79
+ try {
80
+ config = (0, index_1.loadConfig)(path);
81
+ }
82
+ catch (error) {
83
+ return {
84
+ status: "ERROR",
85
+ lines: [
86
+ "Hub V2:",
87
+ " config: invalid",
88
+ ` path: ${path}`,
89
+ ` error: ${error instanceof Error ? error.message : String(error)}`,
90
+ ],
91
+ };
92
+ }
93
+ const selected = selectedProject(config);
94
+ const project = selected.project;
95
+ const baseUrl = envValue("HUB_V2_BASE_URL") ?? configValue(config, project, "base_url");
96
+ const projectKey = envValue("HUB_V2_PROJECT_KEY") ?? configValue(config, project, "project_key");
97
+ const projectToken = envValue("HUB_V2_PROJECT_TOKEN") ?? configValue(config, project, "project_token");
98
+ const personalToken = envValue("HUB_V2_PERSONAL_TOKEN") ?? configValue(config, project, "personal_token");
99
+ const fieldStatus = baseUrl && projectKey && projectToken && personalToken ? "OK" : "WARN";
100
+ return {
101
+ status: maxStatus(selected.status, fieldStatus),
102
+ lines: [
103
+ "Hub V2:",
104
+ " config: found",
105
+ ` defaultProject: ${displayValue(config.default_project)}`,
106
+ ` project: ${displayValue(selected.name)}`,
107
+ ` baseUrl: ${displayValue(baseUrl)}`,
108
+ ` projectKey: ${displayValue(projectKey)}`,
109
+ ` projectToken: ${configured(projectToken)}`,
110
+ ` personalToken: ${configured(personalToken)}`,
111
+ ],
112
+ };
113
+ }
114
+ function policySection() {
115
+ const policy = (0, tool_policy_1.createDefaultToolPolicy)();
116
+ return [
117
+ "Policy:",
118
+ " read: enabled",
119
+ ` write: ${policy.write ? "enabled" : "disabled"}`,
120
+ ` execute: ${policy.execute ? "enabled" : "disabled"}`,
121
+ ` dangerous: ${policy.dangerous ? "enabled" : "disabled"}`,
122
+ ];
123
+ }
124
+ function toolsSection() {
125
+ try {
126
+ const counts = {
127
+ read: 0,
128
+ write: 0,
129
+ execute: 0,
130
+ dangerous: 0,
131
+ };
132
+ const tools = (0, tools_1.allTools)();
133
+ for (const tool of tools) {
134
+ counts[tool.riskLevel] += 1;
135
+ }
136
+ return {
137
+ status: "OK",
138
+ lines: [
139
+ "Tools:",
140
+ ` total: ${tools.length}`,
141
+ ` read: ${counts.read}`,
142
+ ` write: ${counts.write}`,
143
+ ` execute: ${counts.execute}`,
144
+ ` dangerous: ${counts.dangerous}`,
145
+ ],
146
+ };
147
+ }
148
+ catch (error) {
149
+ return {
150
+ status: "ERROR",
151
+ lines: [
152
+ "Tools:",
153
+ " status: failed",
154
+ ` error: ${error instanceof Error ? error.message : String(error)}`,
155
+ ],
156
+ };
157
+ }
158
+ }
159
+ function enterpriseMvpSection() {
160
+ const names = new Set((0, tools_1.allTools)().map((tool) => tool.name));
161
+ const required = {
162
+ frontendStandard: ["ngm_standard_get", "ngm_standard_init", "ngm_standard_validate_project"],
163
+ workflow: ["ngm_workflow_create_frontend_task", "ngm_workflow_generate_dev_plan", "ngm_workflow_advance_status", "ngm_workflow_validate_before_commit", "ngm_workflow_generate_delivery_report"],
164
+ audit: ["ngm_standard_init", "ngm_workflow_create_frontend_task", "ngm_review_generate_report"],
165
+ patchPreview: ["ngm_workspace_diff", "ngm_workspace_apply_patch_preview"],
166
+ dottedAliases: ["ngm_project_run_script", "ngm_project_stop", "ngm_runtime_set_for_project", "ngm_nginx_reload", "ngm_nginx_proxy_save"],
167
+ };
168
+ const missing = Object.entries(required)
169
+ .flatMap(([group, tools]) => tools.filter((tool) => !names.has(tool)).map((tool) => `${group}:${tool}`));
170
+ return {
171
+ status: missing.length ? "WARN" : "OK",
172
+ lines: [
173
+ "Enterprise MVP:",
174
+ ` frontendStandard: ${required.frontendStandard.every((tool) => names.has(tool)) ? "available" : "missing"}`,
175
+ ` workflow: ${required.workflow.every((tool) => names.has(tool)) ? "available" : "missing"}`,
176
+ " audit: project-local .ng-manager/audit/mcp-YYYY-MM-DD.jsonl",
177
+ ` patchPreview: ${required.patchPreview.every((tool) => names.has(tool)) ? "available" : "missing"}`,
178
+ ` dottedAliases: ${required.dottedAliases.every((tool) => names.has(tool)) ? "available" : "missing"}`,
179
+ ...(missing.length ? [` missing: ${missing.join(", ")}`] : []),
180
+ ],
181
+ };
182
+ }
183
+ function createDoctorReport() {
184
+ const packageInfo = readPackageInfo();
185
+ const hubV2 = hubV2Section();
186
+ const tools = toolsSection();
187
+ const enterprise = enterpriseMvpSection();
188
+ const status = maxStatus(packageInfo.status, hubV2.status, tools.status, enterprise.status);
189
+ const lines = [
190
+ "ng-manager MCP Doctor",
191
+ "",
192
+ "Runtime:",
193
+ ` Node.js: ${process.version}`,
194
+ ` Platform: ${process.platform} ${process.arch}`,
195
+ ` CWD: ${process.cwd()}`,
196
+ ` MCP Server: ${packageInfo.text}`,
197
+ "",
198
+ "Paths:",
199
+ ` dataDir: ${defaultDataDir()}`,
200
+ ` agentConnections: ${(0, index_1.resolveAgentConnectionsPath)()}`,
201
+ "",
202
+ ...hubV2.lines,
203
+ "",
204
+ ...policySection(),
205
+ "",
206
+ ...tools.lines,
207
+ "",
208
+ ...enterprise.lines,
209
+ "",
210
+ "Status:",
211
+ ` ${status}`,
212
+ ];
213
+ return {
214
+ status,
215
+ text: lines.join("\n"),
216
+ };
217
+ }
218
+ async function doctor(write = (text) => process.stdout.write(text)) {
219
+ const report = createDoctorReport();
220
+ write(`${report.text}\n`);
221
+ }
@@ -0,0 +1,12 @@
1
+ export declare const McpErrorCodes: {
2
+ readonly PROJECT_NOT_FOUND: "PROJECT_NOT_FOUND";
3
+ readonly PROJECT_ROOT_NOT_FOUND: "PROJECT_ROOT_NOT_FOUND";
4
+ readonly PATH_ESCAPE_DENIED: "PATH_ESCAPE_DENIED";
5
+ readonly ABSOLUTE_PATH_DENIED: "ABSOLUTE_PATH_DENIED";
6
+ readonly CONFIRM_REQUIRED: "CONFIRM_REQUIRED";
7
+ readonly WRITE_NOT_ALLOWED: "WRITE_NOT_ALLOWED";
8
+ readonly EXECUTE_NOT_ALLOWED: "EXECUTE_NOT_ALLOWED";
9
+ readonly LOCAL_SERVER_UNAVAILABLE: "LOCAL_SERVER_UNAVAILABLE";
10
+ readonly TOOL_INPUT_INVALID: "TOOL_INPUT_INVALID";
11
+ };
12
+ export type McpErrorCode = (typeof McpErrorCodes)[keyof typeof McpErrorCodes];
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.McpErrorCodes = void 0;
4
+ exports.McpErrorCodes = {
5
+ PROJECT_NOT_FOUND: "PROJECT_NOT_FOUND",
6
+ PROJECT_ROOT_NOT_FOUND: "PROJECT_ROOT_NOT_FOUND",
7
+ PATH_ESCAPE_DENIED: "PATH_ESCAPE_DENIED",
8
+ ABSOLUTE_PATH_DENIED: "ABSOLUTE_PATH_DENIED",
9
+ CONFIRM_REQUIRED: "CONFIRM_REQUIRED",
10
+ WRITE_NOT_ALLOWED: "WRITE_NOT_ALLOWED",
11
+ EXECUTE_NOT_ALLOWED: "EXECUTE_NOT_ALLOWED",
12
+ LOCAL_SERVER_UNAVAILABLE: "LOCAL_SERVER_UNAVAILABLE",
13
+ TOOL_INPUT_INVALID: "TOOL_INPUT_INVALID",
14
+ };
@@ -0,0 +1,8 @@
1
+ import type { McpErrorCode } from "./error-codes";
2
+ export declare class McpToolError extends Error {
3
+ readonly errorCode: McpErrorCode;
4
+ readonly code: McpErrorCode;
5
+ readonly status?: number;
6
+ readonly detail?: unknown;
7
+ constructor(errorCode: McpErrorCode, message: string, detail?: unknown, status?: number);
8
+ }
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.McpToolError = void 0;
4
+ class McpToolError extends Error {
5
+ constructor(errorCode, message, detail, status) {
6
+ super(message);
7
+ this.name = "McpToolError";
8
+ this.errorCode = errorCode;
9
+ this.code = errorCode;
10
+ this.detail = detail;
11
+ this.status = status;
12
+ }
13
+ }
14
+ exports.McpToolError = McpToolError;
@@ -0,0 +1,18 @@
1
+ import type { ToolContext } from "../context/tool-context";
2
+ export type ProjectLocator = {
3
+ projectId?: string;
4
+ projectPath?: string;
5
+ };
6
+ export type ResolvedProjectRoot = {
7
+ projectId?: string;
8
+ projectName?: string;
9
+ projectRoot: string;
10
+ };
11
+ export declare function resolveProjectRoot(context: ToolContext, locator?: ProjectLocator): Promise<ResolvedProjectRoot>;
12
+ export declare function projectRelativePath(projectRoot: string, filePath: string): string;
13
+ export declare function assertPathInsideProject(projectRoot: string, targetPath: string): void;
14
+ export declare function resolveNgManagerPath(projectRoot: string, ...segments: string[]): string;
15
+ export declare function pathExists(filePath: string): Promise<boolean>;
16
+ export declare function writeJsonFile(filePath: string, value: unknown): Promise<void>;
17
+ export declare function writeTextFile(filePath: string, value: string): Promise<void>;
18
+ export declare function validateSafeId(kind: string, value: string): void;
@@ -0,0 +1,112 @@
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.resolveProjectRoot = resolveProjectRoot;
37
+ exports.projectRelativePath = projectRelativePath;
38
+ exports.assertPathInsideProject = assertPathInsideProject;
39
+ exports.resolveNgManagerPath = resolveNgManagerPath;
40
+ exports.pathExists = pathExists;
41
+ exports.writeJsonFile = writeJsonFile;
42
+ exports.writeTextFile = writeTextFile;
43
+ exports.validateSafeId = validateSafeId;
44
+ const fs = __importStar(require("fs/promises"));
45
+ const path = __importStar(require("path"));
46
+ function normalizePath(value) {
47
+ const resolved = path.resolve(value);
48
+ return process.platform === "win32" ? resolved.replace(/\\/g, "/").toLowerCase() : resolved;
49
+ }
50
+ function isInside(parent, child) {
51
+ const relative = path.relative(parent, child);
52
+ return relative === "" || (!relative.startsWith("..") && !path.isAbsolute(relative));
53
+ }
54
+ async function resolveProjectRoot(context, locator = {}) {
55
+ if (locator.projectId) {
56
+ const project = await context.services.core.project.get(locator.projectId);
57
+ return {
58
+ projectId: project.id,
59
+ projectName: project.name,
60
+ projectRoot: path.resolve(project.root),
61
+ };
62
+ }
63
+ if (locator.projectPath) {
64
+ return {
65
+ projectRoot: path.resolve(locator.projectPath),
66
+ };
67
+ }
68
+ return {
69
+ projectRoot: path.resolve(context.workspaceRoot),
70
+ };
71
+ }
72
+ function projectRelativePath(projectRoot, filePath) {
73
+ return path.relative(projectRoot, filePath).replace(/\\/g, "/") || ".";
74
+ }
75
+ function assertPathInsideProject(projectRoot, targetPath) {
76
+ const root = normalizePath(projectRoot);
77
+ const target = normalizePath(targetPath);
78
+ if (!isInside(root, target)) {
79
+ throw new Error(`Path escapes project root: ${targetPath}`);
80
+ }
81
+ }
82
+ function resolveNgManagerPath(projectRoot, ...segments) {
83
+ const base = path.resolve(projectRoot, ".ng-manager");
84
+ const target = path.resolve(base, ...segments);
85
+ assertPathInsideProject(projectRoot, target);
86
+ if (!isInside(normalizePath(base), normalizePath(target))) {
87
+ throw new Error(`Path escapes .ng-manager directory: ${target}`);
88
+ }
89
+ return target;
90
+ }
91
+ async function pathExists(filePath) {
92
+ try {
93
+ await fs.access(filePath);
94
+ return true;
95
+ }
96
+ catch {
97
+ return false;
98
+ }
99
+ }
100
+ async function writeJsonFile(filePath, value) {
101
+ await fs.mkdir(path.dirname(filePath), { recursive: true });
102
+ await fs.writeFile(filePath, `${JSON.stringify(value, null, 2)}\n`, "utf-8");
103
+ }
104
+ async function writeTextFile(filePath, value) {
105
+ await fs.mkdir(path.dirname(filePath), { recursive: true });
106
+ await fs.writeFile(filePath, value.endsWith("\n") ? value : `${value}\n`, "utf-8");
107
+ }
108
+ function validateSafeId(kind, value) {
109
+ if (!/^[a-zA-Z0-9][a-zA-Z0-9._-]{0,79}$/.test(value)) {
110
+ throw new Error(`${kind} must be 1-80 chars and contain only letters, numbers, dot, underscore, or dash`);
111
+ }
112
+ }
@@ -0,0 +1,2 @@
1
+ import type { GitReadService } from "../context/tool-context";
2
+ export declare function createLocalGitReadService(workspaceRoot: string): GitReadService;
@@ -0,0 +1,96 @@
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.createLocalGitReadService = createLocalGitReadService;
37
+ const child_process_1 = require("child_process");
38
+ const path = __importStar(require("path"));
39
+ const util_1 = require("util");
40
+ const execFileAsync = (0, util_1.promisify)(child_process_1.execFile);
41
+ function resolveCwd(workspaceRoot, projectPath) {
42
+ return path.resolve(projectPath || workspaceRoot);
43
+ }
44
+ async function git(cwd, args, maxBuffer = 200000) {
45
+ const { stdout } = await execFileAsync("git", args, {
46
+ cwd,
47
+ windowsHide: true,
48
+ timeout: 10000,
49
+ maxBuffer,
50
+ });
51
+ return String(stdout);
52
+ }
53
+ function parseChangedFiles(statusText) {
54
+ return statusText
55
+ .split(/\r?\n/)
56
+ .map((line) => line.trim())
57
+ .filter(Boolean)
58
+ .map((line) => line.replace(/^(.{2})\s+/, "").replace(/^"|"$/g, ""))
59
+ .map((line) => line.includes(" -> ") ? line.split(" -> ").pop() : line)
60
+ .filter(Boolean);
61
+ }
62
+ function createLocalGitReadService(workspaceRoot) {
63
+ return {
64
+ async status(input) {
65
+ const cwd = resolveCwd(workspaceRoot, input.projectPath);
66
+ const short = await git(cwd, ["status", "--short", "--untracked-files=all"]);
67
+ return {
68
+ cwd,
69
+ branch: (await git(cwd, ["branch", "--show-current"])).trim() || undefined,
70
+ changedFiles: parseChangedFiles(short),
71
+ short,
72
+ };
73
+ },
74
+ async diff(input) {
75
+ const cwd = resolveCwd(workspaceRoot, input.projectPath);
76
+ const text = await git(cwd, ["diff", "--no-ext-diff"], input.maxBytes ?? 200000);
77
+ const maxBytes = input.maxBytes ?? 200000;
78
+ return {
79
+ cwd,
80
+ diff: text.length > maxBytes ? text.slice(0, maxBytes) : text,
81
+ truncated: text.length > maxBytes || undefined,
82
+ };
83
+ },
84
+ async changedFiles(input) {
85
+ const cwd = resolveCwd(workspaceRoot, input.projectPath);
86
+ const short = await git(cwd, ["status", "--short", "--untracked-files=all"]);
87
+ return parseChangedFiles(short);
88
+ },
89
+ async currentBranch(input) {
90
+ return (await git(resolveCwd(workspaceRoot, input.projectPath), ["branch", "--show-current"])).trim();
91
+ },
92
+ async latestLog(input) {
93
+ return (await git(resolveCwd(workspaceRoot, input.projectPath), ["log", "-1", "--pretty=format:%h %s"])).trim();
94
+ },
95
+ };
96
+ }
package/lib/index.d.ts CHANGED
@@ -1,2 +1,3 @@
1
1
  #!/usr/bin/env node
2
+ export { createDoctorReport, doctor } from "./doctor";
2
3
  export declare function main(): Promise<void>;
package/lib/index.js CHANGED
@@ -1,11 +1,15 @@
1
1
  #!/usr/bin/env node
2
2
  "use strict";
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.doctor = exports.createDoctorReport = void 0;
4
5
  exports.main = main;
5
6
  const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
6
7
  const create_tool_context_1 = require("./context/create-tool-context");
7
8
  const create_mcp_server_1 = require("./create-mcp-server");
8
9
  const errors_1 = require("./utils/errors");
10
+ var doctor_1 = require("./doctor");
11
+ Object.defineProperty(exports, "createDoctorReport", { enumerable: true, get: function () { return doctor_1.createDoctorReport; } });
12
+ Object.defineProperty(exports, "doctor", { enumerable: true, get: function () { return doctor_1.doctor; } });
9
13
  async function main() {
10
14
  const context = await (0, create_tool_context_1.createToolContext)();
11
15
  const server = (0, create_mcp_server_1.createMcpServer)(context);
@@ -1,8 +1,17 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.assertToolPolicy = assertToolPolicy;
4
+ const error_codes_1 = require("../errors/error-codes");
5
+ const mcp_tool_error_1 = require("../errors/mcp-tool-error");
4
6
  function assertToolPolicy(policy, toolName, riskLevel) {
5
7
  if (!policy[riskLevel]) {
6
- throw new Error(`Tool ${toolName} is blocked by policy: ${riskLevel} tools are disabled`);
8
+ const errorCode = riskLevel === "write"
9
+ ? error_codes_1.McpErrorCodes.WRITE_NOT_ALLOWED
10
+ : riskLevel === "execute"
11
+ ? error_codes_1.McpErrorCodes.EXECUTE_NOT_ALLOWED
12
+ : error_codes_1.McpErrorCodes.TOOL_INPUT_INVALID;
13
+ throw new mcp_tool_error_1.McpToolError(errorCode, `Tool ${toolName} is blocked by policy: ${riskLevel} tools are disabled`, {
14
+ riskLevel,
15
+ });
7
16
  }
8
17
  }