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

@@ -93,41 +93,23 @@ function maybeEnableUiDevMiddleware(entrypoint: string): void {
}
async function importServerEntry(): Promise<void> {
// Dev mode: try local workspace path (monorepo with tsx)
const projectRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../../..");
const fileCandidates = [
path.resolve(projectRoot, "server/src/index.ts"),
path.resolve(projectRoot, "server/dist/index.js"),
];
const existingFileCandidates = fileCandidates.filter((filePath) => fs.existsSync(filePath));
if (existingFileCandidates.length > 0) {
for (const filePath of existingFileCandidates) {
try {
maybeEnableUiDevMiddleware(filePath);
await import(pathToFileURL(filePath).href);
return;
} catch (err) {
throw new Error(`Failed to start Paperclip server from ${filePath}: ${formatError(err)}`);
}
}
const devEntry = path.resolve(projectRoot, "server/src/index.ts");
if (fs.existsSync(devEntry)) {
maybeEnableUiDevMiddleware(devEntry);
await import(pathToFileURL(devEntry).href);
return;
}
const specifierCandidates: string[] = ["@paperclipai/server/dist/index.js", "@paperclipai/server/src/index.ts"];
const missingErrors: string[] = [];
for (const specifier of specifierCandidates) {
try {
maybeEnableUiDevMiddleware(specifier);
await import(specifier);
return;
} catch (err) {
if (isModuleNotFoundError(err)) {
missingErrors.push(`${specifier}: ${formatError(err)}`);
continue;
}
throw new Error(`Failed to start Paperclip server from ${specifier}: ${formatError(err)}`);
}
// Production mode: import the published @paperclipai/server package
try {
await import("@paperclipai/server");
} catch (err) {
throw new Error(
`Could not locate a Paperclip server entrypoint.\n` +
`Tried: ${devEntry}, @paperclipai/server\n` +
`${formatError(err)}`,
);
}
throw new Error(
`Could not locate a Paperclip server entrypoint. Tried: ${[...fileCandidates, ...specifierCandidates].join(", ")}\n${missingErrors.join("\n")}`,
);
}