From 30a017162a5aa1815f9e96462dee373e7f600968 Mon Sep 17 00:00:00 2001 From: Vapi Tasker Date: Fri, 30 Jan 2026 19:39:34 +0000 Subject: [PATCH] fix: enable npm publishing by setting private to false - Change private: true to private: false in package.json to allow npm publish - Fix ESM import for figlet (was using require() which fails in ESM mode) - Add package structure tests to prevent regression Fixes: ERR_MODULE_NOT_FOUND: Cannot find module 'dist/cli/index.js' Linear: VAP-11522 Co-Authored-By: Claude --- package.json | 2 +- src/package.test.ts | 68 +++++++++++++++++++++++++++++++++++++++++++++ src/ui/banners.ts | 3 +- 3 files changed, 70 insertions(+), 3 deletions(-) create mode 100644 src/package.test.ts diff --git a/package.json b/package.json index ad5802d..0e82f13 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@vapi/bulletproof", "version": "1.0.0", - "private": true, + "private": false, "description": "Pre-push guardian that uses Claude to run checks and auto-fix issues", "keywords": [ "pre-push", diff --git a/src/package.test.ts b/src/package.test.ts new file mode 100644 index 0000000..98718be --- /dev/null +++ b/src/package.test.ts @@ -0,0 +1,68 @@ +/** + * Package structure tests + * + * These tests verify that the npm package is correctly configured + * for publishing and that the CLI can be imported properly. + */ + +import { describe, it, expect } from 'vitest' +import { readFileSync, existsSync } from 'fs' +import { resolve, dirname } from 'path' +import { fileURLToPath } from 'url' + +const __dirname = dirname(fileURLToPath(import.meta.url)) +const projectRoot = resolve(__dirname, '..') + +describe('package.json configuration', () => { + const packageJson = JSON.parse( + readFileSync(resolve(projectRoot, 'package.json'), 'utf-8') + ) + + it('should not be marked as private (allows npm publish)', () => { + // BUG FIX: private: true prevents npm from publishing the package + // Users were getting ERR_MODULE_NOT_FOUND because the package couldn't be published + expect(packageJson.private).toBe(false) + }) + + it('should include dist in files array', () => { + expect(packageJson.files).toContain('dist') + }) + + it('should include bin in files array', () => { + expect(packageJson.files).toContain('bin') + }) + + it('should have prepublishOnly script that runs build', () => { + expect(packageJson.scripts.prepublishOnly).toBe('npm run build') + }) + + it('should have bin pointing to correct location', () => { + expect(packageJson.bin.bulletproof).toBe('./bin/bulletproof.js') + }) +}) + +describe('bin entry point', () => { + it('bin/bulletproof.js should exist', () => { + const binPath = resolve(projectRoot, 'bin/bulletproof.js') + expect(existsSync(binPath)).toBe(true) + }) + + it('bin/bulletproof.js should import from dist/cli/index.js', () => { + const binPath = resolve(projectRoot, 'bin/bulletproof.js') + const content = readFileSync(binPath, 'utf-8') + expect(content).toContain('../dist/cli/index.js') + }) +}) + +describe('build output', () => { + it('dist/cli/index.js should exist after build', () => { + // This test verifies the fix for: ERR_MODULE_NOT_FOUND: Cannot find module 'dist/cli/index.js' + const distCliPath = resolve(projectRoot, 'dist/cli/index.js') + expect(existsSync(distCliPath)).toBe(true) + }) + + it('dist/index.js should exist after build', () => { + const distIndexPath = resolve(projectRoot, 'dist/index.js') + expect(existsSync(distIndexPath)).toBe(true) + }) +}) diff --git a/src/ui/banners.ts b/src/ui/banners.ts index 84a9054..295c6ab 100644 --- a/src/ui/banners.ts +++ b/src/ui/banners.ts @@ -2,8 +2,7 @@ * BULLETPROOF - ASCII art banners and terminal UI */ -// eslint-disable-next-line @typescript-eslint/no-require-imports -const figlet = require('figlet') +import figlet from 'figlet' import chalkAnimation from 'chalk-animation' import { colors, gradients } from './colors.js'