+16
-2
@@ -156,5 +156,19 @@ // tashan doctor — audit the agent config you actually have. | ||
| const id = item.id || item.name || ""; | ||
| const bare = String(id).replace(/^@[^/]+\//, ""); | ||
| // NEVER STRIP A SCOPE DOWN TO A GENERIC LEAF. `@playwright/mcp` — Microsoft's official server — | ||
| // stripped to `mcp` and matched `@rendobar/mcp`, a different package that IS deleted from the | ||
| // registry. Every user with Playwright configured was told their install had been REMOVED for | ||
| // spam, malware or illegal content: the most serious claim this tool can make, about the wrong | ||
| // package, on the strength of a shared last path segment. Same defect as the slug collision that | ||
| // sent @stripe/mcp to a third-party stripe-mcp's page — a scoped name's identity is the WHOLE | ||
| // name, and its leaf is frequently a word like `mcp`, `server` or `cli` that dozens share. | ||
| // | ||
| // The fallback still exists, because a package genuinely is configured both ways — but only when | ||
| // the leaf is distinctive enough to be an identity on its own. | ||
| const GENERIC = new Set(["mcp", "server", "cli", "core", "client", "sdk", "api", "app", "tools", | ||
| "mcp-server", "server-mcp", "index", "main", "lib"]); | ||
| const leafOk = bare !== id && bare.length >= 4 && !GENERIC.has(bare.toLowerCase()); | ||
| return rec(id) | ||
| // a scoped package may be configured bare, and vice versa | ||
| || rec(String(id).replace(/^@[^/]+\//, "")) | ||
| // a scoped package may be configured bare, and vice versa — but see GENERIC above | ||
| || (leafOk ? rec(bare) : null) | ||
| // docker images and remote hosts arrive without the `kind:` prefix the id carries | ||
@@ -161,0 +175,0 @@ || rec(`${item.kind}:${id}`) |
+1
-1
| { | ||
| "name": "tashan-cli", | ||
| "version": "0.1.3", | ||
| "version": "0.1.4", | ||
| "mcpName": "sh.tashan/tashan", | ||
@@ -5,0 +5,0 @@ "description": "The measured layer for AI capabilities — search, rank, and install MCP servers & agent skills from your terminal.", |
+15
-0
@@ -25,2 +25,11 @@ #!/usr/bin/env node | ||
| // Resolved against this module's own URL, not cwd and not argv[1] — npm installs the bin as a | ||
| // SYMLINK, so a path derived from how the process was invoked points somewhere else entirely. | ||
| // See [[npm-bin-is-a-symlink]]. Falls back rather than throwing: a missing package.json must not | ||
| // take down every command in the CLI just because one of them wanted to print a number. | ||
| const VERSION = (() => { | ||
| try { return JSON.parse(readFileSync(new URL("./package.json", import.meta.url), "utf8")).version; } | ||
| catch { return "unknown"; } | ||
| })(); | ||
| // ---- licence --------------------------------------------------------------------------------- | ||
@@ -594,2 +603,8 @@ // Billing is Polar's; the account centre is ours. The customer-portal license-key endpoints | ||
| if (!cmd || cmd === "help" || cmd === "--help" || cmd === "-h") { process.stdout.write(USAGE + "\n"); return 0; } | ||
| // `--version` answered "unknown command" in every form up to 0.1.4. It is the first thing anyone | ||
| // types at a new CLI and the first thing a bug report asks for, and getting an error for it reads | ||
| // as a broken install. Read from package.json so it can never drift from what npm published. | ||
| if (cmd === "--version" || cmd === "-v" || cmd === "version") { | ||
| process.stdout.write(VERSION + "\n"); return 0; | ||
| } | ||
@@ -596,0 +611,0 @@ // Only the commands that read the Index download it. `activate`, `account` and `mcp` do not touch |
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
95314
2.31%1544
1.85%16
6.67%