feat: add npm build process, version bump, and forbidden token enforcement
- Add esbuild config to bundle CLI with all workspace code for npm publishing - Add build-npm.sh script that runs forbidden token check, type-check, esbuild bundle, and generates publishable package.json - Add generate-npm-package-json.mjs to resolve workspace:* refs to actual npm dependencies for publishing - Add version-bump.sh for patch/minor/major/explicit version bumping - Add check-forbidden-tokens.mjs that scans codebase for forbidden tokens (mirrors git hook logic, safe if token list is missing) - Add esbuild as dev dependency - Add build:npm, version:bump, check:tokens scripts to root package.json - Update .gitignore for build artifacts Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
97
scripts/generate-npm-package-json.mjs
Normal file
97
scripts/generate-npm-package-json.mjs
Normal file
@@ -0,0 +1,97 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* generate-npm-package-json.mjs
|
||||
*
|
||||
* Reads the dev package.json (which has workspace:* refs) and produces
|
||||
* a publishable package.json in cli/ with:
|
||||
* - workspace:* dependencies removed
|
||||
* - all external dependencies from workspace packages inlined
|
||||
* - proper metadata for npm
|
||||
*
|
||||
* Reads from cli/package.dev.json if it exists (build already ran),
|
||||
* otherwise from cli/package.json.
|
||||
*/
|
||||
|
||||
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
||||
import { resolve, dirname } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const repoRoot = resolve(__dirname, "..");
|
||||
|
||||
function readPkg(relativePath) {
|
||||
return JSON.parse(readFileSync(resolve(repoRoot, relativePath, "package.json"), "utf8"));
|
||||
}
|
||||
|
||||
// Read all workspace packages that the CLI depends on
|
||||
const workspacePaths = [
|
||||
"cli",
|
||||
"server",
|
||||
"packages/db",
|
||||
"packages/shared",
|
||||
"packages/adapter-utils",
|
||||
"packages/adapters/claude-local",
|
||||
"packages/adapters/codex-local",
|
||||
"packages/adapters/openclaw",
|
||||
];
|
||||
|
||||
// Collect all external dependencies from all workspace packages
|
||||
const allDeps = {};
|
||||
const allOptionalDeps = {};
|
||||
|
||||
for (const pkgPath of workspacePaths) {
|
||||
const pkg = readPkg(pkgPath);
|
||||
const deps = pkg.dependencies || {};
|
||||
const optDeps = pkg.optionalDependencies || {};
|
||||
|
||||
for (const [name, version] of Object.entries(deps)) {
|
||||
if (name.startsWith("@paperclipai/")) continue; // skip workspace refs
|
||||
// Keep the more specific (pinned) version if conflict
|
||||
if (!allDeps[name] || !version.startsWith("^")) {
|
||||
allDeps[name] = version;
|
||||
}
|
||||
}
|
||||
|
||||
for (const [name, version] of Object.entries(optDeps)) {
|
||||
allOptionalDeps[name] = version;
|
||||
}
|
||||
}
|
||||
|
||||
// Sort alphabetically
|
||||
const sortedDeps = Object.fromEntries(Object.entries(allDeps).sort(([a], [b]) => a.localeCompare(b)));
|
||||
const sortedOptDeps = Object.fromEntries(
|
||||
Object.entries(allOptionalDeps).sort(([a], [b]) => a.localeCompare(b)),
|
||||
);
|
||||
|
||||
// Read the CLI package metadata — prefer the dev backup if it exists
|
||||
const devPkgPath = resolve(repoRoot, "cli/package.dev.json");
|
||||
const cliPkg = existsSync(devPkgPath)
|
||||
? JSON.parse(readFileSync(devPkgPath, "utf8"))
|
||||
: readPkg("cli");
|
||||
|
||||
// Build the publishable package.json
|
||||
const publishPkg = {
|
||||
name: cliPkg.name,
|
||||
version: cliPkg.version,
|
||||
description: cliPkg.description,
|
||||
type: cliPkg.type,
|
||||
bin: cliPkg.bin,
|
||||
keywords: cliPkg.keywords,
|
||||
license: cliPkg.license,
|
||||
repository: cliPkg.repository,
|
||||
homepage: cliPkg.homepage,
|
||||
files: cliPkg.files,
|
||||
engines: { node: ">=20" },
|
||||
dependencies: sortedDeps,
|
||||
};
|
||||
|
||||
if (Object.keys(sortedOptDeps).length > 0) {
|
||||
publishPkg.optionalDependencies = sortedOptDeps;
|
||||
}
|
||||
|
||||
const output = JSON.stringify(publishPkg, null, 2) + "\n";
|
||||
const outPath = resolve(repoRoot, "cli/package.json");
|
||||
writeFileSync(outPath, output);
|
||||
|
||||
console.log(` ✓ Generated publishable package.json (${Object.keys(sortedDeps).length} deps)`);
|
||||
console.log(` Version: ${cliPkg.version}`);
|
||||
Reference in New Issue
Block a user