mcp-probe-kit 3.0.5 → 3.0.7

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 (69) hide show
  1. package/README.md +458 -431
  2. package/build/index.js +875 -141
  3. package/build/lib/gitnexus-bridge.d.ts +58 -0
  4. package/build/lib/gitnexus-bridge.js +379 -0
  5. package/build/lib/template-loader.js +317 -317
  6. package/build/lib/tool-execution-context.d.ts +8 -0
  7. package/build/lib/tool-execution-context.js +20 -0
  8. package/build/lib/toolset-manager.d.ts +1 -1
  9. package/build/lib/toolset-manager.js +7 -5
  10. package/build/schemas/code-analysis-tools.d.ts +46 -0
  11. package/build/schemas/code-analysis-tools.js +47 -0
  12. package/build/schemas/git-tools.js +16 -16
  13. package/build/schemas/index.d.ts +46 -0
  14. package/build/tools/__tests__/code_insight.unit.test.d.ts +1 -0
  15. package/build/tools/__tests__/code_insight.unit.test.js +35 -0
  16. package/build/tools/__tests__/start_bugfix.unit.test.js +14 -14
  17. package/build/tools/__tests__/start_ui.unit.test.js +11 -11
  18. package/build/tools/add_feature.js +79 -79
  19. package/build/tools/ask_user.js +5 -5
  20. package/build/tools/code_insight.d.ts +8 -0
  21. package/build/tools/code_insight.js +129 -0
  22. package/build/tools/index.d.ts +1 -0
  23. package/build/tools/index.js +1 -0
  24. package/build/tools/interview.js +9 -9
  25. package/build/tools/start_bugfix.d.ts +2 -1
  26. package/build/tools/start_bugfix.js +170 -126
  27. package/build/tools/start_feature.d.ts +2 -1
  28. package/build/tools/start_feature.js +156 -112
  29. package/build/tools/start_onboard.d.ts +2 -1
  30. package/build/tools/start_onboard.js +57 -51
  31. package/build/tools/start_product.d.ts +2 -1
  32. package/build/tools/start_product.js +9 -1
  33. package/build/tools/start_ralph.d.ts +2 -1
  34. package/build/tools/start_ralph.js +9 -3
  35. package/build/tools/start_ui.d.ts +2 -1
  36. package/build/tools/start_ui.js +102 -88
  37. package/build/tools/ui-ux-tools.d.ts +2 -1
  38. package/build/tools/ui-ux-tools.js +19 -3
  39. package/build/utils/ui-sync.d.ts +6 -2
  40. package/build/utils/ui-sync.js +125 -29
  41. package/docs/assets/font/MaterialSymbolsOutlined.codepoints +4102 -0
  42. package/docs/assets/font/MaterialSymbolsOutlined.ttf +0 -0
  43. package/docs/assets/font/noto-sans-sc-400.ttf +0 -0
  44. package/docs/assets/font/noto-sans-sc-700.ttf +0 -0
  45. package/docs/assets/font/noto-sans-sc-900.ttf +0 -0
  46. package/docs/assets/js/i18n.js +122 -21
  47. package/docs/assets/js/tailwind.js +83 -83
  48. package/docs/data/tools.js +419 -399
  49. package/docs/debug-i18n.html +163 -0
  50. package/docs/i18n/all-tools/en.json +157 -0
  51. package/docs/i18n/all-tools/ja.json +157 -0
  52. package/docs/i18n/all-tools/ko.json +157 -0
  53. package/docs/i18n/all-tools/zh-CN.json +157 -0
  54. package/docs/pages/all-tools.html +514 -352
  55. package/docs/pages/examples.html +689 -689
  56. package/docs/pages/getting-started.html +589 -589
  57. package/docs/pages/migration.html +298 -298
  58. package/docs/specs/user-auth/design.md +82 -0
  59. package/docs/specs/user-auth/requirements.md +52 -0
  60. package/docs/specs/user-auth/tasks.md +55 -0
  61. package/package.json +5 -5
  62. package/docs/project-context/architecture.md +0 -0
  63. package/docs/project-context/how-to-develop.md +0 -313
  64. package/docs/project-context/how-to-test.md +0 -457
  65. package/docs/project-context/tech-stack.md +0 -96
  66. package/docs/project-context.md +0 -53
  67. package/docs/specs/git-work-report/design.md +0 -568
  68. package/docs/specs/git-work-report/requirements.md +0 -131
  69. package/docs/specs/git-work-report/tasks.md +0 -197
@@ -0,0 +1,58 @@
1
+ export type CodeInsightMode = "auto" | "query" | "context" | "impact";
2
+ export type CodeInsightDirection = "upstream" | "downstream";
3
+ export interface CodeInsightRequest {
4
+ mode?: CodeInsightMode;
5
+ query?: string;
6
+ target?: string;
7
+ repo?: string;
8
+ goal?: string;
9
+ taskContext?: string;
10
+ direction?: CodeInsightDirection;
11
+ maxDepth?: number;
12
+ includeTests?: boolean;
13
+ signal?: AbortSignal;
14
+ }
15
+ export interface CodeInsightExecution {
16
+ tool: string;
17
+ ok: boolean;
18
+ durationMs: number;
19
+ args: Record<string, unknown>;
20
+ text?: string;
21
+ structuredContent?: unknown;
22
+ error?: string;
23
+ }
24
+ export interface CodeInsightBridgeResult {
25
+ provider: "gitnexus";
26
+ enabled: boolean;
27
+ available: boolean;
28
+ degraded: boolean;
29
+ modeRequested: CodeInsightMode;
30
+ modeResolved: "query" | "context" | "impact";
31
+ summary: string;
32
+ executions: CodeInsightExecution[];
33
+ warnings: string[];
34
+ repo?: string;
35
+ }
36
+ export interface EmbeddedGraphContext {
37
+ enabled: boolean;
38
+ available: boolean;
39
+ degraded: boolean;
40
+ summary: string;
41
+ warnings: string[];
42
+ provider: "gitnexus";
43
+ mode: "query" | "context" | "impact";
44
+ highlights: string[];
45
+ }
46
+ export declare function runCodeInsightBridge(request: CodeInsightRequest): Promise<CodeInsightBridgeResult>;
47
+ export declare function buildFeatureGraphContext(input: {
48
+ featureName: string;
49
+ description: string;
50
+ signal?: AbortSignal;
51
+ repo?: string;
52
+ }): Promise<EmbeddedGraphContext>;
53
+ export declare function buildBugfixGraphContext(input: {
54
+ errorMessage: string;
55
+ stackTrace?: string;
56
+ signal?: AbortSignal;
57
+ repo?: string;
58
+ }): Promise<EmbeddedGraphContext>;
@@ -0,0 +1,379 @@
1
+ import { Client } from "@modelcontextprotocol/sdk/client/index.js";
2
+ import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
3
+ import * as fs from "node:fs";
4
+ import * as path from "node:path";
5
+ import { isAbortError, throwIfAborted, } from "./tool-execution-context.js";
6
+ const DEFAULT_CONNECT_TIMEOUT_MS = readIntEnv("MCP_GITNEXUS_CONNECT_TIMEOUT_MS", 12000);
7
+ const DEFAULT_CALL_TIMEOUT_MS = readIntEnv("MCP_GITNEXUS_TIMEOUT_MS", 20000);
8
+ const DEFAULT_GITNEXUS_ARGS = ["-y", "gitnexus", "mcp"];
9
+ const FAILURE_CACHE_TTL_MS = readIntEnv("MCP_GITNEXUS_FAILURE_CACHE_TTL_MS", 30000);
10
+ let bridgeFailureUntil = 0;
11
+ let bridgeFailureReason = "";
12
+ function readIntEnv(name, fallback) {
13
+ const value = process.env[name];
14
+ if (!value) {
15
+ return fallback;
16
+ }
17
+ const parsed = Number(value);
18
+ return Number.isFinite(parsed) && parsed > 0 ? Math.round(parsed) : fallback;
19
+ }
20
+ function isEnvDisabled(name) {
21
+ const value = process.env[name];
22
+ if (value === undefined) {
23
+ return false;
24
+ }
25
+ return /^(0|false|no|off)$/i.test(value.trim());
26
+ }
27
+ function isBridgeEnabled() {
28
+ const raw = process.env.MCP_ENABLE_GITNEXUS_BRIDGE;
29
+ if (raw === undefined) {
30
+ return process.env.NODE_ENV !== "test";
31
+ }
32
+ return !/^(0|false|no|off)$/i.test(raw.trim());
33
+ }
34
+ function splitArgs(raw) {
35
+ if (!raw) {
36
+ return [...DEFAULT_GITNEXUS_ARGS];
37
+ }
38
+ return raw
39
+ .trim()
40
+ .split(/\s+/)
41
+ .filter(Boolean);
42
+ }
43
+ function inferDefaultRepoName() {
44
+ const explicit = process.env.MCP_GITNEXUS_REPO?.trim();
45
+ if (explicit) {
46
+ return explicit;
47
+ }
48
+ const pkgPath = path.join(process.cwd(), "package.json");
49
+ try {
50
+ if (fs.existsSync(pkgPath)) {
51
+ const parsed = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
52
+ const pkgName = typeof parsed.name === "string" ? parsed.name.trim() : "";
53
+ if (pkgName) {
54
+ return pkgName;
55
+ }
56
+ }
57
+ }
58
+ catch {
59
+ // ignore parse failure
60
+ }
61
+ const base = path.basename(process.cwd()).trim();
62
+ return base || undefined;
63
+ }
64
+ function resolveBridgeCommand() {
65
+ const command = (process.env.MCP_GITNEXUS_COMMAND || "npx").trim() || "npx";
66
+ const args = splitArgs(process.env.MCP_GITNEXUS_ARGS);
67
+ return { command, args };
68
+ }
69
+ function extractText(result) {
70
+ if (!result || typeof result !== "object") {
71
+ return "";
72
+ }
73
+ const content = result.content;
74
+ if (!Array.isArray(content)) {
75
+ return "";
76
+ }
77
+ return content
78
+ .map((item) => {
79
+ if (!item || typeof item !== "object") {
80
+ return "";
81
+ }
82
+ const text = item.text;
83
+ return typeof text === "string" ? text : "";
84
+ })
85
+ .filter(Boolean)
86
+ .join("\n\n")
87
+ .trim();
88
+ }
89
+ function shorten(text, maxLen = 260) {
90
+ if (!text) {
91
+ return "";
92
+ }
93
+ const normalized = text.replace(/\s+/g, " ").trim();
94
+ if (normalized.length <= maxLen) {
95
+ return normalized;
96
+ }
97
+ return `${normalized.slice(0, maxLen - 3)}...`;
98
+ }
99
+ function normalizeError(error) {
100
+ if (error instanceof Error) {
101
+ return error.message;
102
+ }
103
+ return String(error);
104
+ }
105
+ function resolveMode(request) {
106
+ const mode = request.mode || "auto";
107
+ if (mode === "query" || mode === "context" || mode === "impact") {
108
+ return mode;
109
+ }
110
+ if (request.target && request.direction) {
111
+ return "impact";
112
+ }
113
+ if (request.target && !request.query) {
114
+ return "context";
115
+ }
116
+ return "query";
117
+ }
118
+ async function callBridgeTool(client, tool, args, signal) {
119
+ const startedAt = Date.now();
120
+ try {
121
+ const result = await client.callTool({
122
+ name: tool,
123
+ arguments: args,
124
+ }, undefined, {
125
+ timeout: DEFAULT_CALL_TIMEOUT_MS,
126
+ signal,
127
+ });
128
+ const durationMs = Date.now() - startedAt;
129
+ const text = extractText(result);
130
+ const isError = Boolean(result.isError);
131
+ if (isError) {
132
+ return {
133
+ tool,
134
+ args,
135
+ ok: false,
136
+ durationMs,
137
+ text,
138
+ structuredContent: result.structuredContent,
139
+ error: text || `GitNexus 工具 ${tool} 返回错误`,
140
+ };
141
+ }
142
+ return {
143
+ tool,
144
+ args,
145
+ ok: true,
146
+ durationMs,
147
+ text,
148
+ structuredContent: result.structuredContent,
149
+ };
150
+ }
151
+ catch (error) {
152
+ if (isAbortError(error)) {
153
+ throw error;
154
+ }
155
+ return {
156
+ tool,
157
+ args,
158
+ ok: false,
159
+ durationMs: Date.now() - startedAt,
160
+ error: normalizeError(error),
161
+ };
162
+ }
163
+ }
164
+ export async function runCodeInsightBridge(request) {
165
+ const modeRequested = request.mode || "auto";
166
+ const modeResolved = resolveMode(request);
167
+ const effectiveRepo = request.repo || inferDefaultRepoName();
168
+ if (!isBridgeEnabled() || isEnvDisabled("MCP_ENABLE_GITNEXUS_BRIDGE")) {
169
+ return {
170
+ provider: "gitnexus",
171
+ enabled: false,
172
+ available: false,
173
+ degraded: true,
174
+ modeRequested,
175
+ modeResolved,
176
+ summary: "GitNexus bridge 已禁用(MCP_ENABLE_GITNEXUS_BRIDGE=0)。",
177
+ executions: [],
178
+ warnings: ["bridge_disabled"],
179
+ repo: effectiveRepo,
180
+ };
181
+ }
182
+ if (Date.now() < bridgeFailureUntil) {
183
+ return {
184
+ provider: "gitnexus",
185
+ enabled: true,
186
+ available: false,
187
+ degraded: true,
188
+ modeRequested,
189
+ modeResolved,
190
+ summary: `GitNexus bridge 暂不可用(缓存中): ${bridgeFailureReason || "请稍后重试"}`,
191
+ executions: [],
192
+ warnings: ["bridge_failure_cached"],
193
+ repo: effectiveRepo,
194
+ };
195
+ }
196
+ throwIfAborted(request.signal, "GitNexus bridge 已取消");
197
+ const { command, args } = resolveBridgeCommand();
198
+ const warnings = [];
199
+ const executions = [];
200
+ const stderrLogs = [];
201
+ const transport = new StdioClientTransport({
202
+ command,
203
+ args,
204
+ cwd: process.cwd(),
205
+ stderr: "pipe",
206
+ });
207
+ if (transport.stderr) {
208
+ transport.stderr.on("data", (chunk) => {
209
+ const text = String(chunk);
210
+ if (text.trim()) {
211
+ stderrLogs.push(text.trim());
212
+ }
213
+ });
214
+ }
215
+ const client = new Client({
216
+ name: "mcp-probe-kit-gitnexus-bridge",
217
+ version: "1.0.0",
218
+ });
219
+ try {
220
+ await client.connect(transport, {
221
+ timeout: DEFAULT_CONNECT_TIMEOUT_MS,
222
+ signal: request.signal,
223
+ });
224
+ throwIfAborted(request.signal, "GitNexus bridge 已取消");
225
+ const runQuery = async () => {
226
+ const queryText = request.query || request.target;
227
+ if (!queryText) {
228
+ warnings.push("缺少 query 参数,已跳过 query");
229
+ return;
230
+ }
231
+ executions.push(await callBridgeTool(client, "query", {
232
+ query: queryText,
233
+ ...(request.goal ? { goal: request.goal } : {}),
234
+ ...(request.taskContext ? { task_context: request.taskContext } : {}),
235
+ ...(effectiveRepo ? { repo: effectiveRepo } : {}),
236
+ }, request.signal));
237
+ };
238
+ const runContext = async () => {
239
+ if (!request.target) {
240
+ warnings.push("缺少 target 参数,已跳过 context");
241
+ return;
242
+ }
243
+ executions.push(await callBridgeTool(client, "context", {
244
+ name: request.target,
245
+ ...(effectiveRepo ? { repo: effectiveRepo } : {}),
246
+ }, request.signal));
247
+ };
248
+ const runImpact = async () => {
249
+ if (!request.target) {
250
+ warnings.push("缺少 target 参数,已跳过 impact");
251
+ return;
252
+ }
253
+ executions.push(await callBridgeTool(client, "impact", {
254
+ target: request.target,
255
+ direction: request.direction || "upstream",
256
+ ...(request.maxDepth ? { maxDepth: request.maxDepth } : {}),
257
+ ...(typeof request.includeTests === "boolean"
258
+ ? { includeTests: request.includeTests }
259
+ : {}),
260
+ ...(effectiveRepo ? { repo: effectiveRepo } : {}),
261
+ }, request.signal));
262
+ };
263
+ if (modeRequested === "auto") {
264
+ await runQuery();
265
+ if (request.target) {
266
+ await runContext();
267
+ }
268
+ if (request.target && request.direction) {
269
+ await runImpact();
270
+ }
271
+ }
272
+ else if (modeResolved === "query") {
273
+ await runQuery();
274
+ }
275
+ else if (modeResolved === "context") {
276
+ await runContext();
277
+ }
278
+ else {
279
+ await runImpact();
280
+ }
281
+ }
282
+ catch (error) {
283
+ if (isAbortError(error)) {
284
+ throw error;
285
+ }
286
+ const hint = stderrLogs.length > 0 ? ` (${shorten(stderrLogs.join(" | "), 180)})` : "";
287
+ const message = `GitNexus bridge 不可用:${normalizeError(error)}${hint}`;
288
+ bridgeFailureReason = message;
289
+ bridgeFailureUntil = Date.now() + FAILURE_CACHE_TTL_MS;
290
+ return {
291
+ provider: "gitnexus",
292
+ enabled: true,
293
+ available: false,
294
+ degraded: true,
295
+ modeRequested,
296
+ modeResolved,
297
+ summary: message,
298
+ executions: [],
299
+ warnings: ["bridge_unavailable", ...warnings],
300
+ repo: effectiveRepo,
301
+ };
302
+ }
303
+ finally {
304
+ await client.close().catch(() => undefined);
305
+ }
306
+ const successful = executions.filter((item) => item.ok);
307
+ const failed = executions.filter((item) => !item.ok);
308
+ bridgeFailureUntil = 0;
309
+ bridgeFailureReason = "";
310
+ if (successful.length === 0) {
311
+ const fallbackError = failed.length > 0
312
+ ? shorten(failed.map((item) => `${item.tool}: ${item.error || "unknown error"}`).join(" | "), 220)
313
+ : "未执行任何 GitNexus 调用";
314
+ return {
315
+ provider: "gitnexus",
316
+ enabled: true,
317
+ available: false,
318
+ degraded: true,
319
+ modeRequested,
320
+ modeResolved,
321
+ summary: `GitNexus bridge 已降级:${fallbackError}`,
322
+ executions,
323
+ warnings: ["bridge_call_failed", ...warnings],
324
+ repo: effectiveRepo,
325
+ };
326
+ }
327
+ const summaryParts = successful.map((item) => `${item.tool}: ${shorten(item.text || "已返回结构化结果", 110)}`);
328
+ const summary = `GitNexus 图谱增强已启用(${successful.length}/${executions.length} 成功): ${summaryParts.join(" | ")}`;
329
+ return {
330
+ provider: "gitnexus",
331
+ enabled: true,
332
+ available: true,
333
+ degraded: failed.length > 0,
334
+ modeRequested,
335
+ modeResolved,
336
+ summary,
337
+ executions,
338
+ warnings,
339
+ repo: effectiveRepo,
340
+ };
341
+ }
342
+ function toEmbeddedGraphContext(result) {
343
+ const highlights = result.executions
344
+ .filter((item) => item.ok && item.text)
345
+ .map((item) => `${item.tool}: ${shorten(item.text || "", 180)}`);
346
+ return {
347
+ enabled: result.enabled,
348
+ available: result.available,
349
+ degraded: result.degraded,
350
+ summary: result.summary,
351
+ warnings: result.warnings,
352
+ provider: result.provider,
353
+ mode: result.modeResolved,
354
+ highlights,
355
+ };
356
+ }
357
+ export async function buildFeatureGraphContext(input) {
358
+ const bridge = await runCodeInsightBridge({
359
+ mode: "query",
360
+ query: `${input.featureName} ${input.description}`,
361
+ goal: "Find related modules and execution flows for feature planning",
362
+ taskContext: "start_feature planning",
363
+ repo: input.repo,
364
+ signal: input.signal,
365
+ });
366
+ return toEmbeddedGraphContext(bridge);
367
+ }
368
+ export async function buildBugfixGraphContext(input) {
369
+ const query = [input.errorMessage, input.stackTrace].filter(Boolean).join("\n");
370
+ const bridge = await runCodeInsightBridge({
371
+ mode: "query",
372
+ query,
373
+ goal: "Find likely root-cause symbols and impacted flows for bug fixing",
374
+ taskContext: "start_bugfix diagnosis",
375
+ repo: input.repo,
376
+ signal: input.signal,
377
+ });
378
+ return toEmbeddedGraphContext(bridge);
379
+ }