@luckychen1993/pm-mcp 0.1.1
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/LICENSE +21 -0
- package/README.md +304 -0
- package/dist/acceptance-evaluator.js +330 -0
- package/dist/acceptance-model.js +440 -0
- package/dist/acceptance-report.js +335 -0
- package/dist/acceptance-tools.js +318 -0
- package/dist/audit-tools.js +61 -0
- package/dist/audit.js +364 -0
- package/dist/budget.js +71 -0
- package/dist/dashboard.js +241 -0
- package/dist/governance-audit.js +126 -0
- package/dist/governance-model.js +306 -0
- package/dist/governance-tools.js +240 -0
- package/dist/health.js +58 -0
- package/dist/index-db.js +97 -0
- package/dist/index-store.js +381 -0
- package/dist/index.js +210 -0
- package/dist/init.js +40 -0
- package/dist/knowledge-tools.js +204 -0
- package/dist/language-adapters.js +450 -0
- package/dist/language-dependencies.js +351 -0
- package/dist/license.js +261 -0
- package/dist/paths.js +51 -0
- package/dist/polyglot-ast.js +329 -0
- package/dist/portfolio.js +349 -0
- package/dist/project-fingerprint.js +83 -0
- package/dist/project-tools.js +217 -0
- package/dist/quality-store.js +77 -0
- package/dist/registry.js +38 -0
- package/dist/roadmap.js +96 -0
- package/dist/scan.js +271 -0
- package/dist/search.js +312 -0
- package/dist/security.js +269 -0
- package/dist/semantic-evidence-store.js +133 -0
- package/dist/semantic-evidence.js +100 -0
- package/dist/semantic-graph-algorithms.js +86 -0
- package/dist/semantic-graph.js +390 -0
- package/dist/semantic-parsers.js +311 -0
- package/dist/store.js +185 -0
- package/dist/task-tools.js +198 -0
- package/dist/tool-base.js +32 -0
- package/dist/tools.js +21 -0
- package/dist/types.js +208 -0
- package/dist/typescript-semantic.js +282 -0
- package/package.json +70 -0
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
import ts from "typescript";
|
|
2
|
+
const ANALYZER_ID = `typescript:compiler-api-ast@${ts.version}`;
|
|
3
|
+
function scriptKind(rel) {
|
|
4
|
+
const ext = rel.toLowerCase().split(".").pop();
|
|
5
|
+
if (ext === "tsx")
|
|
6
|
+
return ts.ScriptKind.TSX;
|
|
7
|
+
if (ext === "jsx")
|
|
8
|
+
return ts.ScriptKind.JSX;
|
|
9
|
+
if (ext === "js" || ext === "mjs" || ext === "cjs")
|
|
10
|
+
return ts.ScriptKind.JS;
|
|
11
|
+
return ts.ScriptKind.TS;
|
|
12
|
+
}
|
|
13
|
+
function stringValue(node) {
|
|
14
|
+
return node && (ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node)) ? node.text : null;
|
|
15
|
+
}
|
|
16
|
+
function bindingNames(name) {
|
|
17
|
+
if (ts.isIdentifier(name))
|
|
18
|
+
return [name.text];
|
|
19
|
+
return name.elements.flatMap((element) => ts.isOmittedExpression(element) ? [] : bindingNames(element.name));
|
|
20
|
+
}
|
|
21
|
+
function bindingIdentifiers(name) {
|
|
22
|
+
if (ts.isIdentifier(name))
|
|
23
|
+
return [name];
|
|
24
|
+
return name.elements.flatMap((element) => ts.isOmittedExpression(element) ? [] : bindingIdentifiers(element.name));
|
|
25
|
+
}
|
|
26
|
+
function inMemoryChecker(rel, source) {
|
|
27
|
+
const options = {
|
|
28
|
+
target: ts.ScriptTarget.Latest,
|
|
29
|
+
module: ts.ModuleKind.NodeNext,
|
|
30
|
+
moduleResolution: ts.ModuleResolutionKind.NodeNext,
|
|
31
|
+
allowJs: true,
|
|
32
|
+
checkJs: false,
|
|
33
|
+
noLib: true,
|
|
34
|
+
noResolve: true,
|
|
35
|
+
};
|
|
36
|
+
const normalize = (value) => value.replace(/\\/g, "/").replace(/^\.\//, "");
|
|
37
|
+
const expected = normalize(rel);
|
|
38
|
+
const host = {
|
|
39
|
+
fileExists: (fileName) => normalize(fileName) === expected,
|
|
40
|
+
readFile: (fileName) => normalize(fileName) === expected ? source.text : undefined,
|
|
41
|
+
getSourceFile: (fileName) => normalize(fileName) === expected ? source : undefined,
|
|
42
|
+
getDefaultLibFileName: () => "lib.d.ts",
|
|
43
|
+
writeFile: () => undefined,
|
|
44
|
+
getCurrentDirectory: () => "",
|
|
45
|
+
getDirectories: () => [],
|
|
46
|
+
getCanonicalFileName: normalize,
|
|
47
|
+
useCaseSensitiveFileNames: () => true,
|
|
48
|
+
getNewLine: () => "\n",
|
|
49
|
+
};
|
|
50
|
+
return ts.createProgram({ rootNames: [expected], options, host }).getTypeChecker();
|
|
51
|
+
}
|
|
52
|
+
function hasModifier(node, kind) {
|
|
53
|
+
return Boolean(ts.canHaveModifiers(node) && ts.getModifiers(node)?.some((modifier) => modifier.kind === kind));
|
|
54
|
+
}
|
|
55
|
+
function expressionRoot(expression) {
|
|
56
|
+
if (ts.isIdentifier(expression))
|
|
57
|
+
return expression;
|
|
58
|
+
if (ts.isPropertyAccessExpression(expression) || ts.isElementAccessExpression(expression))
|
|
59
|
+
return expressionRoot(expression.expression);
|
|
60
|
+
if (ts.isParenthesizedExpression(expression) || ts.isNonNullExpression(expression) || ts.isAsExpression(expression) || ts.isTypeAssertionExpression(expression)) {
|
|
61
|
+
return expressionRoot(expression.expression);
|
|
62
|
+
}
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
function expressionPath(expression) {
|
|
66
|
+
if (ts.isIdentifier(expression))
|
|
67
|
+
return expression.text;
|
|
68
|
+
if (ts.isPropertyAccessExpression(expression)) {
|
|
69
|
+
const parent = expressionPath(expression.expression);
|
|
70
|
+
return parent ? `${parent}.${expression.name.text}` : expression.name.text;
|
|
71
|
+
}
|
|
72
|
+
return "";
|
|
73
|
+
}
|
|
74
|
+
function exportedDeclarationNames(node) {
|
|
75
|
+
if (ts.isVariableStatement(node))
|
|
76
|
+
return node.declarationList.declarations.flatMap((declaration) => bindingNames(declaration.name));
|
|
77
|
+
if ((ts.isFunctionDeclaration(node) || ts.isClassDeclaration(node) || ts.isInterfaceDeclaration(node) || ts.isTypeAliasDeclaration(node) || ts.isEnumDeclaration(node) || ts.isModuleDeclaration(node)) && node.name) {
|
|
78
|
+
return ts.isIdentifier(node.name) || ts.isStringLiteral(node.name) ? [node.name.text] : [];
|
|
79
|
+
}
|
|
80
|
+
return [];
|
|
81
|
+
}
|
|
82
|
+
function diagnosticText(source, diagnostic) {
|
|
83
|
+
const position = source.getLineAndCharacterOfPosition(diagnostic.start);
|
|
84
|
+
return `${position.line + 1}:${position.character + 1} ${ts.flattenDiagnosticMessageText(diagnostic.messageText, " ")}`;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Syntax-semantic extraction backed by the same parser TypeScript uses to compile TS/JS.
|
|
88
|
+
* Calls are conservative syntactic uses of imported bindings; execution and dynamic
|
|
89
|
+
* dispatch still require runtime evidence.
|
|
90
|
+
*/
|
|
91
|
+
export function analyzeTypeScriptSource(rel, content) {
|
|
92
|
+
const source = ts.createSourceFile(rel, content, ts.ScriptTarget.Latest, true, scriptKind(rel));
|
|
93
|
+
const checker = inMemoryChecker(rel, source);
|
|
94
|
+
const parseDiagnostics = source.parseDiagnostics ?? [];
|
|
95
|
+
const diagnostics = parseDiagnostics.map((diagnostic) => diagnosticText(source, diagnostic));
|
|
96
|
+
const references = [];
|
|
97
|
+
const exports = [];
|
|
98
|
+
const symbolBindings = new Map();
|
|
99
|
+
const lineOf = (node) => source.getLineAndCharacterOfPosition(node.getStart(source, false)).line + 1;
|
|
100
|
+
const addReference = (node, kind, specifier, confidence, forceLocal = false, symbol) => {
|
|
101
|
+
if (!specifier.trim())
|
|
102
|
+
return;
|
|
103
|
+
references.push({ kind, specifier: specifier.trim(), line: lineOf(node), parser: ANALYZER_ID, confidence, forceLocal, offset: node.getStart(source, false), symbol });
|
|
104
|
+
};
|
|
105
|
+
const addExport = (node, name, typeOnly, sourceSpecifier) => {
|
|
106
|
+
exports.push({ name, line: lineOf(node), isTypeOnly: typeOnly, sourceSpecifier, parser: ANALYZER_ID, confidence: 0.99 });
|
|
107
|
+
};
|
|
108
|
+
const storeBinding = (identifier, binding) => {
|
|
109
|
+
const symbol = checker.getSymbolAtLocation(identifier);
|
|
110
|
+
if (symbol)
|
|
111
|
+
symbolBindings.set(symbol, binding);
|
|
112
|
+
};
|
|
113
|
+
const registerImportClause = (clause, specifier) => {
|
|
114
|
+
if (!clause)
|
|
115
|
+
return;
|
|
116
|
+
if (clause.name)
|
|
117
|
+
storeBinding(clause.name, { specifier, namespace: false, typeOnly: clause.isTypeOnly, imported: "default" });
|
|
118
|
+
if (clause.namedBindings && ts.isNamespaceImport(clause.namedBindings)) {
|
|
119
|
+
storeBinding(clause.namedBindings.name, { specifier, namespace: true, typeOnly: clause.isTypeOnly, imported: "*" });
|
|
120
|
+
}
|
|
121
|
+
else if (clause.namedBindings) {
|
|
122
|
+
for (const element of clause.namedBindings.elements) {
|
|
123
|
+
storeBinding(element.name, {
|
|
124
|
+
specifier,
|
|
125
|
+
namespace: false,
|
|
126
|
+
typeOnly: clause.isTypeOnly || element.isTypeOnly,
|
|
127
|
+
imported: element.propertyName?.text ?? element.name.text,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
const registerRequireBinding = (name, specifier) => {
|
|
133
|
+
if (ts.isIdentifier(name)) {
|
|
134
|
+
storeBinding(name, { specifier, namespace: true, typeOnly: false, imported: "*" });
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
if (!ts.isObjectBindingPattern(name))
|
|
138
|
+
return;
|
|
139
|
+
for (const element of name.elements) {
|
|
140
|
+
for (const identifier of bindingIdentifiers(element.name)) {
|
|
141
|
+
const local = identifier.text;
|
|
142
|
+
const imported = element.propertyName && (ts.isIdentifier(element.propertyName) || ts.isStringLiteral(element.propertyName))
|
|
143
|
+
? element.propertyName.text
|
|
144
|
+
: local;
|
|
145
|
+
storeBinding(identifier, { specifier, namespace: false, typeOnly: false, imported });
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
const requireSpecifier = (expression) => {
|
|
150
|
+
if (!expression || !ts.isCallExpression(expression) || !ts.isIdentifier(expression.expression) || expression.expression.text !== "require")
|
|
151
|
+
return null;
|
|
152
|
+
return stringValue(expression.arguments[0]);
|
|
153
|
+
};
|
|
154
|
+
const collectDeclarations = (node) => {
|
|
155
|
+
if (ts.isImportDeclaration(node)) {
|
|
156
|
+
const specifier = stringValue(node.moduleSpecifier);
|
|
157
|
+
if (specifier) {
|
|
158
|
+
addReference(node, "import", specifier, 0.99, specifier.startsWith("."));
|
|
159
|
+
registerImportClause(node.importClause, specifier);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
else if (ts.isImportEqualsDeclaration(node) && ts.isExternalModuleReference(node.moduleReference)) {
|
|
163
|
+
const specifier = stringValue(node.moduleReference.expression);
|
|
164
|
+
if (specifier) {
|
|
165
|
+
addReference(node, "import", specifier, 0.98, specifier.startsWith("."));
|
|
166
|
+
storeBinding(node.name, { specifier, namespace: true, typeOnly: node.isTypeOnly, imported: "*" });
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
else if (ts.isVariableDeclaration(node)) {
|
|
170
|
+
const specifier = requireSpecifier(node.initializer);
|
|
171
|
+
if (specifier) {
|
|
172
|
+
addReference(node, "import", specifier, 0.98, specifier.startsWith("."));
|
|
173
|
+
registerRequireBinding(node.name, specifier);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
else if (ts.isExportDeclaration(node)) {
|
|
177
|
+
const specifier = stringValue(node.moduleSpecifier);
|
|
178
|
+
if (specifier)
|
|
179
|
+
addReference(node, "export", specifier, 0.99, specifier.startsWith("."));
|
|
180
|
+
if (!node.exportClause) {
|
|
181
|
+
addExport(node, "*", node.isTypeOnly, specifier ?? undefined);
|
|
182
|
+
}
|
|
183
|
+
else if (ts.isNamespaceExport(node.exportClause)) {
|
|
184
|
+
addExport(node.exportClause, node.exportClause.name.text, node.isTypeOnly, specifier ?? undefined);
|
|
185
|
+
}
|
|
186
|
+
else {
|
|
187
|
+
for (const element of node.exportClause.elements)
|
|
188
|
+
addExport(element, element.name.text, node.isTypeOnly || element.isTypeOnly, specifier ?? undefined);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
else if (hasModifier(node, ts.SyntaxKind.ExportKeyword)) {
|
|
192
|
+
const names = exportedDeclarationNames(node);
|
|
193
|
+
const isDefault = hasModifier(node, ts.SyntaxKind.DefaultKeyword);
|
|
194
|
+
if (isDefault)
|
|
195
|
+
addExport(node, "default", false);
|
|
196
|
+
else
|
|
197
|
+
for (const name of names)
|
|
198
|
+
addExport(node, name, ts.isInterfaceDeclaration(node) || ts.isTypeAliasDeclaration(node));
|
|
199
|
+
}
|
|
200
|
+
else if (ts.isExportAssignment(node)) {
|
|
201
|
+
addExport(node, node.isExportEquals ? "export=" : "default", false);
|
|
202
|
+
}
|
|
203
|
+
ts.forEachChild(node, collectDeclarations);
|
|
204
|
+
};
|
|
205
|
+
collectDeclarations(source);
|
|
206
|
+
const collectUses = (node) => {
|
|
207
|
+
if (ts.isCallExpression(node)) {
|
|
208
|
+
if (node.expression.kind === ts.SyntaxKind.ImportKeyword) {
|
|
209
|
+
const specifier = stringValue(node.arguments[0]);
|
|
210
|
+
if (specifier)
|
|
211
|
+
addReference(node, "import", specifier, 0.98, specifier.startsWith("."));
|
|
212
|
+
}
|
|
213
|
+
else if (!(ts.isIdentifier(node.expression) && node.expression.text === "require")) {
|
|
214
|
+
const root = expressionRoot(node.expression);
|
|
215
|
+
const rootSymbol = root ? checker.getSymbolAtLocation(root) : undefined;
|
|
216
|
+
const binding = rootSymbol ? symbolBindings.get(rootSymbol) : undefined;
|
|
217
|
+
if (binding && !binding.typeOnly)
|
|
218
|
+
addReference(node, "call", binding.specifier, 0.94, binding.specifier.startsWith("."), binding.imported);
|
|
219
|
+
const callee = expressionPath(node.expression);
|
|
220
|
+
const firstArgument = stringValue(node.arguments[0]);
|
|
221
|
+
if (firstArgument && (/^(?:fetch|axios\.(?:get|post|put|patch|delete)|http\.(?:get|post))$/i.test(callee))) {
|
|
222
|
+
addReference(node, "http", firstArgument, 0.96);
|
|
223
|
+
}
|
|
224
|
+
if (firstArgument && /^(?:grpc\.(?:dial|insecure_channel|secure_channel)|grpcchannel\.foraddress)$/i.test(callee)) {
|
|
225
|
+
addReference(node, "grpc", firstArgument, 0.94);
|
|
226
|
+
}
|
|
227
|
+
if (firstArgument && /^(?:ffi\.library|dlopen)$/i.test(callee))
|
|
228
|
+
addReference(node, "ffi", firstArgument, 0.94);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
else if (ts.isNewExpression(node)) {
|
|
232
|
+
const root = expressionRoot(node.expression);
|
|
233
|
+
const rootSymbol = root ? checker.getSymbolAtLocation(root) : undefined;
|
|
234
|
+
const binding = rootSymbol ? symbolBindings.get(rootSymbol) : undefined;
|
|
235
|
+
if (binding && !binding.typeOnly)
|
|
236
|
+
addReference(node, "call", binding.specifier, 0.94, binding.specifier.startsWith("."), binding.imported);
|
|
237
|
+
const firstArgument = stringValue(node.arguments?.[0]);
|
|
238
|
+
if (firstArgument && /(?:Client|Stub)$/.test(expressionPath(node.expression)))
|
|
239
|
+
addReference(node, "grpc", firstArgument, 0.86);
|
|
240
|
+
}
|
|
241
|
+
else if (ts.isStringLiteralLike(node)) {
|
|
242
|
+
const value = node.text;
|
|
243
|
+
const pathPart = value.split("#", 1)[0].replace(/\\/g, "/");
|
|
244
|
+
const basename = pathPart.split("/").at(-1) ?? "";
|
|
245
|
+
// Extension constants such as ".proto" are metadata, not contract links.
|
|
246
|
+
// Requiring a real basename keeps AST evidence precise while still
|
|
247
|
+
// accepting both nearby files (service.proto) and relative paths.
|
|
248
|
+
if (/^[^.\s][^/\s]*\.(?:proto|graphql|gql)$/i.test(basename))
|
|
249
|
+
addReference(node, "contract", value, 0.98, true);
|
|
250
|
+
else if (/^[^.\s][^/\s]*(?:openapi|swagger|asyncapi|contracts?|schemas?)[^/\s]*\.(?:ya?ml|json)$/i.test(basename))
|
|
251
|
+
addReference(node, "contract", value, 0.95, true);
|
|
252
|
+
}
|
|
253
|
+
else if (ts.isTaggedTemplateExpression(node) && /^(?:gql|graphql)$/.test(expressionPath(node.tag))) {
|
|
254
|
+
addReference(node, "contract", "inline GraphQL", 0.96);
|
|
255
|
+
}
|
|
256
|
+
ts.forEachChild(node, collectUses);
|
|
257
|
+
};
|
|
258
|
+
collectUses(source);
|
|
259
|
+
const uniqueReferences = [...new Map(references.map((reference) => [
|
|
260
|
+
`${reference.kind}|${reference.line}|${reference.specifier}|${reference.offset ?? ""}`,
|
|
261
|
+
reference,
|
|
262
|
+
])).values()];
|
|
263
|
+
const uniqueExports = [...new Map(exports.map((item) => [`${item.name}|${item.line}|${item.sourceSpecifier ?? ""}`, item])).values()];
|
|
264
|
+
return {
|
|
265
|
+
references: uniqueReferences,
|
|
266
|
+
exports: uniqueExports,
|
|
267
|
+
analyzer: {
|
|
268
|
+
id: ANALYZER_ID,
|
|
269
|
+
family: "compiler-ast",
|
|
270
|
+
assurance: "ast",
|
|
271
|
+
engine: "TypeScript Compiler API",
|
|
272
|
+
version: ts.version,
|
|
273
|
+
capabilities: ["imports", "exports", "calls", "contracts", "http", "grpc", "ffi"],
|
|
274
|
+
},
|
|
275
|
+
status: diagnostics.length === 0 ? "complete" : "partial",
|
|
276
|
+
diagnostics,
|
|
277
|
+
limitations: [
|
|
278
|
+
"AST call edges prove syntactic use of an imported binding, not runtime execution.",
|
|
279
|
+
"Generated code, reflection, dependency-injection containers, and data-driven dispatch require imported native or runtime evidence.",
|
|
280
|
+
],
|
|
281
|
+
};
|
|
282
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@luckychen1993/pm-mcp",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "AI 编码项目的单一事实来源 + 健康台账 MCP 服务(事实来源 / 路线图 / 防幻觉 / 七本账 / 断点续做 / token 经济)",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"mcp",
|
|
7
|
+
"model-context-protocol",
|
|
8
|
+
"ai-coding",
|
|
9
|
+
"project-management",
|
|
10
|
+
"code-governance"
|
|
11
|
+
],
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"type": "module",
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "git+https://github.com/happy520ai/pm-mcp.git"
|
|
17
|
+
},
|
|
18
|
+
"homepage": "https://github.com/happy520ai/pm-mcp#readme",
|
|
19
|
+
"bugs": {
|
|
20
|
+
"url": "https://github.com/happy520ai/pm-mcp/issues"
|
|
21
|
+
},
|
|
22
|
+
"publishConfig": {
|
|
23
|
+
"access": "public"
|
|
24
|
+
},
|
|
25
|
+
"files": [
|
|
26
|
+
"dist/"
|
|
27
|
+
],
|
|
28
|
+
"bin": {
|
|
29
|
+
"pm-mcp": "dist/index.js"
|
|
30
|
+
},
|
|
31
|
+
"main": "dist/index.js",
|
|
32
|
+
"engines": {
|
|
33
|
+
"node": ">=22.18.0"
|
|
34
|
+
},
|
|
35
|
+
"scripts": {
|
|
36
|
+
"build": "tsc -p tsconfig.json",
|
|
37
|
+
"prepare": "npm run build",
|
|
38
|
+
"typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.scripts.json",
|
|
39
|
+
"test": "node --test \"test/*.test.ts\"",
|
|
40
|
+
"coverage": "node --experimental-test-coverage --test-coverage-include=\"src/**/*.ts\" --test-coverage-lines=90 --test-coverage-branches=85 --test-coverage-functions=90 --test \"test/*.test.ts\"",
|
|
41
|
+
"audit": "node scripts/health-check.mts",
|
|
42
|
+
"benchmark": "node scripts/benchmark.mts",
|
|
43
|
+
"benchmark:volume": "node scripts/benchmark-volume.mts",
|
|
44
|
+
"quality": "node scripts/quality-gate.mts",
|
|
45
|
+
"quality:plan": "node scripts/quality-gate.mts --plan",
|
|
46
|
+
"acceptance:evidence": "node scripts/collect-acceptance-evidence.mts --root .",
|
|
47
|
+
"acceptance:prepare": "node scripts/create-pm-acceptance-evaluation.mts --root .",
|
|
48
|
+
"acceptance": "node scripts/acceptance-gate.mts --root . --baseline-id pm-mcp-local-release --baseline-version 1.0.0 --evaluation .pm/acceptance/evaluations/pm-mcp-local-release-1.0.0.json",
|
|
49
|
+
"acceptance:cycle": "node scripts/acceptance-cycle.mts --root .",
|
|
50
|
+
"gate": "npm run audit -- --root . && npm run quality && npm run acceptance:cycle",
|
|
51
|
+
"start": "node dist/index.js",
|
|
52
|
+
"dev": "node src/index.ts",
|
|
53
|
+
"inspect": "node dist/index.js"
|
|
54
|
+
},
|
|
55
|
+
"dependencies": {
|
|
56
|
+
"@ast-grep/lang-csharp": "0.0.6",
|
|
57
|
+
"@ast-grep/lang-go": "0.0.6",
|
|
58
|
+
"@ast-grep/lang-java": "0.0.7",
|
|
59
|
+
"@ast-grep/lang-kotlin": "0.0.7",
|
|
60
|
+
"@ast-grep/lang-python": "0.0.6",
|
|
61
|
+
"@ast-grep/lang-rust": "0.0.7",
|
|
62
|
+
"@ast-grep/napi": "0.45.3",
|
|
63
|
+
"@modelcontextprotocol/sdk": "^1.30.0",
|
|
64
|
+
"typescript": "^5.9.3",
|
|
65
|
+
"zod": "^3.25.76"
|
|
66
|
+
},
|
|
67
|
+
"devDependencies": {
|
|
68
|
+
"@types/node": "^26.4.0"
|
|
69
|
+
}
|
|
70
|
+
}
|