feat(KB-131): bundle workspace dependencies into CLI for npm publish
- Replace tsc with tsup (esbuild) to inline @kb/* workspace code into a single dist/bin.js - Move @kb/core, @kb/dashboard, @kb/engine from dependencies to devDependencies - Add tsup.config.ts that copies dashboard client assets into dist/client/ - Add bundle output tests verifying shebang, inlined code, and no bare @kb/* imports - Add changeset for the bundled CLI build fix
This commit is contained in:
@@ -11,19 +11,23 @@
|
||||
],
|
||||
"scripts": {
|
||||
"dev": "tsx src/bin.ts",
|
||||
"build": "tsc",
|
||||
"build": "tsup",
|
||||
"build:exe": "bun run build.ts",
|
||||
"build:exe:all": "bun run build.ts --all",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"test": "vitest run"
|
||||
},
|
||||
"dependencies": {
|
||||
"@mariozechner/pi-ai": "^0.62.0",
|
||||
"@mariozechner/pi-coding-agent": "^0.62.0",
|
||||
"express": "^5.1.0",
|
||||
"multer": "^2.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@kb/core": "workspace:*",
|
||||
"@kb/dashboard": "workspace:*",
|
||||
"@kb/engine": "workspace:*",
|
||||
"@mariozechner/pi-coding-agent": "^0.62.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"tsup": "^8.5.1",
|
||||
"tsx": "^4.19.0",
|
||||
"typescript": "^5.7.0",
|
||||
"vitest": "^3.1.0",
|
||||
|
||||
37
packages/cli/src/__tests__/bundle-output.test.ts
Normal file
37
packages/cli/src/__tests__/bundle-output.test.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { readFileSync, existsSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
|
||||
const cliRoot = join(__dirname, "..", "..");
|
||||
const bundlePath = join(cliRoot, "dist", "bin.js");
|
||||
|
||||
describe("CLI bundle output", () => {
|
||||
it("dist/bin.js exists", () => {
|
||||
expect(existsSync(bundlePath)).toBe(true);
|
||||
});
|
||||
|
||||
it("starts with a shebang", () => {
|
||||
const content = readFileSync(bundlePath, "utf-8");
|
||||
expect(content.startsWith("#!/usr/bin/env node")).toBe(true);
|
||||
});
|
||||
|
||||
it("does not contain bare @kb/* import specifiers", () => {
|
||||
const content = readFileSync(bundlePath, "utf-8");
|
||||
expect(content).not.toMatch(/from\s+["']@kb\/core["']/);
|
||||
expect(content).not.toMatch(/from\s+["']@kb\/dashboard["']/);
|
||||
expect(content).not.toMatch(/from\s+["']@kb\/engine["']/);
|
||||
});
|
||||
|
||||
it("contains inlined workspace code", () => {
|
||||
const content = readFileSync(bundlePath, "utf-8");
|
||||
// TaskStore from @kb/core
|
||||
expect(content).toContain("TaskStore");
|
||||
// createServer from @kb/dashboard
|
||||
expect(content).toContain("createServer");
|
||||
});
|
||||
|
||||
it("dashboard client assets are included", () => {
|
||||
const clientIndex = join(cliRoot, "dist", "client", "index.html");
|
||||
expect(existsSync(clientIndex)).toBe(true);
|
||||
});
|
||||
});
|
||||
@@ -33,6 +33,12 @@ describe("CLI package.json publishing config", () => {
|
||||
it("is not private", () => {
|
||||
expect(pkg.private).not.toBe(true);
|
||||
});
|
||||
|
||||
it("does not have @kb/* workspace packages in dependencies", () => {
|
||||
const deps = Object.keys(pkg.dependencies || {});
|
||||
const kbDeps = deps.filter((d) => d.startsWith("@kb/"));
|
||||
expect(kbDeps).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Scoped @kb/* packages publishing config", () => {
|
||||
|
||||
26
packages/cli/tsup.config.ts
Normal file
26
packages/cli/tsup.config.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { defineConfig } from "tsup";
|
||||
import { cpSync, existsSync } from "node:fs";
|
||||
import { dirname, join } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const dashboardClientSrc = join(__dirname, "..", "dashboard", "dist", "client");
|
||||
const dashboardClientDest = join(__dirname, "dist", "client");
|
||||
|
||||
export default defineConfig({
|
||||
entry: ["src/bin.ts"],
|
||||
format: ["esm"],
|
||||
platform: "node",
|
||||
target: "node22",
|
||||
noExternal: [/^@kb\//],
|
||||
splitting: false,
|
||||
clean: true,
|
||||
onSuccess: async () => {
|
||||
if (existsSync(dashboardClientSrc)) {
|
||||
cpSync(dashboardClientSrc, dashboardClientDest, { recursive: true });
|
||||
console.log("Copied dashboard client assets to dist/client/");
|
||||
} else {
|
||||
console.warn("WARNING: Dashboard client assets not found at", dashboardClientSrc);
|
||||
}
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user