Release notes

What changed

Every published version, newest first. Upgrade notes are at the end of a release when there is something you need to do.

2026-09-13
Latest

Checks

  • Dependencies in package.json are checked, even when nothing imports them. npm install fetches every declared dependency, so a name there that npm has never heard of is as squattable as one in an import. workspace:, file:, link:, git and URL specs are skipped, and npm: aliases are checked under the real package name.
  • Scoped names are only called squattable when the scope is free. Only a scope's owner can publish under it, so @babel/made-up is a broken import but not a target. ghostimport now asks the registry whether the scope has an owner — one request per scope, cached for 24 hours.

Agent hook

  • Edits to package.json are checked. When an agent writes a dependency that doesn't exist, the PostToolUse hook blocks it and tells the agent to fix the entry. Only the entries the edit wrote are checked, so bumping one version doesn't re-verify the whole file.

Output

  • Entries in missing carry claimable: boolean | null — false inside an owned scope, null when the scope couldn't be checked. Verdicts from verifyPackages() carry the same field. New exported type: MissingRef.
  • For a name in an owned scope, the CLI prints scope is owned — only its owner can publish this name instead of the squatting warning. The MCP scan_project tool marks those names the same way.

Upgrading

  • No breaking API changes.
  • CI may report new problems. A dependency that only exists on a private registry, and is declared in package.json without being imported, is now checked against public npm. Add it to ignore in .ghostimportrc.json.
  • The first scan of a project with many dependencies makes more registry requests than before. Later runs are served from the cache.
2026-08-30

False-positive fixes, found by running the scanner against 174 public repositories. Popular repositories reporting a problem fell from 19.1% to 12.8%, AI-assisted ones from 11.8% to 5.5%. The field report has the details.

Fixes

  • Nested package.json and tsconfig.json files are read, so workspace packages in a monorepo are no longer reported as missing.
  • Scoped path aliases match their subpaths: the alias @commands/* now answers the import @commands/types.
  • The JSONC parser no longer strips https:// inside strings, which had broken every Deno import map it read.
  • Docusaurus @theme/* and @site/*, and Deno @std/* and @deno/*, are recognised as framework scopes rather than npm names.
  • Build output such as .next, .vercel and .svelte-kit is no longer scanned.
  • Specifiers ending in a non-JavaScript extension, like shared.dart, are no longer read as package names.
2026-08-29

Maintenance release. No changes to the package code.

  • CI moved to actions/checkout and actions/setup-node v5.
  • Development setup moved from the README into CONTRIBUTING.md.
2026-08-29
Breaking

New

  • MCP server. ghostimport mcp lets an AI agent verify packages before it imports or installs them, through three tools: check_packages, check_install_command and scan_project. Still no runtime dependencies.
  • Agent hook. ghostimport hook blocks install commands that would fetch a package that doesn't exist, looks like a typosquat or ships an install script, and flags imports of missing packages right after an edit. It fails open: a network error never blocks the agent.
  • Install commands for npm, pnpm, yarn and bun are parsed, so the hook knows what they would fetch.

Changed

  • The unregistered-name and typosquat checks run by default. --scary is still accepted, so existing scripts keep working. The new --fast skips the deeper registry checks.
  • First release published from CI with an npm provenance attestation.

Breaking: library API

Public exports went from 11 to 7. Added: verifyPackages and extractInstallTargets. Removed from the public API: extractSfcScripts, loadCache, saveCache, loadConfig, walkFiles, readPackageJsonDeps and the CacheEntry type. Renamed:

v0.4.0v0.5.0
checkScary()checkPackageRisk()
ScaryEntryRiskEntry
ScaryCheckResultPackageRiskResult
ScanResult.hallucinatedScanResult.missing
ScanResult.notInPackageJsonScanResult.undeclared
ScanResult.scaryScanResult.risks
ScanOptions.scaryScanOptions.deep (defaults to true)
status 'hallucinated'status 'missing'
RiskEntry.type: 'available'RiskEntry.type: 'unregistered'

The CLI's JSON output follows the same field renames.

2026-07-11
  • Vue, Svelte and Astro. Imports in .vue, .svelte and .astro files are scanned. Only <script> blocks and Astro frontmatter are read, so a package name in markup is never flagged.
  • New logo.
2026-07-01
  • Typosquat detection. Names one or two characters away from a popular package are flagged.
  • checkScary() and detectTyposquat() are available from the library.
2026-06-29
  • --badge prints a README badge with the result of the scan.
2026-06-29

First public release: a CLI that finds imports of npm packages that don't exist, with --json, --watch, --quiet, a 24-hour registry cache, and --scary for the squatting checks.