Files
PaperClipAI/server/package.json
T
Nicky LeachandClaude Sonnet 5 d9d32b1f4a build(docker): prune devDependencies from the production and cloud images
The production stage copied the entire build stage `/app` wholesale,
including every workspace member's devDependencies (typescript, vite,
vitest, storybook, rolldown, ...) and unrelated workspace members' own
dependencies (ui's client-side bundle deps like mermaid, lucide-react),
none of which the running server touches. That alone accounted for
~1.5GB of the shipped image.

Add a `pruned-app` stage, forked from `build` after all builds finish,
that re-resolves node_modules with `pnpm install --prod --frozen-lockfile
--filter='@paperclipai/server...'` -- server plus everything it actually
depends on, transitively, production-only. `production` now copies from
`pruned-app` instead of `build`.

The prune has to live in its own stage rather than in `build` directly:
`cloud-plugins` and `cloud-server-deps` (declared later in the file) both
fork from `build` and still need its full devDependency toolchain
(typescript, etc.) to compile their own TypeScript at image build time.

Move `tsx` from server's devDependencies to dependencies. It looked like
a dev tool, but the image's own ENTRYPOINT imports it directly
(`--import ./server/node_modules/tsx/...`) to transpile the workspace
packages the server consumes by TypeScript source (their `exports` field
points at `./src/*.ts`, not a prebuilt `dist`) -- it's genuinely required
at runtime, and a naive prod-prune would have deleted it and broken every
boot.

Verified locally: the `cloud` target drops from 7.5GB to 5.53GB and the
`production` target lands at 5.26GB. Boot-tested the built `cloud` image:
embedded Postgres initializes, all migrations apply, `/api/health`
returns 200, the UI serves, `@sentry/node` resolves to the version
`server/package.json` declares, and tini/orphan-reaping passes.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RD53WaVFqm8pbntKZ5seWy
2026-09-05 09:05:42 -07:00

148 lines
4.8 KiB
JSON

{
"name": "@paperclipai/server",
"version": "0.3.1",
"license": "MIT",
"homepage": "https://github.com/paperclipai/paperclip",
"bugs": {
"url": "https://github.com/paperclipai/paperclip/issues"
},
"repository": {
"type": "git",
"url": "https://github.com/paperclipai/paperclip",
"directory": "server"
},
"type": "module",
"exports": {
".": "./src/index.ts"
},
"publishConfig": {
"access": "public",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js"
}
},
"main": "./dist/index.js",
"types": "./dist/index.d.ts"
},
"files": [
"dist",
"ui-dist",
"skills"
],
"scripts": {
"dev": "tsx src/index.ts",
"dev:watch": "cross-env PAPERCLIP_MIGRATION_PROMPT=never PAPERCLIP_MIGRATION_AUTO_APPLY=true tsx ./scripts/dev-watch.ts",
"prepare:ui-dist": "bash ../scripts/prepare-server-ui-dist.sh",
"build": "pnpm run prepare:runner-vendor && tsc && mkdir -p dist/onboarding-assets dist/built-ins dist/services/scripts dist/vendor/paperclip-runner && cp -R src/onboarding-assets/. dist/onboarding-assets/ && cp -R src/built-ins/. dist/built-ins/ && cp -R src/services/scripts/. dist/services/scripts/ && cp -R ../packages/paperclip-runner/dist/. dist/vendor/paperclip-runner/ && node scripts/write-build-stamp.mjs",
"prepack": "pnpm run prepare:ui-dist && pnpm run build",
"postpack": "rm -rf ui-dist",
"clean": "rm -rf dist",
"start": "node dist/index.js",
"prepare:runner-vendor": "pnpm --filter @paperclipai/paperclip-runner build",
"typecheck": "pnpm run prepare:runner-vendor && pnpm --filter @paperclipai/plugin-sdk ensure-build-deps && tsc --noEmit"
},
"dependencies": {
"@aws-sdk/client-s3": "^3.1122.0",
"@opentelemetry/api": "^1.9.0",
"@paperclipai/adapter-claude-local": "workspace:*",
"@paperclipai/adapter-codex-local": "workspace:*",
"@paperclipai/adapter-cursor-cloud": "workspace:*",
"@paperclipai/adapter-cursor-local": "workspace:*",
"@paperclipai/adapter-gemini-local": "workspace:*",
"@paperclipai/adapter-grok-local": "workspace:*",
"@paperclipai/adapter-kimi-local": "workspace:*",
"@paperclipai/adapter-openclaw-gateway": "workspace:*",
"@paperclipai/adapter-opencode-local": "workspace:*",
"@paperclipai/adapter-pi-local": "workspace:*",
"@paperclipai/adapter-utils": "workspace:*",
"@paperclipai/db": "workspace:*",
"@paperclipai/hermes-paperclip-adapter": "workspace:*",
"@paperclipai/plugin-sdk": "workspace:*",
"@paperclipai/shared": "workspace:*",
"@paperclipai/skills-catalog": "workspace:*",
"@vercel/connect": "0.6.1",
"acpx": "0.13.1",
"ajv": "^8.20.0",
"ajv-formats": "^3.0.1",
"better-auth": "1.7.2",
"chokidar": "^5.0.0",
"detect-port": "^2.1.0",
"dompurify": "^3.4.14",
"dotenv": "^17.4.2",
"drizzle-orm": "^0.45.2",
"embedded-postgres": "^18.1.0-beta.16",
"express": "^5.1.0",
"jsdom": "^30.0.1",
"multer": "^2.2.0",
"open": "^11.0.1",
"pino": "^10.0.0",
"pino-http": "^11.0.0",
"pino-pretty": "^13.1.3",
"sharp": "^0.35.4",
"ssh2": "^1.17.0",
"tsx": "^4.23.12",
"ws": "^8.21.3",
"zod": "^4.4.3"
},
"bundleDependencies": [
"acpx"
],
"devDependencies": {
"@paperclipai/paperclip-runner": "workspace:*",
"@types/express": "^5.0.0",
"@types/express-serve-static-core": "^5.1.3",
"@types/jsdom": "^30.0.0",
"@types/multer": "^2.2.0",
"@types/node": "^24.0.0",
"@types/sharp": "^0.32.0",
"@types/supertest": "^7.2.1",
"@types/ws": "^8.18.1",
"cross-env": "^10.1.0",
"supertest": "^7.0.0",
"typescript": "^7.0.2",
"vite": "^8.2.2",
"vitest": "^4.1.11"
},
"peerDependencies": {
"@opentelemetry/auto-instrumentations-node": "0.79.0",
"@opentelemetry/exporter-trace-otlp-grpc": "0.221.0",
"@opentelemetry/exporter-trace-otlp-http": "0.221.0",
"@opentelemetry/exporter-trace-otlp-proto": "0.221.0",
"@opentelemetry/resources": "2.10.0",
"@opentelemetry/sdk-node": "0.221.0",
"@opentelemetry/semantic-conventions": "1.43.0",
"@sentry/node": "10.71.0"
},
"peerDependenciesMeta": {
"@opentelemetry/auto-instrumentations-node": {
"optional": true
},
"@opentelemetry/exporter-trace-otlp-grpc": {
"optional": true
},
"@opentelemetry/exporter-trace-otlp-http": {
"optional": true
},
"@opentelemetry/exporter-trace-otlp-proto": {
"optional": true
},
"@opentelemetry/resources": {
"optional": true
},
"@opentelemetry/sdk-node": {
"optional": true
},
"@opentelemetry/semantic-conventions": {
"optional": true
},
"@sentry/node": {
"optional": true
}
},
"engines": {
"node": ">=24.11.0"
}
}