prinfer 0.5.3 → 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/dist/cli.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts","../src/index.ts","../src/core.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { execSync } from \"node:child_process\";\nimport fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { inferType } from \"./index.js\";\n\nconst HELP = `\nprinfer - TypeScript type inference inspection tool\n\nUsage:\n prinfer <file.ts>[:<line>] <name> [--project <tsconfig.json>]\n prinfer setup\n\nCommands:\n setup Install MCP server and skill for Claude Code\n\nArguments:\n file.ts Path to the TypeScript file\n :line Optional line number to narrow search (e.g., file.ts:75)\n name Name of the function/variable to inspect\n\nOptions:\n --project, -p Path to tsconfig.json (optional)\n --help, -h Show this help message\n\nExamples:\n prinfer src/utils.ts myFunction\n prinfer src/utils.ts:75 commandResult\n prinfer setup\n`.trim();\n\nconst MANUAL_SETUP = `\nManual setup instructions:\n\n1. Add MCP server:\n Run: claude mcp add prinfer node /path/to/prinfer-mcp\n\n2. Create skill file at ~/.claude/skills/prefer-infer.md:\n See https://github.com/clockblocker/prinfer for skill content.\n`.trim();\n\nfunction getMcpBinaryPath(): string {\n\t// Resolve absolute path to prinfer-mcp\n\t// It's in the same directory as this script (dist/)\n\tconst thisScript = new URL(import.meta.url).pathname;\n\treturn path.join(path.dirname(thisScript), \"mcp.js\");\n}\n\nfunction installMcpServer(): boolean {\n\ttry {\n\t\tconst mcpPath = getMcpBinaryPath();\n\n\t\t// Always remove first to ensure correct path (handles upgrades/fixes)\n\t\ttry {\n\t\t\texecSync(\"claude mcp remove prinfer\", { stdio: \"pipe\" });\n\t\t} catch {\n\t\t\t// Ignore if not exists\n\t\t}\n\n\t\t// Add MCP server with absolute path\n\t\texecSync(`claude mcp add prinfer node ${mcpPath}`, {\n\t\t\tstdio: \"inherit\",\n\t\t});\n\t\tconsole.log(\"[ok] Added prinfer MCP server\");\n\t\treturn true;\n\t} catch (err) {\n\t\tconsole.error(`[error] MCP setup failed: ${(err as Error).message}`);\n\t\treturn false;\n\t}\n}\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 runSetup(): void {\n\tconst homeDir = os.homedir();\n\tconst claudeDir = path.join(homeDir, \".claude\");\n\n\tif (!fs.existsSync(claudeDir)) {\n\t\tconsole.error(\"Error: ~/.claude directory not found.\");\n\t\tconsole.error(\"Make sure Claude Code is installed first.\\n\");\n\t\tconsole.error(MANUAL_SETUP);\n\t\tprocess.exit(1);\n\t}\n\n\t// Install MCP server using claude CLI\n\tconst mcpOk = installMcpServer();\n\n\t// Install skill\n\tlet skillOk = false;\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\tconsole.log(\"[ok] Skill already installed\");\n\t\t\tskillOk = true;\n\t\t} else {\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\tskillOk = true;\n\t\t}\n\t} catch (err) {\n\t\tconsole.error(\n\t\t\t`[error] Failed to install skill: ${(err as Error).message}`,\n\t\t);\n\t}\n\n\tif (mcpOk && skillOk) {\n\t\tconsole.log(\"\\nSetup complete! Restart Claude Code to use prinfer.\");\n\t} else {\n\t\tconsole.error(\"\\nSome steps failed. Manual setup:\\n\");\n\t\tconsole.error(MANUAL_SETUP);\n\t\tprocess.exit(1);\n\t}\n}\n\ninterface CliOptions {\n\tfile: string;\n\tname: string;\n\tline?: number;\n\tproject?: string;\n}\n\nfunction parseFileArg(arg: string): { file: string; line?: number } {\n\t// Match pattern: file.ts:123 or just file.ts\n\tconst match = arg.match(/^(.+):(\\d+)$/);\n\tif (match) {\n\t\treturn { file: match[1], line: Number.parseInt(match[2], 10) };\n\t}\n\treturn { file: arg };\n}\n\nfunction parseArgs(argv: string[]): CliOptions | null {\n\tconst args = argv.slice(2);\n\n\t// Check for help flag\n\tif (args.includes(\"--help\") || args.includes(\"-h\") || args.length === 0) {\n\t\tconsole.log(HELP);\n\t\treturn null;\n\t}\n\n\t// Check for setup command\n\tif (args[0] === \"setup\") {\n\t\trunSetup();\n\t\treturn null;\n\t}\n\n\tconst fileArg = args[0];\n\tconst name = args[1];\n\n\tif (!fileArg || !name) {\n\t\tconsole.error(\n\t\t\t\"Error: Both <file> and <name> arguments are required.\\n\",\n\t\t);\n\t\tconsole.log(HELP);\n\t\tprocess.exit(1);\n\t}\n\n\tconst { file, line } = parseFileArg(fileArg);\n\n\t// Find project option\n\tlet project: string | undefined;\n\tconst projectIdx = args.findIndex((a) => a === \"--project\" || a === \"-p\");\n\tif (projectIdx >= 0) {\n\t\tproject = args[projectIdx + 1];\n\t\tif (!project) {\n\t\t\tconsole.error(\"Error: --project requires a path argument.\\n\");\n\t\t\tconsole.log(HELP);\n\t\t\tprocess.exit(1);\n\t\t}\n\t}\n\n\treturn { file, name, line, project };\n}\n\nfunction main(): void {\n\tconst options = parseArgs(process.argv);\n\n\tif (!options) {\n\t\tprocess.exit(0);\n\t}\n\n\ttry {\n\t\tconst result = inferType(options.file, options.name, {\n\t\t\tline: options.line,\n\t\t\tproject: options.project,\n\t\t});\n\n\t\tconsole.log(result.signature);\n\t\tif (result.returnType) {\n\t\t\tconsole.log(\"returns:\", result.returnType);\n\t\t}\n\t} catch (error) {\n\t\tconsole.error((error as Error).message);\n\t\tprocess.exit(1);\n\t}\n}\n\nmain();\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":["import_node_fs","import_node_path","import_node_path","ts","path","ts","path","fs","path","os","fs"]}
1
+ {"version":3,"sources":["../src/cli.ts","../src/index.ts","../src/core.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { execSync } from \"node:child_process\";\nimport fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { hover } from \"./index.js\";\n\nconst HELP = `\nprinfer - TypeScript type inference inspection tool\n\nUsage:\n prinfer <file.ts>:<line>:<column> [--docs] [--project <tsconfig.json>]\n prinfer setup\n\nCommands:\n setup Install MCP server and skill for Claude Code\n\nArguments:\n file.ts:line:column Path to TypeScript file with 1-based line and column\n\nOptions:\n --docs, -d Include JSDoc/TSDoc documentation\n --project, -p Path to tsconfig.json (optional)\n --help, -h Show this help message\n\nExamples:\n prinfer src/utils.ts:75:10\n prinfer src/utils.ts:75:10 --docs\n prinfer src/utils.ts:75:10 --project ./tsconfig.json\n prinfer setup\n`.trim();\n\nconst MANUAL_SETUP = `\nManual setup instructions:\n\n1. Add MCP server:\n Run: claude mcp add prinfer node /path/to/prinfer-mcp\n\n2. Create skill file at ~/.claude/skills/prefer-infer.md:\n See https://github.com/clockblocker/prinfer for skill content.\n`.trim();\n\nfunction getMcpBinaryPath(): string {\n\t// Resolve absolute path to prinfer-mcp\n\t// It's in the same directory as this script (dist/)\n\tconst thisScript = new URL(import.meta.url).pathname;\n\treturn path.join(path.dirname(thisScript), \"mcp.js\");\n}\n\nfunction installMcpServer(): boolean {\n\ttry {\n\t\tconst mcpPath = getMcpBinaryPath();\n\n\t\t// Always remove first to ensure correct path (handles upgrades/fixes)\n\t\ttry {\n\t\t\texecSync(\"claude mcp remove prinfer\", { stdio: \"pipe\" });\n\t\t} catch {\n\t\t\t// Ignore if not exists\n\t\t}\n\n\t\t// Add MCP server with absolute path\n\t\texecSync(`claude mcp add prinfer node ${mcpPath}`, {\n\t\t\tstdio: \"inherit\",\n\t\t});\n\t\tconsole.log(\"[ok] Added prinfer MCP server\");\n\t\treturn true;\n\t} catch (err) {\n\t\tconsole.error(`[error] MCP setup failed: ${(err as Error).message}`);\n\t\treturn false;\n\t}\n}\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 (\\`hover\\`) to verify what TypeScript infers before adding explicit types.\n\n## Commands\n\n### /hover\n\nCheck the inferred type at a specific position in a TypeScript file.\n\nUsage: \\`/hover <file>:<line>:<column>\\`\n\nExamples:\n- \\`/hover src/utils.ts:75:10\\`\n- \\`/hover src/utils.ts:42:5\\`\n\n<command-name>hover</command-name>\n\nUse the \\`hover\\` MCP tool to check the type:\n1. Parse the arguments to extract file, line, and column\n2. Call \\`hover(file, line, column, { include_docs: true })\\`\n3. Report the inferred signature, return type, and documentation\n`;\n\nfunction runSetup(): void {\n\tconst homeDir = os.homedir();\n\tconst claudeDir = path.join(homeDir, \".claude\");\n\n\tif (!fs.existsSync(claudeDir)) {\n\t\tconsole.error(\"Error: ~/.claude directory not found.\");\n\t\tconsole.error(\"Make sure Claude Code is installed first.\\n\");\n\t\tconsole.error(MANUAL_SETUP);\n\t\tprocess.exit(1);\n\t}\n\n\t// Install MCP server using claude CLI\n\tconst mcpOk = installMcpServer();\n\n\t// Install skill\n\tlet skillOk = false;\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\tconsole.log(\"[ok] Skill already installed\");\n\t\t\tskillOk = true;\n\t\t} else {\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\tskillOk = true;\n\t\t}\n\t} catch (err) {\n\t\tconsole.error(\n\t\t\t`[error] Failed to install skill: ${(err as Error).message}`,\n\t\t);\n\t}\n\n\tif (mcpOk && skillOk) {\n\t\tconsole.log(\"\\nSetup complete! Restart Claude Code to use prinfer.\");\n\t} else {\n\t\tconsole.error(\"\\nSome steps failed. Manual setup:\\n\");\n\t\tconsole.error(MANUAL_SETUP);\n\t\tprocess.exit(1);\n\t}\n}\n\ninterface CliOptions {\n\tfile: string;\n\tline: number;\n\tcolumn: number;\n\tincludeDocs: boolean;\n\tproject?: string;\n}\n\nfunction parsePositionArg(\n\targ: string,\n): { file: string; line: number; column: number } | null {\n\t// Match pattern: file.ts:line:column\n\tconst match = arg.match(/^(.+):(\\d+):(\\d+)$/);\n\tif (match) {\n\t\treturn {\n\t\t\tfile: match[1],\n\t\t\tline: Number.parseInt(match[2], 10),\n\t\t\tcolumn: Number.parseInt(match[3], 10),\n\t\t};\n\t}\n\treturn null;\n}\n\nfunction parseArgs(argv: string[]): CliOptions | null {\n\tconst args = argv.slice(2);\n\n\t// Check for help flag\n\tif (args.includes(\"--help\") || args.includes(\"-h\") || args.length === 0) {\n\t\tconsole.log(HELP);\n\t\treturn null;\n\t}\n\n\t// Check for setup command\n\tif (args[0] === \"setup\") {\n\t\trunSetup();\n\t\treturn null;\n\t}\n\n\tconst positionArg = args[0];\n\tconst parsed = parsePositionArg(positionArg);\n\n\tif (!parsed) {\n\t\tconsole.error(\n\t\t\t\"Error: Position argument must be in format <file>:<line>:<column>\\n\",\n\t\t);\n\t\tconsole.log(HELP);\n\t\tprocess.exit(1);\n\t}\n\n\tconst { file, line, column } = parsed;\n\n\t// Check for docs flag\n\tconst includeDocs = args.includes(\"--docs\") || args.includes(\"-d\");\n\n\t// Find project option\n\tlet project: string | undefined;\n\tconst projectIdx = args.findIndex((a) => a === \"--project\" || a === \"-p\");\n\tif (projectIdx >= 0) {\n\t\tproject = args[projectIdx + 1];\n\t\tif (!project) {\n\t\t\tconsole.error(\"Error: --project requires a path argument.\\n\");\n\t\t\tconsole.log(HELP);\n\t\t\tprocess.exit(1);\n\t\t}\n\t}\n\n\treturn { file, line, column, includeDocs, project };\n}\n\nfunction main(): void {\n\tconst options = parseArgs(process.argv);\n\n\tif (!options) {\n\t\tprocess.exit(0);\n\t}\n\n\ttry {\n\t\tconst result = hover(options.file, options.line, options.column, {\n\t\t\tinclude_docs: options.includeDocs,\n\t\t\tproject: options.project,\n\t\t});\n\n\t\tconsole.log(result.signature);\n\t\tif (result.returnType) {\n\t\t\tconsole.log(\"returns:\", result.returnType);\n\t\t}\n\t\tif (result.name) {\n\t\t\tconsole.log(\"name:\", result.name);\n\t\t}\n\t\tconsole.log(\"kind:\", result.kind);\n\t\tif (result.documentation) {\n\t\t\tconsole.log(\"docs:\", result.documentation);\n\t\t}\n\t} catch (error) {\n\t\tconsole.error((error as Error).message);\n\t\tprocess.exit(1);\n\t}\n}\n\nmain();\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":["import_node_fs","import_node_path","import_node_path","ts","path","ts","nodeWithName","sig","t","path","fs","path","os","fs"]}
package/dist/cli.js CHANGED
@@ -49,66 +49,203 @@ function loadProgram(entryFileAbs, project) {
49
49
  function isArrowOrFnExpr(n) {
50
50
  return !!n && (ts.isArrowFunction(n) || ts.isFunctionExpression(n));
51
51
  }
52
- function nodeNameText(n) {
53
- if (!n) return void 0;
54
- if (ts.isIdentifier(n)) return n.text;
55
- if (ts.isStringLiteral(n)) return n.text;
56
- if (ts.isNumericLiteral(n)) return n.text;
57
- return void 0;
58
- }
59
- function isFunctionLikeNamed(node, name) {
60
- if (ts.isFunctionDeclaration(node) && node.name?.text === name) return true;
61
- if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name) && node.name.text === name) {
62
- return isArrowOrFnExpr(node.initializer);
63
- }
64
- if ((ts.isMethodDeclaration(node) || ts.isMethodSignature(node)) && nodeNameText(node.name) === name) {
65
- return true;
66
- }
67
- if (ts.isPropertyAssignment(node) && nodeNameText(node.name) === name) {
68
- return isArrowOrFnExpr(node.initializer);
52
+ function findSmallestNodeAtPosition(sourceFile, position) {
53
+ let result;
54
+ function visit(node) {
55
+ const start = node.getStart(sourceFile);
56
+ const end = node.getEnd();
57
+ if (position < start || position >= end) {
58
+ return;
59
+ }
60
+ if (!result || node.getWidth(sourceFile) <= result.getWidth(sourceFile)) {
61
+ result = node;
62
+ }
63
+ ts.forEachChild(node, visit);
69
64
  }
70
- return false;
65
+ visit(sourceFile);
66
+ return result;
71
67
  }
72
- function isVariableNamed(node, name) {
73
- if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name) && node.name.text === name) {
68
+ function findHoverableAncestor(sourceFile, position) {
69
+ const smallestNode = findSmallestNodeAtPosition(sourceFile, position);
70
+ if (!smallestNode) return void 0;
71
+ let bestMatch = smallestNode;
72
+ function visit(n) {
73
+ const start = n.getStart(sourceFile);
74
+ const end = n.getEnd();
75
+ if (position < start || position >= end) {
76
+ return false;
77
+ }
78
+ if (ts.isCallExpression(n)) {
79
+ const expr = n.expression;
80
+ if (ts.isIdentifier(expr)) {
81
+ if (position >= expr.getStart(sourceFile) && position < expr.getEnd()) {
82
+ bestMatch = n;
83
+ }
84
+ } else if (ts.isPropertyAccessExpression(expr)) {
85
+ if (position >= expr.name.getStart(sourceFile) && position < expr.name.getEnd()) {
86
+ bestMatch = n;
87
+ }
88
+ }
89
+ }
90
+ if (ts.isFunctionDeclaration(n) && n.name) {
91
+ if (position >= n.name.getStart(sourceFile) && position < n.name.getEnd()) {
92
+ bestMatch = n;
93
+ }
94
+ }
95
+ if (ts.isVariableDeclaration(n) && ts.isIdentifier(n.name)) {
96
+ if (position >= n.name.getStart(sourceFile) && position < n.name.getEnd()) {
97
+ bestMatch = n;
98
+ }
99
+ }
100
+ if ((ts.isMethodDeclaration(n) || ts.isMethodSignature(n)) && ts.isIdentifier(n.name)) {
101
+ if (position >= n.name.getStart(sourceFile) && position < n.name.getEnd()) {
102
+ bestMatch = n;
103
+ }
104
+ }
105
+ if (ts.isClassDeclaration(n) && n.name) {
106
+ if (position >= n.name.getStart(sourceFile) && position < n.name.getEnd()) {
107
+ bestMatch = n;
108
+ }
109
+ }
110
+ if (ts.isInterfaceDeclaration(n) && n.name) {
111
+ if (position >= n.name.getStart(sourceFile) && position < n.name.getEnd()) {
112
+ bestMatch = n;
113
+ }
114
+ }
115
+ ts.forEachChild(n, visit);
74
116
  return true;
75
117
  }
76
- return false;
77
- }
78
- function isNamedNode(node, name) {
79
- return isFunctionLikeNamed(node, name) || isVariableNamed(node, name);
118
+ visit(sourceFile);
119
+ return bestMatch;
80
120
  }
81
- function getLineNumber(sourceFile, node) {
82
- const { line } = sourceFile.getLineAndCharacterOfPosition(
83
- node.getStart(sourceFile)
121
+ function findNodeAtPosition(sourceFile, line, column) {
122
+ const lineCount = sourceFile.getLineStarts().length;
123
+ if (line < 1 || line > lineCount) {
124
+ return void 0;
125
+ }
126
+ const lineStart = sourceFile.getLineStarts()[line - 1];
127
+ const lineEnd = line < lineCount ? sourceFile.getLineStarts()[line] : sourceFile.getEnd();
128
+ const lineLength = lineEnd - lineStart;
129
+ if (column < 1 || column > lineLength + 1) {
130
+ return void 0;
131
+ }
132
+ const position = sourceFile.getPositionOfLineAndCharacter(
133
+ line - 1,
134
+ column - 1
84
135
  );
85
- return line + 1;
136
+ return findHoverableAncestor(sourceFile, position);
86
137
  }
87
- function findNodeByNameAndLine(sourceFile, name, line) {
88
- let found;
89
- const visit = (node) => {
90
- if (found) return;
91
- if (isNamedNode(node, name)) {
92
- if (line !== void 0) {
93
- const nodeLine = getLineNumber(sourceFile, node);
94
- if (nodeLine === line) {
95
- found = node;
96
- return;
97
- }
98
- } else {
99
- found = node;
100
- return;
101
- }
138
+ function getSymbolKind(node) {
139
+ if (ts.isFunctionDeclaration(node)) return "function";
140
+ if (ts.isArrowFunction(node)) return "function";
141
+ if (ts.isFunctionExpression(node)) return "function";
142
+ if (ts.isMethodDeclaration(node)) return "method";
143
+ if (ts.isMethodSignature(node)) return "method";
144
+ if (ts.isVariableDeclaration(node)) {
145
+ const init = node.initializer;
146
+ if (init && (ts.isArrowFunction(init) || ts.isFunctionExpression(init))) {
147
+ return "function";
102
148
  }
103
- ts.forEachChild(node, visit);
104
- };
105
- visit(sourceFile);
106
- return found;
149
+ return "variable";
150
+ }
151
+ if (ts.isParameter(node)) return "parameter";
152
+ if (ts.isPropertyDeclaration(node)) return "property";
153
+ if (ts.isPropertySignature(node)) return "property";
154
+ if (ts.isPropertyAccessExpression(node)) return "property";
155
+ if (ts.isCallExpression(node)) return "call";
156
+ if (ts.isTypeAliasDeclaration(node)) return "type";
157
+ if (ts.isInterfaceDeclaration(node)) return "interface";
158
+ if (ts.isClassDeclaration(node)) return "class";
159
+ if (ts.isIdentifier(node)) return "identifier";
160
+ return "unknown";
161
+ }
162
+ function getNodeName(node) {
163
+ if (ts.isFunctionDeclaration(node) && node.name) {
164
+ return node.name.text;
165
+ }
166
+ if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name)) {
167
+ return node.name.text;
168
+ }
169
+ if ((ts.isMethodDeclaration(node) || ts.isMethodSignature(node)) && ts.isIdentifier(node.name)) {
170
+ return node.name.text;
171
+ }
172
+ if (ts.isPropertyAccessExpression(node)) {
173
+ return node.name.text;
174
+ }
175
+ if (ts.isCallExpression(node)) {
176
+ const expr = node.expression;
177
+ if (ts.isIdentifier(expr)) return expr.text;
178
+ if (ts.isPropertyAccessExpression(expr)) return expr.name.text;
179
+ }
180
+ if (ts.isParameter(node) && ts.isIdentifier(node.name)) {
181
+ return node.name.text;
182
+ }
183
+ if (ts.isIdentifier(node)) {
184
+ return node.text;
185
+ }
186
+ if (ts.isTypeAliasDeclaration(node) || ts.isInterfaceDeclaration(node) || ts.isClassDeclaration(node)) {
187
+ return node.name?.text;
188
+ }
189
+ return void 0;
107
190
  }
108
- function getTypeInfo(program, node, sourceFile) {
191
+ function getDocumentation(checker, symbol) {
192
+ if (!symbol) return void 0;
193
+ const docs = symbol.getDocumentationComment(checker);
194
+ if (docs.length === 0) return void 0;
195
+ return ts.displayPartsToString(docs);
196
+ }
197
+ function getHoverInfo(program, node, sourceFile, includeDocs) {
109
198
  const checker = program.getTypeChecker();
110
- const sf = sourceFile ?? node.getSourceFile();
111
- const line = getLineNumber(sf, node);
199
+ const sf = sourceFile;
200
+ const { line, character } = sf.getLineAndCharacterOfPosition(
201
+ node.getStart(sf)
202
+ );
203
+ const flags = ts.TypeFormatFlags.NoTruncation;
204
+ const kind = getSymbolKind(node);
205
+ const name = getNodeName(node);
206
+ let symbol;
207
+ if (ts.isCallExpression(node)) {
208
+ const expr = node.expression;
209
+ if (ts.isPropertyAccessExpression(expr)) {
210
+ symbol = checker.getSymbolAtLocation(expr.name);
211
+ } else {
212
+ symbol = checker.getSymbolAtLocation(expr);
213
+ }
214
+ } else {
215
+ const nodeWithName2 = node;
216
+ if (nodeWithName2.name) {
217
+ symbol = checker.getSymbolAtLocation(nodeWithName2.name);
218
+ } else {
219
+ symbol = checker.getSymbolAtLocation(node);
220
+ }
221
+ }
222
+ const documentation = includeDocs ? getDocumentation(checker, symbol) : void 0;
223
+ if (ts.isCallExpression(node)) {
224
+ const sig2 = checker.getResolvedSignature(node);
225
+ if (sig2) {
226
+ const signature = checker.signatureToString(sig2, void 0, flags);
227
+ const ret = checker.getReturnTypeOfSignature(sig2);
228
+ const returnType = checker.typeToString(ret, void 0, flags);
229
+ return {
230
+ signature,
231
+ returnType,
232
+ line: line + 1,
233
+ column: character + 1,
234
+ documentation,
235
+ kind,
236
+ name
237
+ };
238
+ }
239
+ const t2 = checker.getTypeAtLocation(node);
240
+ return {
241
+ signature: checker.typeToString(t2, void 0, flags),
242
+ line: line + 1,
243
+ column: character + 1,
244
+ documentation,
245
+ kind,
246
+ name
247
+ };
248
+ }
112
249
  let sig;
113
250
  if (ts.isFunctionDeclaration(node) || ts.isMethodDeclaration(node)) {
114
251
  sig = checker.getSignatureFromDeclaration(node) ?? void 0;
@@ -123,26 +260,39 @@ function getTypeInfo(program, node, sourceFile) {
123
260
  } else if (ts.isMethodSignature(node)) {
124
261
  sig = checker.getSignatureFromDeclaration(node) ?? void 0;
125
262
  }
126
- const flags = ts.TypeFormatFlags.NoTruncation;
127
263
  if (sig) {
128
264
  const signature = checker.signatureToString(sig, void 0, flags);
129
265
  const ret = checker.getReturnTypeOfSignature(sig);
130
266
  const returnType = checker.typeToString(ret, void 0, flags);
131
- return { signature, returnType, line };
267
+ return {
268
+ signature,
269
+ returnType,
270
+ line: line + 1,
271
+ column: character + 1,
272
+ documentation,
273
+ kind,
274
+ name
275
+ };
132
276
  }
133
277
  const nodeWithName = node;
134
- let nameNode = node;
278
+ let targetNode = node;
135
279
  if (nodeWithName.name && ts.isIdentifier(nodeWithName.name)) {
136
- nameNode = nodeWithName.name;
280
+ targetNode = nodeWithName.name;
137
281
  }
138
- const t = checker.getTypeAtLocation(nameNode);
139
- return { signature: checker.typeToString(t, void 0, flags), line };
282
+ const t = checker.getTypeAtLocation(targetNode);
283
+ return {
284
+ signature: checker.typeToString(t, void 0, flags),
285
+ line: line + 1,
286
+ column: character + 1,
287
+ documentation,
288
+ kind,
289
+ name
290
+ };
140
291
  }
141
292
 
142
293
  // src/index.ts
143
- function inferType(file, name, options) {
144
- const opts = typeof options === "string" ? { project: options } : options ?? {};
145
- const { line, project } = opts;
294
+ function hover(file, line, column, options) {
295
+ const { project, include_docs = false } = options ?? {};
146
296
  const entryFileAbs = path2.resolve(process.cwd(), file);
147
297
  if (!fs.existsSync(entryFileAbs)) {
148
298
  throw new Error(`File not found: ${entryFileAbs}`);
@@ -154,14 +304,11 @@ function inferType(file, name, options) {
154
304
  `Could not load source file into the program (check tsconfig include/exclude): ${entryFileAbs}`
155
305
  );
156
306
  }
157
- const node = findNodeByNameAndLine(sourceFile, name, line);
307
+ const node = findNodeAtPosition(sourceFile, line, column);
158
308
  if (!node) {
159
- const lineInfo = line !== void 0 ? ` at line ${line}` : "";
160
- throw new Error(
161
- `No symbol named "${name}"${lineInfo} found in ${entryFileAbs}`
162
- );
309
+ throw new Error(`No symbol found at ${entryFileAbs}:${line}:${column}`);
163
310
  }
164
- return getTypeInfo(program, node, sourceFile);
311
+ return getHoverInfo(program, node, sourceFile, include_docs);
165
312
  }
166
313
 
167
314
  // src/cli.ts
@@ -169,24 +316,24 @@ var HELP = `
169
316
  prinfer - TypeScript type inference inspection tool
170
317
 
171
318
  Usage:
172
- prinfer <file.ts>[:<line>] <name> [--project <tsconfig.json>]
319
+ prinfer <file.ts>:<line>:<column> [--docs] [--project <tsconfig.json>]
173
320
  prinfer setup
174
321
 
175
322
  Commands:
176
323
  setup Install MCP server and skill for Claude Code
177
324
 
178
325
  Arguments:
179
- file.ts Path to the TypeScript file
180
- :line Optional line number to narrow search (e.g., file.ts:75)
181
- name Name of the function/variable to inspect
326
+ file.ts:line:column Path to TypeScript file with 1-based line and column
182
327
 
183
328
  Options:
329
+ --docs, -d Include JSDoc/TSDoc documentation
184
330
  --project, -p Path to tsconfig.json (optional)
185
331
  --help, -h Show this help message
186
332
 
187
333
  Examples:
188
- prinfer src/utils.ts myFunction
189
- prinfer src/utils.ts:75 commandResult
334
+ prinfer src/utils.ts:75:10
335
+ prinfer src/utils.ts:75:10 --docs
336
+ prinfer src/utils.ts:75:10 --project ./tsconfig.json
190
337
  prinfer setup
191
338
  `.trim();
192
339
  var MANUAL_SETUP = `
@@ -232,26 +379,26 @@ When writing TypeScript code, prefer relying on type inference over explicit typ
232
379
  - The type serves as documentation for complex structures
233
380
  - You're defining a public API contract
234
381
 
235
- Use the \`prinfer\` MCP tool (\`infer_type\`) to verify what TypeScript infers before adding explicit types.
382
+ Use the \`prinfer\` MCP tool (\`hover\`) to verify what TypeScript infers before adding explicit types.
236
383
 
237
384
  ## Commands
238
385
 
239
- ### /check-type
386
+ ### /hover
240
387
 
241
- Check the inferred type of a TypeScript symbol.
388
+ Check the inferred type at a specific position in a TypeScript file.
242
389
 
243
- Usage: \`/check-type <file>:<line> <name>\` or \`/check-type <file> <name>\`
390
+ Usage: \`/hover <file>:<line>:<column>\`
244
391
 
245
392
  Examples:
246
- - \`/check-type src/utils.ts:75 commandResult\`
247
- - \`/check-type src/utils.ts myFunction\`
393
+ - \`/hover src/utils.ts:75:10\`
394
+ - \`/hover src/utils.ts:42:5\`
248
395
 
249
- <command-name>check-type</command-name>
396
+ <command-name>hover</command-name>
250
397
 
251
- Use the \`infer_type\` MCP tool to check the type:
252
- 1. Parse the arguments to extract file, optional line number, and symbol name
253
- 2. Call \`infer_type(file, name, line?)\`
254
- 3. Report the inferred signature and return type
398
+ Use the \`hover\` MCP tool to check the type:
399
+ 1. Parse the arguments to extract file, line, and column
400
+ 2. Call \`hover(file, line, column, { include_docs: true })\`
401
+ 3. Report the inferred signature, return type, and documentation
255
402
  `;
256
403
  function runSetup() {
257
404
  const homeDir = os.homedir();
@@ -293,12 +440,16 @@ function runSetup() {
293
440
  process.exit(1);
294
441
  }
295
442
  }
296
- function parseFileArg(arg) {
297
- const match = arg.match(/^(.+):(\d+)$/);
443
+ function parsePositionArg(arg) {
444
+ const match = arg.match(/^(.+):(\d+):(\d+)$/);
298
445
  if (match) {
299
- return { file: match[1], line: Number.parseInt(match[2], 10) };
446
+ return {
447
+ file: match[1],
448
+ line: Number.parseInt(match[2], 10),
449
+ column: Number.parseInt(match[3], 10)
450
+ };
300
451
  }
301
- return { file: arg };
452
+ return null;
302
453
  }
303
454
  function parseArgs(argv) {
304
455
  const args = argv.slice(2);
@@ -310,16 +461,17 @@ function parseArgs(argv) {
310
461
  runSetup();
311
462
  return null;
312
463
  }
313
- const fileArg = args[0];
314
- const name = args[1];
315
- if (!fileArg || !name) {
464
+ const positionArg = args[0];
465
+ const parsed = parsePositionArg(positionArg);
466
+ if (!parsed) {
316
467
  console.error(
317
- "Error: Both <file> and <name> arguments are required.\n"
468
+ "Error: Position argument must be in format <file>:<line>:<column>\n"
318
469
  );
319
470
  console.log(HELP);
320
471
  process.exit(1);
321
472
  }
322
- const { file, line } = parseFileArg(fileArg);
473
+ const { file, line, column } = parsed;
474
+ const includeDocs = args.includes("--docs") || args.includes("-d");
323
475
  let project;
324
476
  const projectIdx = args.findIndex((a) => a === "--project" || a === "-p");
325
477
  if (projectIdx >= 0) {
@@ -330,7 +482,7 @@ function parseArgs(argv) {
330
482
  process.exit(1);
331
483
  }
332
484
  }
333
- return { file, name, line, project };
485
+ return { file, line, column, includeDocs, project };
334
486
  }
335
487
  function main() {
336
488
  const options = parseArgs(process.argv);
@@ -338,14 +490,21 @@ function main() {
338
490
  process.exit(0);
339
491
  }
340
492
  try {
341
- const result = inferType(options.file, options.name, {
342
- line: options.line,
493
+ const result = hover(options.file, options.line, options.column, {
494
+ include_docs: options.includeDocs,
343
495
  project: options.project
344
496
  });
345
497
  console.log(result.signature);
346
498
  if (result.returnType) {
347
499
  console.log("returns:", result.returnType);
348
500
  }
501
+ if (result.name) {
502
+ console.log("name:", result.name);
503
+ }
504
+ console.log("kind:", result.kind);
505
+ if (result.documentation) {
506
+ console.log("docs:", result.documentation);
507
+ }
349
508
  } catch (error) {
350
509
  console.error(error.message);
351
510
  process.exit(1);