feat: integrate Changesets for multi-package npm publishing

Migrate from single-bundle CLI publishing to publishing all @paperclipai/*
packages individually via Changesets. This fixes the "Cannot find package
@paperclipai/server" error when installing from npm.

Changes:
- Add @changesets/cli with fixed versioning (all packages share version)
- Make 7 packages publishable (shared, adapter-utils, db, 3 adapters, server)
- Add build scripts, publishConfig, and files fields to all packages
- Mark @paperclipai/server as external in CLI esbuild config
- Simplify CLI importServerEntry() to use string-literal dynamic import
- Add generate-npm-package-json support for external workspace packages
- Create scripts/release.sh for one-command releases
- Remove old bump-and-publish.sh and version-bump.sh
- All packages start at version 0.2.0

Usage: ./scripts/release.sh patch|minor|major [--dry-run]

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Dotta
2026-03-03 14:46:16 -06:00
parent 6e7f948314
commit defccdd4d9
20 changed files with 1197 additions and 256 deletions

View File

@@ -23,10 +23,10 @@ function readPkg(relativePath) {
return JSON.parse(readFileSync(resolve(repoRoot, relativePath, "package.json"), "utf8"));
}
// Read all workspace packages that the CLI depends on
// Read all workspace packages that are BUNDLED into the CLI.
// Note: "server" is excluded — it's published separately as a dependency.
const workspacePaths = [
"cli",
"server",
"packages/db",
"packages/shared",
"packages/adapter-utils",
@@ -35,6 +35,12 @@ const workspacePaths = [
"packages/adapters/openclaw",
];
// Workspace packages that are NOT bundled and must stay as npm dependencies.
// These get published separately via Changesets and resolved at runtime.
const externalWorkspacePackages = new Set([
"@paperclipai/server",
]);
// Collect all external dependencies from all workspace packages
const allDeps = {};
const allOptionalDeps = {};
@@ -45,7 +51,14 @@ for (const pkgPath of workspacePaths) {
const optDeps = pkg.optionalDependencies || {};
for (const [name, version] of Object.entries(deps)) {
if (name.startsWith("@paperclipai/")) continue; // skip workspace refs
if (name.startsWith("@paperclipai/") && !externalWorkspacePackages.has(name)) continue;
// For external workspace packages, read their version directly
if (externalWorkspacePackages.has(name)) {
const pkgDirMap = { "@paperclipai/server": "server" };
const wsPkg = readPkg(pkgDirMap[name]);
allDeps[name] = `^${wsPkg.version}`;
continue;
}
// Keep the more specific (pinned) version if conflict
if (!allDeps[name] || !version.startsWith("^")) {
allDeps[name] = version;