typegraph-mcp 0.9.1 → 0.9.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "typegraph",
3
- "version": "0.9.1",
3
+ "version": "0.9.3",
4
4
  "description": "Type-aware TypeScript navigation — 14 MCP tools for go-to-definition, find-references, dependency graphs, cycle detection, and impact analysis",
5
5
  "author": {
6
6
  "name": "Owen Jones"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "typegraph",
3
- "version": "0.9.1",
3
+ "version": "0.9.3",
4
4
  "description": "Type-aware TypeScript navigation — 14 MCP tools for go-to-definition, find-references, dependency graphs, cycle detection, and impact analysis",
5
5
  "author": {
6
6
  "name": "Owen Jones"
package/README.md CHANGED
@@ -48,7 +48,7 @@ Agent: ts_trace_chain({ file: "src/handlers.ts", symbol: "createUser" })
48
48
  ```bash
49
49
  # Clone and install
50
50
  git clone https://github.com/guyowen/typegraph-mcp.git ~/typegraph-mcp
51
- cd ~/typegraph-mcp && pnpm install
51
+ cd ~/typegraph-mcp && npm install
52
52
 
53
53
  # Load the plugin
54
54
  claude --plugin-dir ~/typegraph-mcp
@@ -65,7 +65,7 @@ The plugin auto-configures everything:
65
65
  ```bash
66
66
  # Clone and install
67
67
  git clone https://github.com/guyowen/typegraph-mcp.git ~/typegraph-mcp
68
- cd ~/typegraph-mcp && pnpm install
68
+ cd ~/typegraph-mcp && npm install
69
69
 
70
70
  # Run setup from your project root
71
71
  cd /path/to/your-ts-project
@@ -115,7 +115,7 @@ First query takes ~2s (tsserver warmup). Subsequent queries: 1–60ms.
115
115
 
116
116
  - **Node.js** >= 18
117
117
  - **TypeScript** >= 5.0 in the target project (`node_modules`)
118
- - **pnpm** (or npm) for installing typegraph-mcp dependencies
118
+ - **npm** for installing typegraph-mcp dependencies
119
119
 
120
120
  ## CLI
121
121
 
@@ -435,7 +435,7 @@ npx tsx ~/typegraph-mcp/cli.ts check
435
435
 
436
436
  | Symptom | Likely cause | Fix |
437
437
  |---|---|---|
438
- | Server won't start | Dependencies missing | `cd /path/to/typegraph-mcp && pnpm install` |
438
+ | Server won't start | Dependencies missing | `cd /path/to/typegraph-mcp && npm install` |
439
439
  | "TypeScript not found" | Target project missing TS | Add `typescript` to devDependencies |
440
440
  | Tools return empty results | tsconfig misconfigured | Check `TYPEGRAPH_TSCONFIG` points to the right file |
441
441
  | MCP registration not found | Wrong path in config | Verify the `args` path to `server.ts` is absolute |
package/check.ts CHANGED
@@ -6,7 +6,7 @@
6
6
  * npx tsx plugins/typegraph-mcp/check.ts
7
7
  *
8
8
  * Or from plugins/typegraph-mcp/:
9
- * pnpm check
9
+ * npm run check
10
10
  */
11
11
 
12
12
  import * as fs from "node:fs";
@@ -170,7 +170,7 @@ export async function main(configOverride?: TypegraphConfig): Promise<CheckResul
170
170
  } catch {
171
171
  fail(
172
172
  "TypeScript not found in project",
173
- "Add `typescript` to devDependencies and run `pnpm install`"
173
+ "Add `typescript` to devDependencies and run `npm install`"
174
174
  );
175
175
  }
176
176
 
@@ -251,10 +251,10 @@ export async function main(configOverride?: TypegraphConfig): Promise<CheckResul
251
251
  if (missing.length === 0) {
252
252
  pass(`Dependencies installed (${requiredPkgs.length} packages)`);
253
253
  } else {
254
- fail(`Missing packages: ${missing.join(", ")}`, `Run \`cd ${toolRelPath} && pnpm install\``);
254
+ fail(`Missing packages: ${missing.join(", ")}`, `Run \`cd ${toolRelPath} && npm install\``);
255
255
  }
256
256
  } else {
257
- fail("typegraph-mcp dependencies not installed", `Run \`cd ${toolRelPath} && pnpm install\``);
257
+ fail("typegraph-mcp dependencies not installed", `Run \`cd ${toolRelPath} && npm install\``);
258
258
  }
259
259
 
260
260
  // 7. oxc-parser smoke test
@@ -267,13 +267,13 @@ export async function main(configOverride?: TypegraphConfig): Promise<CheckResul
267
267
  } else {
268
268
  fail(
269
269
  "oxc-parser parseSync returned unexpected result",
270
- `Reinstall: \`cd ${toolRelPath} && rm -rf node_modules && pnpm install\``
270
+ `Reinstall: \`cd ${toolRelPath} && rm -rf node_modules && npm install\``
271
271
  );
272
272
  }
273
273
  } catch (err) {
274
274
  fail(
275
275
  `oxc-parser failed: ${err instanceof Error ? err.message : String(err)}`,
276
- `Reinstall: \`cd ${toolRelPath} && rm -rf node_modules && pnpm install\``
276
+ `Reinstall: \`cd ${toolRelPath} && rm -rf node_modules && npm install\``
277
277
  );
278
278
  }
279
279
 
@@ -307,7 +307,7 @@ export async function main(configOverride?: TypegraphConfig): Promise<CheckResul
307
307
  } catch (err) {
308
308
  fail(
309
309
  `oxc-resolver failed: ${err instanceof Error ? err.message : String(err)}`,
310
- `Reinstall: \`cd ${toolRelPath} && rm -rf node_modules && pnpm install\``
310
+ `Reinstall: \`cd ${toolRelPath} && rm -rf node_modules && npm install\``
311
311
  );
312
312
  }
313
313
 
package/cli.ts CHANGED
@@ -111,7 +111,7 @@ const CORE_FILES = [
111
111
  "smoke-test.ts",
112
112
  "cli.ts",
113
113
  "package.json",
114
- "pnpm-lock.yaml",
114
+ "package-lock.json",
115
115
  ];
116
116
 
117
117
  /** Skill files inside plugin dir (Claude Code + Cursor discover from skills/) */
@@ -356,7 +356,9 @@ async function selectAgents(projectRoot: string, yes: boolean): Promise<AgentId[
356
356
  // ─── Setup Command ───────────────────────────────────────────────────────────
357
357
 
358
358
  async function setup(yes: boolean): Promise<void> {
359
- const sourceDir = import.meta.dirname;
359
+ const sourceDir = path.basename(import.meta.dirname) === "dist"
360
+ ? path.resolve(import.meta.dirname, "..")
361
+ : import.meta.dirname;
360
362
  const projectRoot = process.cwd();
361
363
 
362
364
  process.stdout.write("\x1Bc"); // Clear terminal
package/dist/check.js ADDED
@@ -0,0 +1,376 @@
1
+
2
+ // check.ts
3
+ import * as fs from "fs";
4
+ import * as path2 from "path";
5
+ import { createRequire } from "module";
6
+ import { spawn } from "child_process";
7
+
8
+ // config.ts
9
+ import * as path from "path";
10
+ function resolveConfig(toolDir) {
11
+ const cwd = process.cwd();
12
+ const projectRoot = process.env["TYPEGRAPH_PROJECT_ROOT"] ? path.resolve(cwd, process.env["TYPEGRAPH_PROJECT_ROOT"]) : path.basename(path.dirname(toolDir)) === "plugins" ? path.resolve(toolDir, "../..") : cwd;
13
+ const tsconfigPath = process.env["TYPEGRAPH_TSCONFIG"] || "./tsconfig.json";
14
+ const toolIsEmbedded = toolDir.startsWith(projectRoot + path.sep);
15
+ const toolRelPath = toolIsEmbedded ? path.relative(projectRoot, toolDir) : toolDir;
16
+ return { projectRoot, tsconfigPath, toolDir, toolIsEmbedded, toolRelPath };
17
+ }
18
+
19
+ // check.ts
20
+ function findFirstTsFile(dir) {
21
+ const skipDirs = /* @__PURE__ */ new Set(["node_modules", "dist", ".git", ".wrangler", "coverage"]);
22
+ try {
23
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
24
+ if (entry.isFile() && entry.name.endsWith(".ts") && !entry.name.endsWith(".d.ts")) {
25
+ return path2.join(dir, entry.name);
26
+ }
27
+ }
28
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
29
+ if (entry.isDirectory() && !skipDirs.has(entry.name) && !entry.name.startsWith(".")) {
30
+ const found = findFirstTsFile(path2.join(dir, entry.name));
31
+ if (found) return found;
32
+ }
33
+ }
34
+ } catch {
35
+ }
36
+ return null;
37
+ }
38
+ function testTsserver(projectRoot) {
39
+ return new Promise((resolve3) => {
40
+ let tsserverPath;
41
+ try {
42
+ const require2 = createRequire(path2.resolve(projectRoot, "package.json"));
43
+ tsserverPath = require2.resolve("typescript/lib/tsserver.js");
44
+ } catch {
45
+ resolve3(false);
46
+ return;
47
+ }
48
+ const child = spawn("node", [tsserverPath, "--disableAutomaticTypingAcquisition"], {
49
+ cwd: projectRoot,
50
+ stdio: ["pipe", "pipe", "pipe"]
51
+ });
52
+ const timeout = setTimeout(() => {
53
+ child.kill();
54
+ resolve3(false);
55
+ }, 1e4);
56
+ let buffer = "";
57
+ child.stdout.on("data", (chunk) => {
58
+ buffer += chunk.toString();
59
+ if (buffer.includes('"success":true')) {
60
+ clearTimeout(timeout);
61
+ child.kill();
62
+ resolve3(true);
63
+ }
64
+ });
65
+ child.on("error", () => {
66
+ clearTimeout(timeout);
67
+ resolve3(false);
68
+ });
69
+ child.on("exit", () => {
70
+ clearTimeout(timeout);
71
+ });
72
+ const request = JSON.stringify({
73
+ seq: 1,
74
+ type: "request",
75
+ command: "configure",
76
+ arguments: {
77
+ preferences: { disableSuggestions: true }
78
+ }
79
+ });
80
+ child.stdin.write(request + "\n");
81
+ });
82
+ }
83
+ async function main(configOverride) {
84
+ const { projectRoot, tsconfigPath, toolDir, toolIsEmbedded, toolRelPath } = configOverride ?? resolveConfig(import.meta.dirname);
85
+ let passed = 0;
86
+ let failed = 0;
87
+ let warned = 0;
88
+ function pass(msg) {
89
+ console.log(` \u2713 ${msg}`);
90
+ passed++;
91
+ }
92
+ function fail(msg, fix) {
93
+ console.log(` \u2717 ${msg}`);
94
+ console.log(` Fix: ${fix}`);
95
+ failed++;
96
+ }
97
+ function warn(msg, note) {
98
+ console.log(` ! ${msg}`);
99
+ console.log(` ${note}`);
100
+ warned++;
101
+ }
102
+ function skip(msg) {
103
+ console.log(` - ${msg} (skipped)`);
104
+ }
105
+ console.log("");
106
+ console.log("typegraph-mcp Health Check");
107
+ console.log("=======================");
108
+ console.log(`Project root: ${projectRoot}`);
109
+ console.log("");
110
+ const nodeVersion = process.version;
111
+ const nodeMajor = parseInt(nodeVersion.slice(1).split(".")[0], 10);
112
+ if (nodeMajor >= 18) {
113
+ pass(`Node.js ${nodeVersion} (>= 18 required)`);
114
+ } else {
115
+ fail(`Node.js ${nodeVersion} is too old`, "Upgrade Node.js to >= 18");
116
+ }
117
+ const tsxInRoot = fs.existsSync(path2.join(projectRoot, "node_modules/.bin/tsx"));
118
+ const tsxInTool = fs.existsSync(path2.join(toolDir, "node_modules/.bin/tsx"));
119
+ if (tsxInRoot || tsxInTool) {
120
+ pass(`tsx available (in ${tsxInRoot ? "project" : "tool"} node_modules)`);
121
+ } else {
122
+ pass("tsx available (via npx/global)");
123
+ }
124
+ let tsVersion = null;
125
+ try {
126
+ const require2 = createRequire(path2.resolve(projectRoot, "package.json"));
127
+ const tsserverPath = require2.resolve("typescript/lib/tsserver.js");
128
+ const tsPkgPath = path2.resolve(path2.dirname(tsserverPath), "..", "package.json");
129
+ const tsPkg = JSON.parse(fs.readFileSync(tsPkgPath, "utf-8"));
130
+ tsVersion = tsPkg.version;
131
+ pass(`TypeScript found (v${tsVersion})`);
132
+ } catch {
133
+ fail(
134
+ "TypeScript not found in project",
135
+ "Add `typescript` to devDependencies and run `npm install`"
136
+ );
137
+ }
138
+ const tsconfigAbs = path2.resolve(projectRoot, tsconfigPath);
139
+ if (fs.existsSync(tsconfigAbs)) {
140
+ pass(`tsconfig.json exists at ${tsconfigPath}`);
141
+ } else {
142
+ fail(`tsconfig.json not found at ${tsconfigPath}`, `Create a tsconfig.json at ${tsconfigPath}`);
143
+ }
144
+ const pluginMcpPath = path2.join(toolDir, ".mcp.json");
145
+ const hasPluginMcp = fs.existsSync(pluginMcpPath) && fs.existsSync(path2.join(toolDir, ".claude-plugin/plugin.json"));
146
+ if (process.env.CLAUDE_PLUGIN_ROOT) {
147
+ pass("MCP registered via plugin (CLAUDE_PLUGIN_ROOT set)");
148
+ } else if (hasPluginMcp) {
149
+ pass("MCP registered via plugin (.mcp.json + .claude-plugin/ present)");
150
+ } else {
151
+ const mcpJsonPath = path2.resolve(projectRoot, ".claude/mcp.json");
152
+ if (fs.existsSync(mcpJsonPath)) {
153
+ try {
154
+ const mcpJson = JSON.parse(fs.readFileSync(mcpJsonPath, "utf-8"));
155
+ const tsNav = mcpJson?.mcpServers?.["typegraph"];
156
+ if (tsNav) {
157
+ const hasCommand = tsNav.command === "npx";
158
+ const hasArgs = Array.isArray(tsNav.args) && tsNav.args.includes("tsx");
159
+ const hasEnv = tsNav.env?.["TYPEGRAPH_PROJECT_ROOT"] && tsNav.env?.["TYPEGRAPH_TSCONFIG"];
160
+ if (hasCommand && hasArgs && hasEnv) {
161
+ pass("MCP registered in .claude/mcp.json");
162
+ } else {
163
+ const issues = [];
164
+ if (!hasCommand) issues.push("command should be 'npx'");
165
+ if (!hasArgs) issues.push("args should include 'tsx'");
166
+ if (!hasEnv) issues.push("env should set TYPEGRAPH_PROJECT_ROOT and TYPEGRAPH_TSCONFIG");
167
+ fail(
168
+ `MCP registration incomplete: ${issues.join(", ")}`,
169
+ "See README for correct .claude/mcp.json format"
170
+ );
171
+ }
172
+ } else {
173
+ const serverPath = toolIsEmbedded ? `./${toolRelPath}/server.ts` : path2.resolve(toolDir, "server.ts");
174
+ fail(
175
+ "MCP entry 'typegraph' not found in .claude/mcp.json",
176
+ `Add to .claude/mcp.json:
177
+ {
178
+ "mcpServers": {
179
+ "typegraph": {
180
+ "command": "npx",
181
+ "args": ["tsx", "${serverPath}"],
182
+ "env": { "TYPEGRAPH_PROJECT_ROOT": ".", "TYPEGRAPH_TSCONFIG": "./tsconfig.json" }
183
+ }
184
+ }
185
+ }`
186
+ );
187
+ }
188
+ } catch (err) {
189
+ fail(
190
+ "Failed to parse .claude/mcp.json",
191
+ `Check JSON syntax: ${err instanceof Error ? err.message : String(err)}`
192
+ );
193
+ }
194
+ } else {
195
+ fail(".claude/mcp.json not found", `Create .claude/mcp.json with typegraph server registration`);
196
+ }
197
+ }
198
+ const toolNodeModules = path2.join(toolDir, "node_modules");
199
+ if (fs.existsSync(toolNodeModules)) {
200
+ const requiredPkgs = ["@modelcontextprotocol/sdk", "oxc-parser", "oxc-resolver", "zod"];
201
+ const missing = requiredPkgs.filter(
202
+ (pkg) => !fs.existsSync(path2.join(toolNodeModules, ...pkg.split("/")))
203
+ );
204
+ if (missing.length === 0) {
205
+ pass(`Dependencies installed (${requiredPkgs.length} packages)`);
206
+ } else {
207
+ fail(`Missing packages: ${missing.join(", ")}`, `Run \`cd ${toolRelPath} && npm install\``);
208
+ }
209
+ } else {
210
+ fail("typegraph-mcp dependencies not installed", `Run \`cd ${toolRelPath} && npm install\``);
211
+ }
212
+ try {
213
+ const oxcParserReq = createRequire(path2.join(toolDir, "package.json"));
214
+ const { parseSync } = await import(oxcParserReq.resolve("oxc-parser"));
215
+ const result = parseSync("test.ts", 'import { x } from "./y";');
216
+ if (result.module?.staticImports?.length === 1) {
217
+ pass("oxc-parser working");
218
+ } else {
219
+ fail(
220
+ "oxc-parser parseSync returned unexpected result",
221
+ `Reinstall: \`cd ${toolRelPath} && rm -rf node_modules && npm install\``
222
+ );
223
+ }
224
+ } catch (err) {
225
+ fail(
226
+ `oxc-parser failed: ${err instanceof Error ? err.message : String(err)}`,
227
+ `Reinstall: \`cd ${toolRelPath} && rm -rf node_modules && npm install\``
228
+ );
229
+ }
230
+ try {
231
+ const oxcResolverReq = createRequire(path2.join(toolDir, "package.json"));
232
+ const { ResolverFactory } = await import(oxcResolverReq.resolve("oxc-resolver"));
233
+ const resolver = new ResolverFactory({
234
+ tsconfig: { configFile: tsconfigAbs, references: "auto" },
235
+ extensions: [".ts", ".tsx", ".js"],
236
+ extensionAlias: { ".js": [".ts", ".tsx", ".js"] }
237
+ });
238
+ let resolveOk = false;
239
+ const testFile = findFirstTsFile(projectRoot);
240
+ if (testFile) {
241
+ const dir = path2.dirname(testFile);
242
+ const base = "./" + path2.basename(testFile);
243
+ const result = resolver.sync(dir, base);
244
+ resolveOk = !!result.path;
245
+ }
246
+ if (resolveOk) {
247
+ pass("oxc-resolver working");
248
+ } else {
249
+ warn(
250
+ "oxc-resolver loaded but couldn't resolve a test import",
251
+ "Check tsconfig.json is valid and has correct `references`"
252
+ );
253
+ }
254
+ } catch (err) {
255
+ fail(
256
+ `oxc-resolver failed: ${err instanceof Error ? err.message : String(err)}`,
257
+ `Reinstall: \`cd ${toolRelPath} && rm -rf node_modules && npm install\``
258
+ );
259
+ }
260
+ if (tsVersion) {
261
+ try {
262
+ const ok = await testTsserver(projectRoot);
263
+ if (ok) {
264
+ pass("tsserver responds to configure");
265
+ } else {
266
+ fail(
267
+ "tsserver did not respond",
268
+ "Verify `typescript` is installed and tsconfig.json is valid"
269
+ );
270
+ }
271
+ } catch (err) {
272
+ fail(
273
+ `tsserver failed to start: ${err instanceof Error ? err.message : String(err)}`,
274
+ "Verify `typescript` is installed and tsconfig.json is valid"
275
+ );
276
+ }
277
+ } else {
278
+ skip("tsserver test (TypeScript not found)");
279
+ }
280
+ try {
281
+ const { buildGraph } = await import(path2.resolve(toolDir, "module-graph.js"));
282
+ const start = performance.now();
283
+ const { graph } = await buildGraph(projectRoot, tsconfigPath);
284
+ const elapsed = (performance.now() - start).toFixed(0);
285
+ const edgeCount = [...graph.forward.values()].reduce(
286
+ (s, e) => s + e.length,
287
+ 0
288
+ );
289
+ if (graph.files.size > 0 && edgeCount > 0) {
290
+ pass(`Module graph: ${graph.files.size} files, ${edgeCount} edges [${elapsed}ms]`);
291
+ } else if (graph.files.size > 0) {
292
+ warn(
293
+ `Module graph: ${graph.files.size} files but 0 edges`,
294
+ "Files found but no internal imports resolved. Check tsconfig references."
295
+ );
296
+ } else {
297
+ fail(
298
+ "Module graph: 0 files discovered",
299
+ "Check tsconfig.json includes source files and project root is correct"
300
+ );
301
+ }
302
+ } catch (err) {
303
+ fail(
304
+ `Module graph build failed: ${err instanceof Error ? err.message : String(err)}`,
305
+ "Check that oxc-parser and oxc-resolver are installed correctly"
306
+ );
307
+ }
308
+ if (toolIsEmbedded) {
309
+ const eslintConfigPath = path2.resolve(projectRoot, "eslint.config.mjs");
310
+ if (fs.existsSync(eslintConfigPath)) {
311
+ const eslintContent = fs.readFileSync(eslintConfigPath, "utf-8");
312
+ const parentDir = path2.basename(path2.dirname(toolDir));
313
+ const parentIgnorePattern = new RegExp(`["']${parentDir}\\/\\*\\*["']`);
314
+ const hasParentIgnore = parentIgnorePattern.test(eslintContent);
315
+ if (hasParentIgnore) {
316
+ pass(`ESLint ignores ${parentDir}/`);
317
+ } else {
318
+ fail(
319
+ `ESLint missing ignore: "${parentDir}/**"`,
320
+ `Add to the ignores array in eslint.config.mjs:
321
+ "${parentDir}/**",`
322
+ );
323
+ }
324
+ } else {
325
+ skip("ESLint config check (no eslint.config.mjs)");
326
+ }
327
+ } else {
328
+ skip("ESLint config check (typegraph-mcp is external to project)");
329
+ }
330
+ const gitignorePath = path2.resolve(projectRoot, ".gitignore");
331
+ if (fs.existsSync(gitignorePath)) {
332
+ const gitignoreContent = fs.readFileSync(gitignorePath, "utf-8");
333
+ const lines = gitignoreContent.split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("#"));
334
+ const ignoresClaude = lines.some(
335
+ (l) => l === ".claude/" || l === ".claude" || l === "/.claude"
336
+ );
337
+ const parentDir = toolIsEmbedded ? path2.basename(path2.dirname(toolDir)) : null;
338
+ const ignoresParent = parentDir && lines.some((l) => l === `${parentDir}/` || l === parentDir || l === `/${parentDir}`);
339
+ if (!ignoresParent && !ignoresClaude) {
340
+ pass(".gitignore does not exclude .claude/" + (parentDir ? ` or ${parentDir}/` : ""));
341
+ } else {
342
+ const excluded = [];
343
+ if (ignoresParent) excluded.push(`${parentDir}/`);
344
+ if (ignoresClaude) excluded.push(".claude/");
345
+ warn(
346
+ `.gitignore excludes ${excluded.join(" and ")}`,
347
+ "Remove these entries so MCP config and tool source are tracked in git"
348
+ );
349
+ }
350
+ } else {
351
+ skip(".gitignore check (no .gitignore)");
352
+ }
353
+ console.log("");
354
+ const total = passed + failed;
355
+ if (failed === 0) {
356
+ console.log(
357
+ `${passed}/${total} checks passed` + (warned > 0 ? ` (${warned} warning${warned > 1 ? "s" : ""})` : "") + " -- typegraph-mcp is ready"
358
+ );
359
+ } else {
360
+ console.log(
361
+ `${passed}/${total} checks passed, ${failed} failed` + (warned > 0 ? `, ${warned} warning${warned > 1 ? "s" : ""}` : "") + " -- fix issues above"
362
+ );
363
+ }
364
+ console.log("");
365
+ return { passed, failed, warned };
366
+ }
367
+ var isDirectRun = process.argv[1] && fs.realpathSync(process.argv[1]) === fs.realpathSync(new URL(import.meta.url).pathname);
368
+ if (isDirectRun) {
369
+ main().then((result) => process.exit(result.failed > 0 ? 1 : 0)).catch((err) => {
370
+ console.error("Fatal error:", err);
371
+ process.exit(1);
372
+ });
373
+ }
374
+ export {
375
+ main
376
+ };