diff --git a/package-lock.json b/package-lock.json index 1e5b965..a8690b8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "codebase-cli", - "version": "2.0.0-pre.75", + "version": "2.0.0-pre.76", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "codebase-cli", - "version": "2.0.0-pre.75", + "version": "2.0.0-pre.76", "license": "MIT", "dependencies": { "@earendil-works/pi-agent-core": "0.74.0", diff --git a/package.json b/package.json index 8bb990f..ac74083 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "codebase-cli", - "version": "2.0.0-pre.75", + "version": "2.0.0-pre.76", "description": "Codebase CLI — a TypeScript coding agent on the pi-mono runtime. OAuth-aware, any LLM provider, single install.", "keywords": [ "ai", diff --git a/src/projects/cli.test.ts b/src/projects/cli.test.ts index 5389fac..3606c8e 100644 --- a/src/projects/cli.test.ts +++ b/src/projects/cli.test.ts @@ -237,6 +237,24 @@ describe("runProjectSubcommand", () => { expect(result.stdout.join("\n")).toContain("preview: https://codebase.design/preview/proj-1"); }); + it("fails a terminal build and prints the server reason", async () => { + const result = await runProject( + ["project", "build", "--wait", "Build", "a", "demo"], + fakeClient({ + status: { + sessionId: "sess-1", + status: "failed", + projectId: "proj-1", + error: "active-project cap reached (1)", + }, + }), + ); + + expect(result.code).toBe(1); + expect(result.stdout.join("\n")).toContain("build sess-1: failed"); + expect(result.stdout.join("\n")).toContain("error: active-project cap reached (1)"); + }); + it("streams deduplicated file and phase progress while waiting", async () => { let calls = 0; const statuses: BuildStatusResponse[] = [ diff --git a/src/projects/cli.ts b/src/projects/cli.ts index bb076c8..2467c1b 100644 --- a/src/projects/cli.ts +++ b/src/projects/cli.ts @@ -330,7 +330,7 @@ async function buildCmd( if (previewUrl) handoffStore?.update({ sessionId: started.sessionId, previewUrl }); return 0; } - return status.status === "failed" ? 1 : 0; + return 1; } async function waitForBuild( @@ -408,7 +408,7 @@ async function statusCmd( const status = await client.getBuildStatus(resolved.sessionId); handoffStore?.update({ sessionId: resolved.sessionId, status: status.status, model: status.model }); printBuildStatus(status, out); - return status.status === "failed" ? 1 : 0; + return status.status === "completed" || status.status === "building" ? 0 : 1; } async function previewCmd( @@ -472,6 +472,7 @@ function resolveBuildSessionId( function printBuildStatus(status: BuildStatusResponse, out: (msg: string) => void): void { out(`build ${status.sessionId}: ${status.status}`); + if (status.error) out(` error: ${status.error}`); if (status.projectId) out(` project: ${status.projectId}`); if (status.model) out(` model: ${status.model}`); const files = uniqueStrings(status.filesCreated); diff --git a/src/projects/types.ts b/src/projects/types.ts index bd7897e..2196abd 100644 --- a/src/projects/types.ts +++ b/src/projects/types.ts @@ -41,6 +41,7 @@ export interface BuildStartResponse { export interface BuildStatusResponse { sessionId: string; status: string; + error?: string; projectId?: string; filesCreated?: string[]; model?: string;