prinfer 0.5.2 → 0.6.0
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 +26 -21
- package/dist/cli.cjs +279 -130
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +278 -130
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +298 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +66 -1
- package/dist/index.d.ts +66 -1
- package/dist/index.js +294 -12
- package/dist/index.js.map +1 -1
- package/dist/mcp.cjs +233 -85
- package/dist/mcp.cjs.map +1 -1
- package/dist/mcp.js +233 -85
- package/dist/mcp.js.map +1 -1
- package/dist/postinstall.cjs +2 -25
- package/dist/postinstall.cjs.map +1 -1
- package/dist/postinstall.js +2 -25
- package/dist/postinstall.js.map +1 -1
- package/package.json +1 -1
package/dist/mcp.js
CHANGED
|
@@ -48,66 +48,203 @@ function loadProgram(entryFileAbs, project) {
|
|
|
48
48
|
function isArrowOrFnExpr(n) {
|
|
49
49
|
return !!n && (ts.isArrowFunction(n) || ts.isFunctionExpression(n));
|
|
50
50
|
}
|
|
51
|
-
function
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
if ((ts.isMethodDeclaration(node) || ts.isMethodSignature(node)) && nodeNameText(node.name) === name) {
|
|
64
|
-
return true;
|
|
65
|
-
}
|
|
66
|
-
if (ts.isPropertyAssignment(node) && nodeNameText(node.name) === name) {
|
|
67
|
-
return isArrowOrFnExpr(node.initializer);
|
|
51
|
+
function findSmallestNodeAtPosition(sourceFile, position) {
|
|
52
|
+
let result;
|
|
53
|
+
function visit(node) {
|
|
54
|
+
const start = node.getStart(sourceFile);
|
|
55
|
+
const end = node.getEnd();
|
|
56
|
+
if (position < start || position >= end) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
if (!result || node.getWidth(sourceFile) <= result.getWidth(sourceFile)) {
|
|
60
|
+
result = node;
|
|
61
|
+
}
|
|
62
|
+
ts.forEachChild(node, visit);
|
|
68
63
|
}
|
|
69
|
-
|
|
64
|
+
visit(sourceFile);
|
|
65
|
+
return result;
|
|
70
66
|
}
|
|
71
|
-
function
|
|
72
|
-
|
|
67
|
+
function findHoverableAncestor(sourceFile, position) {
|
|
68
|
+
const smallestNode = findSmallestNodeAtPosition(sourceFile, position);
|
|
69
|
+
if (!smallestNode) return void 0;
|
|
70
|
+
let bestMatch = smallestNode;
|
|
71
|
+
function visit(n) {
|
|
72
|
+
const start = n.getStart(sourceFile);
|
|
73
|
+
const end = n.getEnd();
|
|
74
|
+
if (position < start || position >= end) {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
if (ts.isCallExpression(n)) {
|
|
78
|
+
const expr = n.expression;
|
|
79
|
+
if (ts.isIdentifier(expr)) {
|
|
80
|
+
if (position >= expr.getStart(sourceFile) && position < expr.getEnd()) {
|
|
81
|
+
bestMatch = n;
|
|
82
|
+
}
|
|
83
|
+
} else if (ts.isPropertyAccessExpression(expr)) {
|
|
84
|
+
if (position >= expr.name.getStart(sourceFile) && position < expr.name.getEnd()) {
|
|
85
|
+
bestMatch = n;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
if (ts.isFunctionDeclaration(n) && n.name) {
|
|
90
|
+
if (position >= n.name.getStart(sourceFile) && position < n.name.getEnd()) {
|
|
91
|
+
bestMatch = n;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
if (ts.isVariableDeclaration(n) && ts.isIdentifier(n.name)) {
|
|
95
|
+
if (position >= n.name.getStart(sourceFile) && position < n.name.getEnd()) {
|
|
96
|
+
bestMatch = n;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
if ((ts.isMethodDeclaration(n) || ts.isMethodSignature(n)) && ts.isIdentifier(n.name)) {
|
|
100
|
+
if (position >= n.name.getStart(sourceFile) && position < n.name.getEnd()) {
|
|
101
|
+
bestMatch = n;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
if (ts.isClassDeclaration(n) && n.name) {
|
|
105
|
+
if (position >= n.name.getStart(sourceFile) && position < n.name.getEnd()) {
|
|
106
|
+
bestMatch = n;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
if (ts.isInterfaceDeclaration(n) && n.name) {
|
|
110
|
+
if (position >= n.name.getStart(sourceFile) && position < n.name.getEnd()) {
|
|
111
|
+
bestMatch = n;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
ts.forEachChild(n, visit);
|
|
73
115
|
return true;
|
|
74
116
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
function isNamedNode(node, name) {
|
|
78
|
-
return isFunctionLikeNamed(node, name) || isVariableNamed(node, name);
|
|
117
|
+
visit(sourceFile);
|
|
118
|
+
return bestMatch;
|
|
79
119
|
}
|
|
80
|
-
function
|
|
81
|
-
const
|
|
82
|
-
|
|
120
|
+
function findNodeAtPosition(sourceFile, line, column) {
|
|
121
|
+
const lineCount = sourceFile.getLineStarts().length;
|
|
122
|
+
if (line < 1 || line > lineCount) {
|
|
123
|
+
return void 0;
|
|
124
|
+
}
|
|
125
|
+
const lineStart = sourceFile.getLineStarts()[line - 1];
|
|
126
|
+
const lineEnd = line < lineCount ? sourceFile.getLineStarts()[line] : sourceFile.getEnd();
|
|
127
|
+
const lineLength = lineEnd - lineStart;
|
|
128
|
+
if (column < 1 || column > lineLength + 1) {
|
|
129
|
+
return void 0;
|
|
130
|
+
}
|
|
131
|
+
const position = sourceFile.getPositionOfLineAndCharacter(
|
|
132
|
+
line - 1,
|
|
133
|
+
column - 1
|
|
83
134
|
);
|
|
84
|
-
return
|
|
135
|
+
return findHoverableAncestor(sourceFile, position);
|
|
85
136
|
}
|
|
86
|
-
function
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
}
|
|
97
|
-
} else {
|
|
98
|
-
found = node;
|
|
99
|
-
return;
|
|
100
|
-
}
|
|
137
|
+
function getSymbolKind(node) {
|
|
138
|
+
if (ts.isFunctionDeclaration(node)) return "function";
|
|
139
|
+
if (ts.isArrowFunction(node)) return "function";
|
|
140
|
+
if (ts.isFunctionExpression(node)) return "function";
|
|
141
|
+
if (ts.isMethodDeclaration(node)) return "method";
|
|
142
|
+
if (ts.isMethodSignature(node)) return "method";
|
|
143
|
+
if (ts.isVariableDeclaration(node)) {
|
|
144
|
+
const init = node.initializer;
|
|
145
|
+
if (init && (ts.isArrowFunction(init) || ts.isFunctionExpression(init))) {
|
|
146
|
+
return "function";
|
|
101
147
|
}
|
|
102
|
-
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
return
|
|
148
|
+
return "variable";
|
|
149
|
+
}
|
|
150
|
+
if (ts.isParameter(node)) return "parameter";
|
|
151
|
+
if (ts.isPropertyDeclaration(node)) return "property";
|
|
152
|
+
if (ts.isPropertySignature(node)) return "property";
|
|
153
|
+
if (ts.isPropertyAccessExpression(node)) return "property";
|
|
154
|
+
if (ts.isCallExpression(node)) return "call";
|
|
155
|
+
if (ts.isTypeAliasDeclaration(node)) return "type";
|
|
156
|
+
if (ts.isInterfaceDeclaration(node)) return "interface";
|
|
157
|
+
if (ts.isClassDeclaration(node)) return "class";
|
|
158
|
+
if (ts.isIdentifier(node)) return "identifier";
|
|
159
|
+
return "unknown";
|
|
106
160
|
}
|
|
107
|
-
function
|
|
161
|
+
function getNodeName(node) {
|
|
162
|
+
if (ts.isFunctionDeclaration(node) && node.name) {
|
|
163
|
+
return node.name.text;
|
|
164
|
+
}
|
|
165
|
+
if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name)) {
|
|
166
|
+
return node.name.text;
|
|
167
|
+
}
|
|
168
|
+
if ((ts.isMethodDeclaration(node) || ts.isMethodSignature(node)) && ts.isIdentifier(node.name)) {
|
|
169
|
+
return node.name.text;
|
|
170
|
+
}
|
|
171
|
+
if (ts.isPropertyAccessExpression(node)) {
|
|
172
|
+
return node.name.text;
|
|
173
|
+
}
|
|
174
|
+
if (ts.isCallExpression(node)) {
|
|
175
|
+
const expr = node.expression;
|
|
176
|
+
if (ts.isIdentifier(expr)) return expr.text;
|
|
177
|
+
if (ts.isPropertyAccessExpression(expr)) return expr.name.text;
|
|
178
|
+
}
|
|
179
|
+
if (ts.isParameter(node) && ts.isIdentifier(node.name)) {
|
|
180
|
+
return node.name.text;
|
|
181
|
+
}
|
|
182
|
+
if (ts.isIdentifier(node)) {
|
|
183
|
+
return node.text;
|
|
184
|
+
}
|
|
185
|
+
if (ts.isTypeAliasDeclaration(node) || ts.isInterfaceDeclaration(node) || ts.isClassDeclaration(node)) {
|
|
186
|
+
return node.name?.text;
|
|
187
|
+
}
|
|
188
|
+
return void 0;
|
|
189
|
+
}
|
|
190
|
+
function getDocumentation(checker, symbol) {
|
|
191
|
+
if (!symbol) return void 0;
|
|
192
|
+
const docs = symbol.getDocumentationComment(checker);
|
|
193
|
+
if (docs.length === 0) return void 0;
|
|
194
|
+
return ts.displayPartsToString(docs);
|
|
195
|
+
}
|
|
196
|
+
function getHoverInfo(program, node, sourceFile, includeDocs) {
|
|
108
197
|
const checker = program.getTypeChecker();
|
|
109
|
-
const sf = sourceFile
|
|
110
|
-
const line =
|
|
198
|
+
const sf = sourceFile;
|
|
199
|
+
const { line, character } = sf.getLineAndCharacterOfPosition(
|
|
200
|
+
node.getStart(sf)
|
|
201
|
+
);
|
|
202
|
+
const flags = ts.TypeFormatFlags.NoTruncation;
|
|
203
|
+
const kind = getSymbolKind(node);
|
|
204
|
+
const name = getNodeName(node);
|
|
205
|
+
let symbol;
|
|
206
|
+
if (ts.isCallExpression(node)) {
|
|
207
|
+
const expr = node.expression;
|
|
208
|
+
if (ts.isPropertyAccessExpression(expr)) {
|
|
209
|
+
symbol = checker.getSymbolAtLocation(expr.name);
|
|
210
|
+
} else {
|
|
211
|
+
symbol = checker.getSymbolAtLocation(expr);
|
|
212
|
+
}
|
|
213
|
+
} else {
|
|
214
|
+
const nodeWithName2 = node;
|
|
215
|
+
if (nodeWithName2.name) {
|
|
216
|
+
symbol = checker.getSymbolAtLocation(nodeWithName2.name);
|
|
217
|
+
} else {
|
|
218
|
+
symbol = checker.getSymbolAtLocation(node);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
const documentation = includeDocs ? getDocumentation(checker, symbol) : void 0;
|
|
222
|
+
if (ts.isCallExpression(node)) {
|
|
223
|
+
const sig2 = checker.getResolvedSignature(node);
|
|
224
|
+
if (sig2) {
|
|
225
|
+
const signature = checker.signatureToString(sig2, void 0, flags);
|
|
226
|
+
const ret = checker.getReturnTypeOfSignature(sig2);
|
|
227
|
+
const returnType = checker.typeToString(ret, void 0, flags);
|
|
228
|
+
return {
|
|
229
|
+
signature,
|
|
230
|
+
returnType,
|
|
231
|
+
line: line + 1,
|
|
232
|
+
column: character + 1,
|
|
233
|
+
documentation,
|
|
234
|
+
kind,
|
|
235
|
+
name
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
const t2 = checker.getTypeAtLocation(node);
|
|
239
|
+
return {
|
|
240
|
+
signature: checker.typeToString(t2, void 0, flags),
|
|
241
|
+
line: line + 1,
|
|
242
|
+
column: character + 1,
|
|
243
|
+
documentation,
|
|
244
|
+
kind,
|
|
245
|
+
name
|
|
246
|
+
};
|
|
247
|
+
}
|
|
111
248
|
let sig;
|
|
112
249
|
if (ts.isFunctionDeclaration(node) || ts.isMethodDeclaration(node)) {
|
|
113
250
|
sig = checker.getSignatureFromDeclaration(node) ?? void 0;
|
|
@@ -122,26 +259,39 @@ function getTypeInfo(program, node, sourceFile) {
|
|
|
122
259
|
} else if (ts.isMethodSignature(node)) {
|
|
123
260
|
sig = checker.getSignatureFromDeclaration(node) ?? void 0;
|
|
124
261
|
}
|
|
125
|
-
const flags = ts.TypeFormatFlags.NoTruncation;
|
|
126
262
|
if (sig) {
|
|
127
263
|
const signature = checker.signatureToString(sig, void 0, flags);
|
|
128
264
|
const ret = checker.getReturnTypeOfSignature(sig);
|
|
129
265
|
const returnType = checker.typeToString(ret, void 0, flags);
|
|
130
|
-
return {
|
|
266
|
+
return {
|
|
267
|
+
signature,
|
|
268
|
+
returnType,
|
|
269
|
+
line: line + 1,
|
|
270
|
+
column: character + 1,
|
|
271
|
+
documentation,
|
|
272
|
+
kind,
|
|
273
|
+
name
|
|
274
|
+
};
|
|
131
275
|
}
|
|
132
276
|
const nodeWithName = node;
|
|
133
|
-
let
|
|
277
|
+
let targetNode = node;
|
|
134
278
|
if (nodeWithName.name && ts.isIdentifier(nodeWithName.name)) {
|
|
135
|
-
|
|
279
|
+
targetNode = nodeWithName.name;
|
|
136
280
|
}
|
|
137
|
-
const t = checker.getTypeAtLocation(
|
|
138
|
-
return {
|
|
281
|
+
const t = checker.getTypeAtLocation(targetNode);
|
|
282
|
+
return {
|
|
283
|
+
signature: checker.typeToString(t, void 0, flags),
|
|
284
|
+
line: line + 1,
|
|
285
|
+
column: character + 1,
|
|
286
|
+
documentation,
|
|
287
|
+
kind,
|
|
288
|
+
name
|
|
289
|
+
};
|
|
139
290
|
}
|
|
140
291
|
|
|
141
292
|
// src/index.ts
|
|
142
|
-
function
|
|
143
|
-
const
|
|
144
|
-
const { line, project } = opts;
|
|
293
|
+
function hover(file, line, column, options) {
|
|
294
|
+
const { project, include_docs = false } = options ?? {};
|
|
145
295
|
const entryFileAbs = path2.resolve(process.cwd(), file);
|
|
146
296
|
if (!fs.existsSync(entryFileAbs)) {
|
|
147
297
|
throw new Error(`File not found: ${entryFileAbs}`);
|
|
@@ -153,14 +303,11 @@ function inferType(file, name, options) {
|
|
|
153
303
|
`Could not load source file into the program (check tsconfig include/exclude): ${entryFileAbs}`
|
|
154
304
|
);
|
|
155
305
|
}
|
|
156
|
-
const node =
|
|
306
|
+
const node = findNodeAtPosition(sourceFile, line, column);
|
|
157
307
|
if (!node) {
|
|
158
|
-
|
|
159
|
-
throw new Error(
|
|
160
|
-
`No symbol named "${name}"${lineInfo} found in ${entryFileAbs}`
|
|
161
|
-
);
|
|
308
|
+
throw new Error(`No symbol found at ${entryFileAbs}:${line}:${column}`);
|
|
162
309
|
}
|
|
163
|
-
return
|
|
310
|
+
return getHoverInfo(program, node, sourceFile, include_docs);
|
|
164
311
|
}
|
|
165
312
|
|
|
166
313
|
// src/mcp.ts
|
|
@@ -174,19 +321,11 @@ Setup:
|
|
|
174
321
|
Run 'prinfer setup' to configure Claude Code automatically.
|
|
175
322
|
|
|
176
323
|
Manual setup:
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
{
|
|
180
|
-
"mcpServers": {
|
|
181
|
-
"prinfer": {
|
|
182
|
-
"command": "prinfer-mcp"
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
}
|
|
324
|
+
Run: claude mcp add prinfer node /path/to/prinfer-mcp
|
|
186
325
|
|
|
187
326
|
Provided tools:
|
|
188
|
-
|
|
189
|
-
|
|
327
|
+
hover(file, line, column, include_docs?, project?)
|
|
328
|
+
Get TypeScript type information at a specific position.
|
|
190
329
|
|
|
191
330
|
See also:
|
|
192
331
|
prinfer --help CLI for direct type inspection
|
|
@@ -197,28 +336,37 @@ if (process.argv.includes("--help") || process.argv.includes("-h")) {
|
|
|
197
336
|
}
|
|
198
337
|
var server = new McpServer({
|
|
199
338
|
name: "prinfer",
|
|
200
|
-
version: "0.
|
|
339
|
+
version: "0.3.0"
|
|
201
340
|
});
|
|
202
341
|
server.tool(
|
|
203
|
-
"
|
|
204
|
-
"
|
|
342
|
+
"hover",
|
|
343
|
+
"Get TypeScript type information at a specific position in a file. Returns the type signature, return type, documentation, and symbol kind.",
|
|
205
344
|
{
|
|
206
345
|
file: z.string().describe("Path to the TypeScript file"),
|
|
207
|
-
|
|
208
|
-
|
|
346
|
+
line: z.number().describe("1-based line number"),
|
|
347
|
+
column: z.number().describe("1-based column (character position)"),
|
|
348
|
+
include_docs: z.boolean().optional().describe("Include JSDoc/TSDoc documentation"),
|
|
209
349
|
project: z.string().optional().describe("Optional path to tsconfig.json")
|
|
210
350
|
},
|
|
211
|
-
async ({ file,
|
|
351
|
+
async ({ file, line, column, include_docs, project }) => {
|
|
212
352
|
try {
|
|
213
|
-
const result =
|
|
353
|
+
const result = hover(file, line, column, { include_docs, project });
|
|
214
354
|
let text = `Type: ${result.signature}`;
|
|
215
355
|
if (result.returnType) {
|
|
216
356
|
text += `
|
|
217
357
|
Returns: ${result.returnType}`;
|
|
218
358
|
}
|
|
219
|
-
if (result.
|
|
359
|
+
if (result.name) {
|
|
360
|
+
text += `
|
|
361
|
+
Name: ${result.name}`;
|
|
362
|
+
}
|
|
363
|
+
text += `
|
|
364
|
+
Kind: ${result.kind}`;
|
|
365
|
+
text += `
|
|
366
|
+
Position: ${result.line}:${result.column}`;
|
|
367
|
+
if (result.documentation) {
|
|
220
368
|
text += `
|
|
221
|
-
|
|
369
|
+
Documentation: ${result.documentation}`;
|
|
222
370
|
}
|
|
223
371
|
return { content: [{ type: "text", text }] };
|
|
224
372
|
} catch (error) {
|
package/dist/mcp.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/mcp.ts","../src/index.ts","../src/core.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { z } from \"zod\";\nimport { inferType } from \"./index.js\";\n\nconst HELP = `\nprinfer-mcp - MCP server for TypeScript type inference\n\nThis is an MCP (Model Context Protocol) server. It's designed to be run\nby Claude Code, not directly from the command line.\n\nSetup:\n Run 'prinfer setup' to configure Claude Code automatically.\n\nManual setup:\n Add to ~/.claude/settings.json:\n\n {\n \"mcpServers\": {\n \"prinfer\": {\n \"command\": \"prinfer-mcp\"\n }\n }\n }\n\nProvided tools:\n infer_type(file, name, line?, project?)\n Infer the TypeScript type of a function or variable.\n\nSee also:\n prinfer --help CLI for direct type inspection\n`.trim();\n\nif (process.argv.includes(\"--help\") || process.argv.includes(\"-h\")) {\n\tconsole.log(HELP);\n\tprocess.exit(0);\n}\n\nconst server = new McpServer({\n\tname: \"prinfer\",\n\tversion: \"0.2.1\",\n});\n\nserver.tool(\n\t\"infer_type\",\n\t\"Infer the TypeScript type of a function or variable in a file. Returns the type signature and optionally the return type for functions.\",\n\t{\n\t\tfile: z.string().describe(\"Path to the TypeScript file\"),\n\t\tname: z\n\t\t\t.string()\n\t\t\t.describe(\"Name of the function or variable to inspect\"),\n\t\tline: z\n\t\t\t.number()\n\t\t\t.optional()\n\t\t\t.describe(\"Optional line number to narrow search (1-based)\"),\n\t\tproject: z\n\t\t\t.string()\n\t\t\t.optional()\n\t\t\t.describe(\"Optional path to tsconfig.json\"),\n\t},\n\tasync ({ file, name, line, project }) => {\n\t\ttry {\n\t\t\tconst result = inferType(file, name, { line, project });\n\t\t\tlet text = `Type: ${result.signature}`;\n\t\t\tif (result.returnType) {\n\t\t\t\ttext += `\\nReturns: ${result.returnType}`;\n\t\t\t}\n\t\t\tif (result.line) {\n\t\t\t\ttext += `\\nLine: ${result.line}`;\n\t\t\t}\n\t\t\treturn { content: [{ type: \"text\", text }] };\n\t\t} catch (error) {\n\t\t\treturn {\n\t\t\t\tcontent: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\ttext: `Error: ${(error as Error).message}`,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tisError: true,\n\t\t\t};\n\t\t}\n\t},\n);\n\nasync function main() {\n\tconst transport = new StdioServerTransport();\n\tawait server.connect(transport);\n}\n\nmain().catch(console.error);\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { findNodeByNameAndLine, getTypeInfo, loadProgram } from \"./core.js\";\nimport type { InferredTypeResult, Options } from \"./types.js\";\n\n// Re-export types\nexport type { Options, InferredTypeResult };\n\n// Re-export core utilities\nexport {\n\tfindFirstMatch,\n\tfindNearestTsconfig,\n\tfindNodeByNameAndLine,\n\tgetLineNumber,\n\tgetTypeInfo,\n\tloadProgram,\n} from \"./core.js\";\n\n/**\n * Infer the type of a function or variable in a TypeScript file\n *\n * @param file - Path to the TypeScript file\n * @param name - Name of the function/variable to inspect\n * @param options - Optional: project path (string) or options object with line and project\n * @returns The inferred type information\n * @throws Error if file not found or symbol not found\n *\n * @example\n * ```ts\n * import { inferType } from \"prinfer\";\n *\n * // By name only\n * const result = inferType(\"./src/utils.ts\", \"myFunction\");\n * console.log(result.signature);\n * // => \"(x: number, y: string) => boolean\"\n *\n * // By name and line number\n * const result2 = inferType(\"./src/utils.ts\", \"commandResult\", { line: 75 });\n * console.log(result2.signature);\n * // => \"Result<VaultAction[], CommandError>\"\n * ```\n */\nexport function inferType(\n\tfile: string,\n\tname: string,\n\toptions?: string | { line?: number; project?: string },\n): InferredTypeResult {\n\t// Normalize options for backward compatibility\n\tconst opts =\n\t\ttypeof options === \"string\" ? { project: options } : (options ?? {});\n\tconst { line, project } = opts;\n\n\tconst entryFileAbs = path.resolve(process.cwd(), file);\n\n\tif (!fs.existsSync(entryFileAbs)) {\n\t\tthrow new Error(`File not found: ${entryFileAbs}`);\n\t}\n\n\tconst program = loadProgram(entryFileAbs, project);\n\tconst sourceFile = program.getSourceFile(entryFileAbs);\n\n\tif (!sourceFile) {\n\t\tthrow new Error(\n\t\t\t`Could not load source file into the program (check tsconfig include/exclude): ${entryFileAbs}`,\n\t\t);\n\t}\n\n\tconst node = findNodeByNameAndLine(sourceFile, name, line);\n\tif (!node) {\n\t\tconst lineInfo = line !== undefined ? ` at line ${line}` : \"\";\n\t\tthrow new Error(\n\t\t\t`No symbol named \"${name}\"${lineInfo} found in ${entryFileAbs}`,\n\t\t);\n\t}\n\n\treturn getTypeInfo(program, node, sourceFile);\n}\n\n/**\n * Infer the type using an options object\n *\n * @param options - Options for type inference\n * @returns The inferred type information\n */\nexport function inferTypeFromOptions(options: Options): InferredTypeResult {\n\treturn inferType(options.file, options.name, {\n\t\tline: options.line,\n\t\tproject: options.project,\n\t});\n}\n","import path from \"node:path\";\nimport ts from \"typescript\";\nimport type { InferredTypeResult } from \"./types.js\";\n\n/**\n * Find the nearest tsconfig.json from a starting directory\n */\nexport function findNearestTsconfig(startDir: string): string | undefined {\n\treturn (\n\t\tts.findConfigFile(startDir, ts.sys.fileExists, \"tsconfig.json\") ??\n\t\tundefined\n\t);\n}\n\n/**\n * Load a TypeScript program from an entry file\n */\nexport function loadProgram(\n\tentryFileAbs: string,\n\tproject?: string,\n): ts.Program {\n\tconst fileDir = path.dirname(entryFileAbs);\n\tconst tsconfigPath = project\n\t\t? path.resolve(process.cwd(), project)\n\t\t: findNearestTsconfig(fileDir);\n\n\tif (!tsconfigPath) {\n\t\t// Fallback: single-file program\n\t\treturn ts.createProgram([entryFileAbs], {\n\t\t\ttarget: ts.ScriptTarget.ES2022,\n\t\t\tmodule: ts.ModuleKind.ESNext,\n\t\t\tstrict: true,\n\t\t\tallowJs: true,\n\t\t\tcheckJs: false,\n\t\t\tmoduleResolution: ts.ModuleResolutionKind.Bundler,\n\t\t\tskipLibCheck: true,\n\t\t});\n\t}\n\n\tconst cfg = ts.readConfigFile(tsconfigPath, ts.sys.readFile);\n\tif (cfg.error) {\n\t\tthrow new Error(\n\t\t\tts.flattenDiagnosticMessageText(cfg.error.messageText, \"\\n\"),\n\t\t);\n\t}\n\n\tconst parsed = ts.parseJsonConfigFileContent(\n\t\tcfg.config,\n\t\tts.sys,\n\t\tpath.dirname(tsconfigPath),\n\t);\n\treturn ts.createProgram({\n\t\trootNames: parsed.fileNames,\n\t\toptions: parsed.options,\n\t});\n}\n\nfunction isArrowOrFnExpr(\n\tn: ts.Node | undefined,\n): n is ts.ArrowFunction | ts.FunctionExpression {\n\treturn !!n && (ts.isArrowFunction(n) || ts.isFunctionExpression(n));\n}\n\nfunction nodeNameText(\n\tn: ts.PropertyName | ts.BindingName | undefined,\n): string | undefined {\n\tif (!n) return undefined;\n\tif (ts.isIdentifier(n)) return n.text;\n\tif (ts.isStringLiteral(n)) return n.text;\n\tif (ts.isNumericLiteral(n)) return n.text;\n\treturn undefined; // ignore computed names etc.\n}\n\nfunction isFunctionLikeNamed(node: ts.Node, name: string): boolean {\n\t// function foo() {}\n\tif (ts.isFunctionDeclaration(node) && node.name?.text === name) return true;\n\n\t// const foo = () => {} / function() {}\n\tif (\n\t\tts.isVariableDeclaration(node) &&\n\t\tts.isIdentifier(node.name) &&\n\t\tnode.name.text === name\n\t) {\n\t\treturn isArrowOrFnExpr(node.initializer);\n\t}\n\n\t// class C { foo() {} } / interface signatures\n\tif (\n\t\t(ts.isMethodDeclaration(node) || ts.isMethodSignature(node)) &&\n\t\tnodeNameText(node.name) === name\n\t) {\n\t\treturn true;\n\t}\n\n\t// object literal { foo() {} } via MethodDeclaration inside object literal is also MethodDeclaration\n\t// property assignment: { foo: () => {} }\n\tif (ts.isPropertyAssignment(node) && nodeNameText(node.name) === name) {\n\t\treturn isArrowOrFnExpr(node.initializer);\n\t}\n\n\treturn false;\n}\n\n/**\n * Check if a node is any variable declaration with the given name\n */\nfunction isVariableNamed(node: ts.Node, name: string): boolean {\n\tif (\n\t\tts.isVariableDeclaration(node) &&\n\t\tts.isIdentifier(node.name) &&\n\t\tnode.name.text === name\n\t) {\n\t\treturn true;\n\t}\n\treturn false;\n}\n\n/**\n * Check if a node matches the given name (function-like or variable)\n */\nfunction isNamedNode(node: ts.Node, name: string): boolean {\n\treturn isFunctionLikeNamed(node, name) || isVariableNamed(node, name);\n}\n\n/**\n * Get the 1-based line number for a node\n */\nexport function getLineNumber(\n\tsourceFile: ts.SourceFile,\n\tnode: ts.Node,\n): number {\n\tconst { line } = sourceFile.getLineAndCharacterOfPosition(\n\t\tnode.getStart(sourceFile),\n\t);\n\treturn line + 1;\n}\n\n/**\n * Find the first function-like node with the given name in a source file\n */\nexport function findFirstMatch(\n\tsourceFile: ts.SourceFile,\n\tname: string,\n): ts.Node | undefined {\n\tlet found: ts.Node | undefined;\n\n\tconst visit = (node: ts.Node) => {\n\t\tif (found) return;\n\t\tif (isFunctionLikeNamed(node, name)) {\n\t\t\tfound = node;\n\t\t\treturn;\n\t\t}\n\t\tts.forEachChild(node, visit);\n\t};\n\n\tvisit(sourceFile);\n\treturn found;\n}\n\n/**\n * Find a node by name and optionally by line number\n */\nexport function findNodeByNameAndLine(\n\tsourceFile: ts.SourceFile,\n\tname: string,\n\tline?: number,\n): ts.Node | undefined {\n\tlet found: ts.Node | undefined;\n\n\tconst visit = (node: ts.Node) => {\n\t\tif (found) return;\n\t\tif (isNamedNode(node, name)) {\n\t\t\tif (line !== undefined) {\n\t\t\t\tconst nodeLine = getLineNumber(sourceFile, node);\n\t\t\t\tif (nodeLine === line) {\n\t\t\t\t\tfound = node;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfound = node;\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\tts.forEachChild(node, visit);\n\t};\n\n\tvisit(sourceFile);\n\treturn found;\n}\n\n/**\n * Get type information for a node\n */\nexport function getTypeInfo(\n\tprogram: ts.Program,\n\tnode: ts.Node,\n\tsourceFile?: ts.SourceFile,\n): InferredTypeResult {\n\tconst checker = program.getTypeChecker();\n\tconst sf = sourceFile ?? node.getSourceFile();\n\tconst line = getLineNumber(sf, node);\n\n\tlet sig: ts.Signature | undefined;\n\n\t// Prefer getting the signature from a declaration/expression directly\n\tif (ts.isFunctionDeclaration(node) || ts.isMethodDeclaration(node)) {\n\t\tsig = checker.getSignatureFromDeclaration(node) ?? undefined;\n\t} else if (ts.isVariableDeclaration(node)) {\n\t\tconst init = node.initializer;\n\t\tif (isArrowOrFnExpr(init))\n\t\t\tsig = checker.getSignatureFromDeclaration(init) ?? undefined;\n\t} else if (ts.isPropertyAssignment(node)) {\n\t\tconst init = node.initializer;\n\t\tif (isArrowOrFnExpr(init))\n\t\t\tsig = checker.getSignatureFromDeclaration(init) ?? undefined;\n\t} else if (ts.isMethodSignature(node)) {\n\t\t// interfaces/types\n\t\tsig = checker.getSignatureFromDeclaration(node) ?? undefined;\n\t}\n\n\tconst flags = ts.TypeFormatFlags.NoTruncation;\n\n\tif (sig) {\n\t\tconst signature = checker.signatureToString(sig, undefined, flags);\n\t\tconst ret = checker.getReturnTypeOfSignature(sig);\n\t\tconst returnType = checker.typeToString(ret, undefined, flags);\n\t\treturn { signature, returnType, line };\n\t}\n\n\t// Fallback: type at the name location\n\tconst nodeWithName = node as unknown as { name?: ts.Node };\n\tlet nameNode: ts.Node = node;\n\tif (nodeWithName.name && ts.isIdentifier(nodeWithName.name)) {\n\t\tnameNode = nodeWithName.name;\n\t}\n\n\tconst t = checker.getTypeAtLocation(nameNode);\n\treturn { signature: checker.typeToString(t, undefined, flags), line };\n}\n"],"mappings":"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","names":["path","path"]}
|
|
1
|
+
{"version":3,"sources":["../src/mcp.ts","../src/index.ts","../src/core.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { z } from \"zod\";\nimport { hover } from \"./index.js\";\n\nconst HELP = `\nprinfer-mcp - MCP server for TypeScript type inference\n\nThis is an MCP (Model Context Protocol) server. It's designed to be run\nby Claude Code, not directly from the command line.\n\nSetup:\n Run 'prinfer setup' to configure Claude Code automatically.\n\nManual setup:\n Run: claude mcp add prinfer node /path/to/prinfer-mcp\n\nProvided tools:\n hover(file, line, column, include_docs?, project?)\n Get TypeScript type information at a specific position.\n\nSee also:\n prinfer --help CLI for direct type inspection\n`.trim();\n\nif (process.argv.includes(\"--help\") || process.argv.includes(\"-h\")) {\n\tconsole.log(HELP);\n\tprocess.exit(0);\n}\n\nconst server = new McpServer({\n\tname: \"prinfer\",\n\tversion: \"0.3.0\",\n});\n\nserver.tool(\n\t\"hover\",\n\t\"Get TypeScript type information at a specific position in a file. Returns the type signature, return type, documentation, and symbol kind.\",\n\t{\n\t\tfile: z.string().describe(\"Path to the TypeScript file\"),\n\t\tline: z.number().describe(\"1-based line number\"),\n\t\tcolumn: z.number().describe(\"1-based column (character position)\"),\n\t\tinclude_docs: z\n\t\t\t.boolean()\n\t\t\t.optional()\n\t\t\t.describe(\"Include JSDoc/TSDoc documentation\"),\n\t\tproject: z\n\t\t\t.string()\n\t\t\t.optional()\n\t\t\t.describe(\"Optional path to tsconfig.json\"),\n\t},\n\tasync ({ file, line, column, include_docs, project }) => {\n\t\ttry {\n\t\t\tconst result = hover(file, line, column, { include_docs, project });\n\t\t\tlet text = `Type: ${result.signature}`;\n\t\t\tif (result.returnType) {\n\t\t\t\ttext += `\\nReturns: ${result.returnType}`;\n\t\t\t}\n\t\t\tif (result.name) {\n\t\t\t\ttext += `\\nName: ${result.name}`;\n\t\t\t}\n\t\t\ttext += `\\nKind: ${result.kind}`;\n\t\t\ttext += `\\nPosition: ${result.line}:${result.column}`;\n\t\t\tif (result.documentation) {\n\t\t\t\ttext += `\\nDocumentation: ${result.documentation}`;\n\t\t\t}\n\t\t\treturn { content: [{ type: \"text\", text }] };\n\t\t} catch (error) {\n\t\t\treturn {\n\t\t\t\tcontent: [\n\t\t\t\t\t{\n\t\t\t\t\t\ttype: \"text\",\n\t\t\t\t\t\ttext: `Error: ${(error as Error).message}`,\n\t\t\t\t\t},\n\t\t\t\t],\n\t\t\t\tisError: true,\n\t\t\t};\n\t\t}\n\t},\n);\n\nasync function main() {\n\tconst transport = new StdioServerTransport();\n\tawait server.connect(transport);\n}\n\nmain().catch(console.error);\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport {\n\tfindNodeAtPosition,\n\tfindNodeByNameAndLine,\n\tgetHoverInfo,\n\tgetTypeInfo,\n\tloadProgram,\n} from \"./core.js\";\nimport type {\n\tHoverOptions,\n\tHoverResult,\n\tInferredTypeResult,\n\tOptions,\n} from \"./types.js\";\n\n// Re-export types\nexport type { HoverOptions, HoverResult, InferredTypeResult, Options };\n\n// Re-export core utilities\nexport {\n\tfindFirstMatch,\n\tfindNearestTsconfig,\n\tfindNodeAtPosition,\n\tfindNodeByNameAndLine,\n\tgetDocumentation,\n\tgetHoverInfo,\n\tgetLineNumber,\n\tgetTypeInfo,\n\tloadProgram,\n} from \"./core.js\";\n\n/**\n * Infer the type of a function or variable in a TypeScript file\n *\n * @param file - Path to the TypeScript file\n * @param name - Name of the function/variable to inspect\n * @param options - Optional: project path (string) or options object with line and project\n * @returns The inferred type information\n * @throws Error if file not found or symbol not found\n *\n * @example\n * ```ts\n * import { inferType } from \"prinfer\";\n *\n * // By name only\n * const result = inferType(\"./src/utils.ts\", \"myFunction\");\n * console.log(result.signature);\n * // => \"(x: number, y: string) => boolean\"\n *\n * // By name and line number\n * const result2 = inferType(\"./src/utils.ts\", \"commandResult\", { line: 75 });\n * console.log(result2.signature);\n * // => \"Result<VaultAction[], CommandError>\"\n * ```\n */\nexport function inferType(\n\tfile: string,\n\tname: string,\n\toptions?: string | { line?: number; project?: string },\n): InferredTypeResult {\n\t// Normalize options for backward compatibility\n\tconst opts =\n\t\ttypeof options === \"string\" ? { project: options } : (options ?? {});\n\tconst { line, project } = opts;\n\n\tconst entryFileAbs = path.resolve(process.cwd(), file);\n\n\tif (!fs.existsSync(entryFileAbs)) {\n\t\tthrow new Error(`File not found: ${entryFileAbs}`);\n\t}\n\n\tconst program = loadProgram(entryFileAbs, project);\n\tconst sourceFile = program.getSourceFile(entryFileAbs);\n\n\tif (!sourceFile) {\n\t\tthrow new Error(\n\t\t\t`Could not load source file into the program (check tsconfig include/exclude): ${entryFileAbs}`,\n\t\t);\n\t}\n\n\tconst node = findNodeByNameAndLine(sourceFile, name, line);\n\tif (!node) {\n\t\tconst lineInfo = line !== undefined ? ` at line ${line}` : \"\";\n\t\tthrow new Error(\n\t\t\t`No symbol named \"${name}\"${lineInfo} found in ${entryFileAbs}`,\n\t\t);\n\t}\n\n\treturn getTypeInfo(program, node, sourceFile);\n}\n\n/**\n * Infer the type using an options object\n *\n * @param options - Options for type inference\n * @returns The inferred type information\n */\nexport function inferTypeFromOptions(options: Options): InferredTypeResult {\n\treturn inferType(options.file, options.name, {\n\t\tline: options.line,\n\t\tproject: options.project,\n\t});\n}\n\n/**\n * Get type information at a specific position in a TypeScript file\n *\n * @param file - Path to the TypeScript file\n * @param line - 1-based line number\n * @param column - 1-based column number\n * @param options - Optional hover options (project path, include_docs)\n * @returns The hover information at the position\n * @throws Error if file not found or no symbol at position\n *\n * @example\n * ```ts\n * import { hover } from \"prinfer\";\n *\n * const result = hover(\"./src/utils.ts\", 75, 10);\n * console.log(result.signature);\n * // => \"(x: number) => string\"\n *\n * // With documentation\n * const result2 = hover(\"./src/utils.ts\", 75, 10, { include_docs: true });\n * console.log(result2.documentation);\n * // => \"Formats a number as a string\"\n * ```\n */\nexport function hover(\n\tfile: string,\n\tline: number,\n\tcolumn: number,\n\toptions?: HoverOptions,\n): HoverResult {\n\tconst { project, include_docs = false } = options ?? {};\n\n\tconst entryFileAbs = path.resolve(process.cwd(), file);\n\n\tif (!fs.existsSync(entryFileAbs)) {\n\t\tthrow new Error(`File not found: ${entryFileAbs}`);\n\t}\n\n\tconst program = loadProgram(entryFileAbs, project);\n\tconst sourceFile = program.getSourceFile(entryFileAbs);\n\n\tif (!sourceFile) {\n\t\tthrow new Error(\n\t\t\t`Could not load source file into the program (check tsconfig include/exclude): ${entryFileAbs}`,\n\t\t);\n\t}\n\n\tconst node = findNodeAtPosition(sourceFile, line, column);\n\tif (!node) {\n\t\tthrow new Error(`No symbol found at ${entryFileAbs}:${line}:${column}`);\n\t}\n\n\treturn getHoverInfo(program, node, sourceFile, include_docs);\n}\n","import path from \"node:path\";\nimport ts from \"typescript\";\nimport type { HoverResult, InferredTypeResult } from \"./types.js\";\n\n/**\n * Find the nearest tsconfig.json from a starting directory\n */\nexport function findNearestTsconfig(startDir: string): string | undefined {\n\treturn (\n\t\tts.findConfigFile(startDir, ts.sys.fileExists, \"tsconfig.json\") ??\n\t\tundefined\n\t);\n}\n\n/**\n * Load a TypeScript program from an entry file\n */\nexport function loadProgram(\n\tentryFileAbs: string,\n\tproject?: string,\n): ts.Program {\n\tconst fileDir = path.dirname(entryFileAbs);\n\tconst tsconfigPath = project\n\t\t? path.resolve(process.cwd(), project)\n\t\t: findNearestTsconfig(fileDir);\n\n\tif (!tsconfigPath) {\n\t\t// Fallback: single-file program\n\t\treturn ts.createProgram([entryFileAbs], {\n\t\t\ttarget: ts.ScriptTarget.ES2022,\n\t\t\tmodule: ts.ModuleKind.ESNext,\n\t\t\tstrict: true,\n\t\t\tallowJs: true,\n\t\t\tcheckJs: false,\n\t\t\tmoduleResolution: ts.ModuleResolutionKind.Bundler,\n\t\t\tskipLibCheck: true,\n\t\t});\n\t}\n\n\tconst cfg = ts.readConfigFile(tsconfigPath, ts.sys.readFile);\n\tif (cfg.error) {\n\t\tthrow new Error(\n\t\t\tts.flattenDiagnosticMessageText(cfg.error.messageText, \"\\n\"),\n\t\t);\n\t}\n\n\tconst parsed = ts.parseJsonConfigFileContent(\n\t\tcfg.config,\n\t\tts.sys,\n\t\tpath.dirname(tsconfigPath),\n\t);\n\treturn ts.createProgram({\n\t\trootNames: parsed.fileNames,\n\t\toptions: parsed.options,\n\t});\n}\n\nfunction isArrowOrFnExpr(\n\tn: ts.Node | undefined,\n): n is ts.ArrowFunction | ts.FunctionExpression {\n\treturn !!n && (ts.isArrowFunction(n) || ts.isFunctionExpression(n));\n}\n\nfunction nodeNameText(\n\tn: ts.PropertyName | ts.BindingName | undefined,\n): string | undefined {\n\tif (!n) return undefined;\n\tif (ts.isIdentifier(n)) return n.text;\n\tif (ts.isStringLiteral(n)) return n.text;\n\tif (ts.isNumericLiteral(n)) return n.text;\n\treturn undefined; // ignore computed names etc.\n}\n\nfunction isFunctionLikeNamed(node: ts.Node, name: string): boolean {\n\t// function foo() {}\n\tif (ts.isFunctionDeclaration(node) && node.name?.text === name) return true;\n\n\t// const foo = () => {} / function() {}\n\tif (\n\t\tts.isVariableDeclaration(node) &&\n\t\tts.isIdentifier(node.name) &&\n\t\tnode.name.text === name\n\t) {\n\t\treturn isArrowOrFnExpr(node.initializer);\n\t}\n\n\t// class C { foo() {} } / interface signatures\n\tif (\n\t\t(ts.isMethodDeclaration(node) || ts.isMethodSignature(node)) &&\n\t\tnodeNameText(node.name) === name\n\t) {\n\t\treturn true;\n\t}\n\n\t// object literal { foo() {} } via MethodDeclaration inside object literal is also MethodDeclaration\n\t// property assignment: { foo: () => {} }\n\tif (ts.isPropertyAssignment(node) && nodeNameText(node.name) === name) {\n\t\treturn isArrowOrFnExpr(node.initializer);\n\t}\n\n\treturn false;\n}\n\n/**\n * Check if a node is any variable declaration with the given name\n */\nfunction isVariableNamed(node: ts.Node, name: string): boolean {\n\tif (\n\t\tts.isVariableDeclaration(node) &&\n\t\tts.isIdentifier(node.name) &&\n\t\tnode.name.text === name\n\t) {\n\t\treturn true;\n\t}\n\treturn false;\n}\n\n/**\n * Check if a node matches the given name (function-like or variable)\n */\nfunction isNamedNode(node: ts.Node, name: string): boolean {\n\treturn isFunctionLikeNamed(node, name) || isVariableNamed(node, name);\n}\n\n/**\n * Check if a node is a call expression with the given name\n */\nfunction isCallExpressionNamed(node: ts.Node, name: string): boolean {\n\tif (!ts.isCallExpression(node)) return false;\n\tconst expr = node.expression;\n\n\t// Direct call: foo()\n\tif (ts.isIdentifier(expr) && expr.text === name) return true;\n\n\t// Property access: this.foo() or obj.foo()\n\tif (ts.isPropertyAccessExpression(expr) && expr.name.text === name)\n\t\treturn true;\n\n\treturn false;\n}\n\n/**\n * Get the 1-based line number for a node\n */\nexport function getLineNumber(\n\tsourceFile: ts.SourceFile,\n\tnode: ts.Node,\n): number {\n\tconst { line } = sourceFile.getLineAndCharacterOfPosition(\n\t\tnode.getStart(sourceFile),\n\t);\n\treturn line + 1;\n}\n\n/**\n * Find the first function-like node with the given name in a source file\n */\nexport function findFirstMatch(\n\tsourceFile: ts.SourceFile,\n\tname: string,\n): ts.Node | undefined {\n\tlet found: ts.Node | undefined;\n\n\tconst visit = (node: ts.Node) => {\n\t\tif (found) return;\n\t\tif (isFunctionLikeNamed(node, name)) {\n\t\t\tfound = node;\n\t\t\treturn;\n\t\t}\n\t\tts.forEachChild(node, visit);\n\t};\n\n\tvisit(sourceFile);\n\treturn found;\n}\n\n/**\n * Find a node by name and optionally by line number\n */\nexport function findNodeByNameAndLine(\n\tsourceFile: ts.SourceFile,\n\tname: string,\n\tline?: number,\n): ts.Node | undefined {\n\tlet found: ts.Node | undefined;\n\n\tconst matchesLine = (node: ts.Node): boolean => {\n\t\tif (line === undefined) return true;\n\t\treturn getLineNumber(sourceFile, node) === line;\n\t};\n\n\tconst visit = (node: ts.Node) => {\n\t\tif (found) return;\n\n\t\t// Check declarations (existing logic)\n\t\tif (isNamedNode(node, name) && matchesLine(node)) {\n\t\t\tfound = node;\n\t\t\treturn;\n\t\t}\n\n\t\t// Check call expressions (new)\n\t\tif (isCallExpressionNamed(node, name) && matchesLine(node)) {\n\t\t\tfound = node;\n\t\t\treturn;\n\t\t}\n\n\t\tts.forEachChild(node, visit);\n\t};\n\n\tvisit(sourceFile);\n\treturn found;\n}\n\n/**\n * Get type information for a node\n */\nexport function getTypeInfo(\n\tprogram: ts.Program,\n\tnode: ts.Node,\n\tsourceFile?: ts.SourceFile,\n): InferredTypeResult {\n\tconst checker = program.getTypeChecker();\n\tconst sf = sourceFile ?? node.getSourceFile();\n\tconst line = getLineNumber(sf, node);\n\tconst flags = ts.TypeFormatFlags.NoTruncation;\n\n\t// Handle call expressions - get instantiated signature\n\tif (ts.isCallExpression(node)) {\n\t\tconst sig = checker.getResolvedSignature(node);\n\t\tif (sig) {\n\t\t\tconst signature = checker.signatureToString(sig, undefined, flags);\n\t\t\tconst ret = checker.getReturnTypeOfSignature(sig);\n\t\t\tconst returnType = checker.typeToString(ret, undefined, flags);\n\t\t\treturn { signature, returnType, line };\n\t\t}\n\t\t// Fallback: get type of the call result\n\t\tconst t = checker.getTypeAtLocation(node);\n\t\treturn { signature: checker.typeToString(t, undefined, flags), line };\n\t}\n\n\tlet sig: ts.Signature | undefined;\n\n\t// Prefer getting the signature from a declaration/expression directly\n\tif (ts.isFunctionDeclaration(node) || ts.isMethodDeclaration(node)) {\n\t\tsig = checker.getSignatureFromDeclaration(node) ?? undefined;\n\t} else if (ts.isVariableDeclaration(node)) {\n\t\tconst init = node.initializer;\n\t\tif (isArrowOrFnExpr(init))\n\t\t\tsig = checker.getSignatureFromDeclaration(init) ?? undefined;\n\t} else if (ts.isPropertyAssignment(node)) {\n\t\tconst init = node.initializer;\n\t\tif (isArrowOrFnExpr(init))\n\t\t\tsig = checker.getSignatureFromDeclaration(init) ?? undefined;\n\t} else if (ts.isMethodSignature(node)) {\n\t\t// interfaces/types\n\t\tsig = checker.getSignatureFromDeclaration(node) ?? undefined;\n\t}\n\n\tif (sig) {\n\t\tconst signature = checker.signatureToString(sig, undefined, flags);\n\t\tconst ret = checker.getReturnTypeOfSignature(sig);\n\t\tconst returnType = checker.typeToString(ret, undefined, flags);\n\t\treturn { signature, returnType, line };\n\t}\n\n\t// Fallback: type at the name location\n\tconst nodeWithName = node as unknown as { name?: ts.Node };\n\tlet nameNode: ts.Node = node;\n\tif (nodeWithName.name && ts.isIdentifier(nodeWithName.name)) {\n\t\tnameNode = nodeWithName.name;\n\t}\n\n\tconst t = checker.getTypeAtLocation(nameNode);\n\treturn { signature: checker.typeToString(t, undefined, flags), line };\n}\n\n/**\n * Find the most specific node containing a position by walking the AST\n */\nfunction findSmallestNodeAtPosition(\n\tsourceFile: ts.SourceFile,\n\tposition: number,\n): ts.Node | undefined {\n\tlet result: ts.Node | undefined;\n\n\tfunction visit(node: ts.Node): void {\n\t\tconst start = node.getStart(sourceFile);\n\t\tconst end = node.getEnd();\n\n\t\t// Position must be within this node's range\n\t\tif (position < start || position >= end) {\n\t\t\treturn;\n\t\t}\n\n\t\t// This node contains the position - check if it's more specific than current result\n\t\tif (\n\t\t\t!result ||\n\t\t\tnode.getWidth(sourceFile) <= result.getWidth(sourceFile)\n\t\t) {\n\t\t\tresult = node;\n\t\t}\n\n\t\t// Continue to check children for more specific nodes\n\t\tts.forEachChild(node, visit);\n\t}\n\n\tvisit(sourceFile);\n\treturn result;\n}\n\n/**\n * Walk up from a token to find the most useful node for hover info\n */\nfunction findHoverableAncestor(\n\tsourceFile: ts.SourceFile,\n\tposition: number,\n): ts.Node | undefined {\n\tconst smallestNode = findSmallestNodeAtPosition(sourceFile, position);\n\tif (!smallestNode) return undefined;\n\n\t// Walk up the tree to find the most useful hoverable node\n\tlet bestMatch: ts.Node | undefined = smallestNode;\n\n\t// Visit ancestors\n\tfunction visit(n: ts.Node): boolean {\n\t\tconst start = n.getStart(sourceFile);\n\t\tconst end = n.getEnd();\n\n\t\tif (position < start || position >= end) {\n\t\t\treturn false;\n\t\t}\n\n\t\t// Check if this is a call expression with our node as the callee\n\t\tif (ts.isCallExpression(n)) {\n\t\t\tconst expr = n.expression;\n\t\t\t// Check if position is on the function name part\n\t\t\tif (ts.isIdentifier(expr)) {\n\t\t\t\tif (\n\t\t\t\t\tposition >= expr.getStart(sourceFile) &&\n\t\t\t\t\tposition < expr.getEnd()\n\t\t\t\t) {\n\t\t\t\t\tbestMatch = n;\n\t\t\t\t}\n\t\t\t} else if (ts.isPropertyAccessExpression(expr)) {\n\t\t\t\tif (\n\t\t\t\t\tposition >= expr.name.getStart(sourceFile) &&\n\t\t\t\t\tposition < expr.name.getEnd()\n\t\t\t\t) {\n\t\t\t\t\tbestMatch = n;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// If this is a declaration and the position is on its name, use this declaration\n\t\tif (ts.isFunctionDeclaration(n) && n.name) {\n\t\t\tif (\n\t\t\t\tposition >= n.name.getStart(sourceFile) &&\n\t\t\t\tposition < n.name.getEnd()\n\t\t\t) {\n\t\t\t\tbestMatch = n;\n\t\t\t}\n\t\t}\n\t\tif (ts.isVariableDeclaration(n) && ts.isIdentifier(n.name)) {\n\t\t\tif (\n\t\t\t\tposition >= n.name.getStart(sourceFile) &&\n\t\t\t\tposition < n.name.getEnd()\n\t\t\t) {\n\t\t\t\tbestMatch = n;\n\t\t\t}\n\t\t}\n\t\tif (\n\t\t\t(ts.isMethodDeclaration(n) || ts.isMethodSignature(n)) &&\n\t\t\tts.isIdentifier(n.name)\n\t\t) {\n\t\t\tif (\n\t\t\t\tposition >= n.name.getStart(sourceFile) &&\n\t\t\t\tposition < n.name.getEnd()\n\t\t\t) {\n\t\t\t\tbestMatch = n;\n\t\t\t}\n\t\t}\n\t\tif (ts.isClassDeclaration(n) && n.name) {\n\t\t\tif (\n\t\t\t\tposition >= n.name.getStart(sourceFile) &&\n\t\t\t\tposition < n.name.getEnd()\n\t\t\t) {\n\t\t\t\tbestMatch = n;\n\t\t\t}\n\t\t}\n\t\tif (ts.isInterfaceDeclaration(n) && n.name) {\n\t\t\tif (\n\t\t\t\tposition >= n.name.getStart(sourceFile) &&\n\t\t\t\tposition < n.name.getEnd()\n\t\t\t) {\n\t\t\t\tbestMatch = n;\n\t\t\t}\n\t\t}\n\n\t\tts.forEachChild(n, visit);\n\t\treturn true;\n\t}\n\n\tvisit(sourceFile);\n\treturn bestMatch;\n}\n\n/**\n * Find the node at a specific position (1-based line and column)\n */\nexport function findNodeAtPosition(\n\tsourceFile: ts.SourceFile,\n\tline: number,\n\tcolumn: number,\n): ts.Node | undefined {\n\t// Validate line/column bounds\n\tconst lineCount = sourceFile.getLineStarts().length;\n\tif (line < 1 || line > lineCount) {\n\t\treturn undefined;\n\t}\n\n\tconst lineStart = sourceFile.getLineStarts()[line - 1];\n\tconst lineEnd =\n\t\tline < lineCount\n\t\t\t? sourceFile.getLineStarts()[line]\n\t\t\t: sourceFile.getEnd();\n\tconst lineLength = lineEnd - lineStart;\n\n\tif (column < 1 || column > lineLength + 1) {\n\t\treturn undefined;\n\t}\n\n\t// Convert 1-based line/column to 0-based position\n\tconst position = sourceFile.getPositionOfLineAndCharacter(\n\t\tline - 1,\n\t\tcolumn - 1,\n\t);\n\n\treturn findHoverableAncestor(sourceFile, position);\n}\n\n/**\n * Get the symbol kind as a string\n */\nfunction getSymbolKind(node: ts.Node): string {\n\tif (ts.isFunctionDeclaration(node)) return \"function\";\n\tif (ts.isArrowFunction(node)) return \"function\";\n\tif (ts.isFunctionExpression(node)) return \"function\";\n\tif (ts.isMethodDeclaration(node)) return \"method\";\n\tif (ts.isMethodSignature(node)) return \"method\";\n\tif (ts.isVariableDeclaration(node)) {\n\t\tconst init = node.initializer;\n\t\tif (\n\t\t\tinit &&\n\t\t\t(ts.isArrowFunction(init) || ts.isFunctionExpression(init))\n\t\t) {\n\t\t\treturn \"function\";\n\t\t}\n\t\treturn \"variable\";\n\t}\n\tif (ts.isParameter(node)) return \"parameter\";\n\tif (ts.isPropertyDeclaration(node)) return \"property\";\n\tif (ts.isPropertySignature(node)) return \"property\";\n\tif (ts.isPropertyAccessExpression(node)) return \"property\";\n\tif (ts.isCallExpression(node)) return \"call\";\n\tif (ts.isTypeAliasDeclaration(node)) return \"type\";\n\tif (ts.isInterfaceDeclaration(node)) return \"interface\";\n\tif (ts.isClassDeclaration(node)) return \"class\";\n\tif (ts.isIdentifier(node)) return \"identifier\";\n\treturn \"unknown\";\n}\n\n/**\n * Get the name of a node if it has one\n */\nfunction getNodeName(node: ts.Node): string | undefined {\n\tif (ts.isFunctionDeclaration(node) && node.name) {\n\t\treturn node.name.text;\n\t}\n\tif (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name)) {\n\t\treturn node.name.text;\n\t}\n\tif (\n\t\t(ts.isMethodDeclaration(node) || ts.isMethodSignature(node)) &&\n\t\tts.isIdentifier(node.name)\n\t) {\n\t\treturn node.name.text;\n\t}\n\tif (ts.isPropertyAccessExpression(node)) {\n\t\treturn node.name.text;\n\t}\n\tif (ts.isCallExpression(node)) {\n\t\tconst expr = node.expression;\n\t\tif (ts.isIdentifier(expr)) return expr.text;\n\t\tif (ts.isPropertyAccessExpression(expr)) return expr.name.text;\n\t}\n\tif (ts.isParameter(node) && ts.isIdentifier(node.name)) {\n\t\treturn node.name.text;\n\t}\n\tif (ts.isIdentifier(node)) {\n\t\treturn node.text;\n\t}\n\tif (\n\t\tts.isTypeAliasDeclaration(node) ||\n\t\tts.isInterfaceDeclaration(node) ||\n\t\tts.isClassDeclaration(node)\n\t) {\n\t\treturn node.name?.text;\n\t}\n\treturn undefined;\n}\n\n/**\n * Get documentation from a symbol\n */\nexport function getDocumentation(\n\tchecker: ts.TypeChecker,\n\tsymbol: ts.Symbol | undefined,\n): string | undefined {\n\tif (!symbol) return undefined;\n\n\tconst docs = symbol.getDocumentationComment(checker);\n\tif (docs.length === 0) return undefined;\n\n\treturn ts.displayPartsToString(docs);\n}\n\n/**\n * Get hover information at a specific position\n */\nexport function getHoverInfo(\n\tprogram: ts.Program,\n\tnode: ts.Node,\n\tsourceFile: ts.SourceFile,\n\tincludeDocs: boolean,\n): HoverResult {\n\tconst checker = program.getTypeChecker();\n\tconst sf = sourceFile;\n\tconst { line, character } = sf.getLineAndCharacterOfPosition(\n\t\tnode.getStart(sf),\n\t);\n\tconst flags = ts.TypeFormatFlags.NoTruncation;\n\n\tconst kind = getSymbolKind(node);\n\tconst name = getNodeName(node);\n\n\t// Get symbol for documentation\n\tlet symbol: ts.Symbol | undefined;\n\tif (ts.isCallExpression(node)) {\n\t\t// For calls, get symbol from the expression\n\t\tconst expr = node.expression;\n\t\tif (ts.isPropertyAccessExpression(expr)) {\n\t\t\tsymbol = checker.getSymbolAtLocation(expr.name);\n\t\t} else {\n\t\t\tsymbol = checker.getSymbolAtLocation(expr);\n\t\t}\n\t} else {\n\t\tconst nodeWithName = node as unknown as { name?: ts.Node };\n\t\tif (nodeWithName.name) {\n\t\t\tsymbol = checker.getSymbolAtLocation(nodeWithName.name);\n\t\t} else {\n\t\t\tsymbol = checker.getSymbolAtLocation(node);\n\t\t}\n\t}\n\n\tconst documentation = includeDocs\n\t\t? getDocumentation(checker, symbol)\n\t\t: undefined;\n\n\t// Handle call expressions - get instantiated signature\n\tif (ts.isCallExpression(node)) {\n\t\tconst sig = checker.getResolvedSignature(node);\n\t\tif (sig) {\n\t\t\tconst signature = checker.signatureToString(sig, undefined, flags);\n\t\t\tconst ret = checker.getReturnTypeOfSignature(sig);\n\t\t\tconst returnType = checker.typeToString(ret, undefined, flags);\n\t\t\treturn {\n\t\t\t\tsignature,\n\t\t\t\treturnType,\n\t\t\t\tline: line + 1,\n\t\t\t\tcolumn: character + 1,\n\t\t\t\tdocumentation,\n\t\t\t\tkind,\n\t\t\t\tname,\n\t\t\t};\n\t\t}\n\t\t// Fallback: get type of the call result\n\t\tconst t = checker.getTypeAtLocation(node);\n\t\treturn {\n\t\t\tsignature: checker.typeToString(t, undefined, flags),\n\t\t\tline: line + 1,\n\t\t\tcolumn: character + 1,\n\t\t\tdocumentation,\n\t\t\tkind,\n\t\t\tname,\n\t\t};\n\t}\n\n\tlet sig: ts.Signature | undefined;\n\n\t// Prefer getting the signature from a declaration/expression directly\n\tif (ts.isFunctionDeclaration(node) || ts.isMethodDeclaration(node)) {\n\t\tsig = checker.getSignatureFromDeclaration(node) ?? undefined;\n\t} else if (ts.isVariableDeclaration(node)) {\n\t\tconst init = node.initializer;\n\t\tif (isArrowOrFnExpr(init))\n\t\t\tsig = checker.getSignatureFromDeclaration(init) ?? undefined;\n\t} else if (ts.isPropertyAssignment(node)) {\n\t\tconst init = node.initializer;\n\t\tif (isArrowOrFnExpr(init))\n\t\t\tsig = checker.getSignatureFromDeclaration(init) ?? undefined;\n\t} else if (ts.isMethodSignature(node)) {\n\t\tsig = checker.getSignatureFromDeclaration(node) ?? undefined;\n\t}\n\n\tif (sig) {\n\t\tconst signature = checker.signatureToString(sig, undefined, flags);\n\t\tconst ret = checker.getReturnTypeOfSignature(sig);\n\t\tconst returnType = checker.typeToString(ret, undefined, flags);\n\t\treturn {\n\t\t\tsignature,\n\t\t\treturnType,\n\t\t\tline: line + 1,\n\t\t\tcolumn: character + 1,\n\t\t\tdocumentation,\n\t\t\tkind,\n\t\t\tname,\n\t\t};\n\t}\n\n\t// Fallback: type at the node location\n\tconst nodeWithName = node as unknown as { name?: ts.Node };\n\tlet targetNode: ts.Node = node;\n\tif (nodeWithName.name && ts.isIdentifier(nodeWithName.name)) {\n\t\ttargetNode = nodeWithName.name;\n\t}\n\n\tconst t = checker.getTypeAtLocation(targetNode);\n\treturn {\n\t\tsignature: checker.typeToString(t, undefined, flags),\n\t\tline: line + 1,\n\t\tcolumn: character + 1,\n\t\tdocumentation,\n\t\tkind,\n\t\tname,\n\t};\n}\n"],"mappings":"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","names":["path","nodeWithName","sig","t","path"]}
|
package/dist/postinstall.cjs
CHANGED
|
@@ -70,27 +70,6 @@ function main() {
|
|
|
70
70
|
);
|
|
71
71
|
return;
|
|
72
72
|
}
|
|
73
|
-
let success = true;
|
|
74
|
-
const configFile = import_node_path.default.join(claudeDir, "settings.json");
|
|
75
|
-
try {
|
|
76
|
-
let config = {};
|
|
77
|
-
if (import_node_fs.default.existsSync(configFile)) {
|
|
78
|
-
config = JSON.parse(import_node_fs.default.readFileSync(configFile, "utf-8"));
|
|
79
|
-
}
|
|
80
|
-
if (!config.mcpServers?.prinfer) {
|
|
81
|
-
config.mcpServers = config.mcpServers || {};
|
|
82
|
-
config.mcpServers.prinfer = { command: "prinfer-mcp" };
|
|
83
|
-
import_node_fs.default.writeFileSync(
|
|
84
|
-
configFile,
|
|
85
|
-
`${JSON.stringify(config, null, 2)}
|
|
86
|
-
`
|
|
87
|
-
);
|
|
88
|
-
console.log("[ok] Added MCP server to settings.json");
|
|
89
|
-
}
|
|
90
|
-
} catch (err) {
|
|
91
|
-
console.error(`[error] MCP setup failed: ${err.message}`);
|
|
92
|
-
success = false;
|
|
93
|
-
}
|
|
94
73
|
const skillsDir = import_node_path.default.join(claudeDir, "skills");
|
|
95
74
|
const skillFile = import_node_path.default.join(skillsDir, "prefer-infer.md");
|
|
96
75
|
try {
|
|
@@ -105,11 +84,9 @@ function main() {
|
|
|
105
84
|
}
|
|
106
85
|
} catch (err) {
|
|
107
86
|
console.error(`[error] Skill setup failed: ${err.message}`);
|
|
108
|
-
|
|
109
|
-
}
|
|
110
|
-
if (!success) {
|
|
111
|
-
console.error("\nSome steps failed. Run 'prinfer setup' for details.");
|
|
87
|
+
console.error("Run 'prinfer setup' for full installation.");
|
|
112
88
|
}
|
|
89
|
+
console.log("Run 'prinfer setup' to configure the MCP server.");
|
|
113
90
|
}
|
|
114
91
|
main();
|
|
115
92
|
//# sourceMappingURL=postinstall.cjs.map
|
package/dist/postinstall.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/postinstall.ts"],"sourcesContent":["#!/usr/bin/env node\nimport fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\n\
|
|
1
|
+
{"version":3,"sources":["../src/postinstall.ts"],"sourcesContent":["#!/usr/bin/env node\nimport fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\n\nconst SKILL_CONTENT = `# TypeScript Type Inference (prinfer)\n\n## Coding Guideline\n\nWhen writing TypeScript code, prefer relying on type inference over explicit type annotations:\n\n- Let TypeScript infer return types for functions when the implementation makes them obvious\n- Let TypeScript infer variable types from their initializers\n- Only add explicit types when:\n - The inferred type is too wide (e.g., \\`string\\` instead of a literal type)\n - The type serves as documentation for complex structures\n - You're defining a public API contract\n\nUse the \\`prinfer\\` MCP tool (\\`infer_type\\`) to verify what TypeScript infers before adding explicit types.\n\n## Commands\n\n### /check-type\n\nCheck the inferred type of a TypeScript symbol.\n\nUsage: \\`/check-type <file>:<line> <name>\\` or \\`/check-type <file> <name>\\`\n\nExamples:\n- \\`/check-type src/utils.ts:75 commandResult\\`\n- \\`/check-type src/utils.ts myFunction\\`\n\n<command-name>check-type</command-name>\n\nUse the \\`infer_type\\` MCP tool to check the type:\n1. Parse the arguments to extract file, optional line number, and symbol name\n2. Call \\`infer_type(file, name, line?)\\`\n3. Report the inferred signature and return type\n`;\n\nfunction main() {\n\tconst homeDir = os.homedir();\n\tconst claudeDir = path.join(homeDir, \".claude\");\n\n\tif (!fs.existsSync(claudeDir)) {\n\t\tconsole.log(\n\t\t\t\"~/.claude not found. Run 'prinfer setup' after installing Claude Code.\",\n\t\t);\n\t\treturn;\n\t}\n\n\t// Install skill only (MCP setup requires 'claude' CLI which may not be available during npm install)\n\tconst skillsDir = path.join(claudeDir, \"skills\");\n\tconst skillFile = path.join(skillsDir, \"prefer-infer.md\");\n\ttry {\n\t\tif (!fs.existsSync(skillsDir)) {\n\t\t\tfs.mkdirSync(skillsDir, { recursive: true });\n\t\t}\n\n\t\tif (!fs.existsSync(skillFile)) {\n\t\t\tfs.writeFileSync(skillFile, SKILL_CONTENT);\n\t\t\tconsole.log(\n\t\t\t\t\"[ok] Installed skill to ~/.claude/skills/prefer-infer.md\",\n\t\t\t);\n\t\t}\n\t} catch (err) {\n\t\tconsole.error(`[error] Skill setup failed: ${(err as Error).message}`);\n\t\tconsole.error(\"Run 'prinfer setup' for full installation.\");\n\t}\n\n\t// Remind user to run setup for MCP\n\tconsole.log(\"Run 'prinfer setup' to configure the MCP server.\");\n}\n\nmain();\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AACA,qBAAe;AACf,qBAAe;AACf,uBAAiB;AAEjB,IAAM,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAmCtB,SAAS,OAAO;AACf,QAAM,UAAU,eAAAA,QAAG,QAAQ;AAC3B,QAAM,YAAY,iBAAAC,QAAK,KAAK,SAAS,SAAS;AAE9C,MAAI,CAAC,eAAAC,QAAG,WAAW,SAAS,GAAG;AAC9B,YAAQ;AAAA,MACP;AAAA,IACD;AACA;AAAA,EACD;AAGA,QAAM,YAAY,iBAAAD,QAAK,KAAK,WAAW,QAAQ;AAC/C,QAAM,YAAY,iBAAAA,QAAK,KAAK,WAAW,iBAAiB;AACxD,MAAI;AACH,QAAI,CAAC,eAAAC,QAAG,WAAW,SAAS,GAAG;AAC9B,qBAAAA,QAAG,UAAU,WAAW,EAAE,WAAW,KAAK,CAAC;AAAA,IAC5C;AAEA,QAAI,CAAC,eAAAA,QAAG,WAAW,SAAS,GAAG;AAC9B,qBAAAA,QAAG,cAAc,WAAW,aAAa;AACzC,cAAQ;AAAA,QACP;AAAA,MACD;AAAA,IACD;AAAA,EACD,SAAS,KAAK;AACb,YAAQ,MAAM,+BAAgC,IAAc,OAAO,EAAE;AACrE,YAAQ,MAAM,4CAA4C;AAAA,EAC3D;AAGA,UAAQ,IAAI,kDAAkD;AAC/D;AAEA,KAAK;","names":["os","path","fs"]}
|
package/dist/postinstall.js
CHANGED
|
@@ -47,27 +47,6 @@ function main() {
|
|
|
47
47
|
);
|
|
48
48
|
return;
|
|
49
49
|
}
|
|
50
|
-
let success = true;
|
|
51
|
-
const configFile = path.join(claudeDir, "settings.json");
|
|
52
|
-
try {
|
|
53
|
-
let config = {};
|
|
54
|
-
if (fs.existsSync(configFile)) {
|
|
55
|
-
config = JSON.parse(fs.readFileSync(configFile, "utf-8"));
|
|
56
|
-
}
|
|
57
|
-
if (!config.mcpServers?.prinfer) {
|
|
58
|
-
config.mcpServers = config.mcpServers || {};
|
|
59
|
-
config.mcpServers.prinfer = { command: "prinfer-mcp" };
|
|
60
|
-
fs.writeFileSync(
|
|
61
|
-
configFile,
|
|
62
|
-
`${JSON.stringify(config, null, 2)}
|
|
63
|
-
`
|
|
64
|
-
);
|
|
65
|
-
console.log("[ok] Added MCP server to settings.json");
|
|
66
|
-
}
|
|
67
|
-
} catch (err) {
|
|
68
|
-
console.error(`[error] MCP setup failed: ${err.message}`);
|
|
69
|
-
success = false;
|
|
70
|
-
}
|
|
71
50
|
const skillsDir = path.join(claudeDir, "skills");
|
|
72
51
|
const skillFile = path.join(skillsDir, "prefer-infer.md");
|
|
73
52
|
try {
|
|
@@ -82,11 +61,9 @@ function main() {
|
|
|
82
61
|
}
|
|
83
62
|
} catch (err) {
|
|
84
63
|
console.error(`[error] Skill setup failed: ${err.message}`);
|
|
85
|
-
|
|
86
|
-
}
|
|
87
|
-
if (!success) {
|
|
88
|
-
console.error("\nSome steps failed. Run 'prinfer setup' for details.");
|
|
64
|
+
console.error("Run 'prinfer setup' for full installation.");
|
|
89
65
|
}
|
|
66
|
+
console.log("Run 'prinfer setup' to configure the MCP server.");
|
|
90
67
|
}
|
|
91
68
|
main();
|
|
92
69
|
//# sourceMappingURL=postinstall.js.map
|
package/dist/postinstall.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/postinstall.ts"],"sourcesContent":["#!/usr/bin/env node\nimport fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\n\
|
|
1
|
+
{"version":3,"sources":["../src/postinstall.ts"],"sourcesContent":["#!/usr/bin/env node\nimport fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\n\nconst SKILL_CONTENT = `# TypeScript Type Inference (prinfer)\n\n## Coding Guideline\n\nWhen writing TypeScript code, prefer relying on type inference over explicit type annotations:\n\n- Let TypeScript infer return types for functions when the implementation makes them obvious\n- Let TypeScript infer variable types from their initializers\n- Only add explicit types when:\n - The inferred type is too wide (e.g., \\`string\\` instead of a literal type)\n - The type serves as documentation for complex structures\n - You're defining a public API contract\n\nUse the \\`prinfer\\` MCP tool (\\`infer_type\\`) to verify what TypeScript infers before adding explicit types.\n\n## Commands\n\n### /check-type\n\nCheck the inferred type of a TypeScript symbol.\n\nUsage: \\`/check-type <file>:<line> <name>\\` or \\`/check-type <file> <name>\\`\n\nExamples:\n- \\`/check-type src/utils.ts:75 commandResult\\`\n- \\`/check-type src/utils.ts myFunction\\`\n\n<command-name>check-type</command-name>\n\nUse the \\`infer_type\\` MCP tool to check the type:\n1. Parse the arguments to extract file, optional line number, and symbol name\n2. Call \\`infer_type(file, name, line?)\\`\n3. Report the inferred signature and return type\n`;\n\nfunction main() {\n\tconst homeDir = os.homedir();\n\tconst claudeDir = path.join(homeDir, \".claude\");\n\n\tif (!fs.existsSync(claudeDir)) {\n\t\tconsole.log(\n\t\t\t\"~/.claude not found. Run 'prinfer setup' after installing Claude Code.\",\n\t\t);\n\t\treturn;\n\t}\n\n\t// Install skill only (MCP setup requires 'claude' CLI which may not be available during npm install)\n\tconst skillsDir = path.join(claudeDir, \"skills\");\n\tconst skillFile = path.join(skillsDir, \"prefer-infer.md\");\n\ttry {\n\t\tif (!fs.existsSync(skillsDir)) {\n\t\t\tfs.mkdirSync(skillsDir, { recursive: true });\n\t\t}\n\n\t\tif (!fs.existsSync(skillFile)) {\n\t\t\tfs.writeFileSync(skillFile, SKILL_CONTENT);\n\t\t\tconsole.log(\n\t\t\t\t\"[ok] Installed skill to ~/.claude/skills/prefer-infer.md\",\n\t\t\t);\n\t\t}\n\t} catch (err) {\n\t\tconsole.error(`[error] Skill setup failed: ${(err as Error).message}`);\n\t\tconsole.error(\"Run 'prinfer setup' for full installation.\");\n\t}\n\n\t// Remind user to run setup for MCP\n\tconsole.log(\"Run 'prinfer setup' to configure the MCP server.\");\n}\n\nmain();\n"],"mappings":";;;AACA,OAAO,QAAQ;AACf,OAAO,QAAQ;AACf,OAAO,UAAU;AAEjB,IAAM,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAmCtB,SAAS,OAAO;AACf,QAAM,UAAU,GAAG,QAAQ;AAC3B,QAAM,YAAY,KAAK,KAAK,SAAS,SAAS;AAE9C,MAAI,CAAC,GAAG,WAAW,SAAS,GAAG;AAC9B,YAAQ;AAAA,MACP;AAAA,IACD;AACA;AAAA,EACD;AAGA,QAAM,YAAY,KAAK,KAAK,WAAW,QAAQ;AAC/C,QAAM,YAAY,KAAK,KAAK,WAAW,iBAAiB;AACxD,MAAI;AACH,QAAI,CAAC,GAAG,WAAW,SAAS,GAAG;AAC9B,SAAG,UAAU,WAAW,EAAE,WAAW,KAAK,CAAC;AAAA,IAC5C;AAEA,QAAI,CAAC,GAAG,WAAW,SAAS,GAAG;AAC9B,SAAG,cAAc,WAAW,aAAa;AACzC,cAAQ;AAAA,QACP;AAAA,MACD;AAAA,IACD;AAAA,EACD,SAAS,KAAK;AACb,YAAQ,MAAM,+BAAgC,IAAc,OAAO,EAAE;AACrE,YAAQ,MAAM,4CAA4C;AAAA,EAC3D;AAGA,UAAQ,IAAI,kDAAkD;AAC/D;AAEA,KAAK;","names":[]}
|