Skip to content

build: fix the two breaks that keep CI red on main - #1575

Open
Salhi-zh wants to merge 2 commits into
CodebuffAI:mainfrom
Salhi-zh:build/green-main
Open

Salhi-zh wants to merge 2 commits into
CodebuffAI:mainfrom
Salhi-zh:build/green-main

Conversation

@Salhi-zh

Copy link
Copy Markdown
Contributor

Problem

build-and-test fails on main for every recent commit, at the first build step:

Build SDK → ❌ TypeScript declaration bundling failed: Compiled with errors

Seven errors, in three files, all one cause — plus a second break waiting behind it that only shows once the SDK builds.

Cause 1 — JSON is read-only where it crosses a boundary, but its type said mutable

common/src/types/json.ts declared:

export type JSONObject = { [key in string]: JSONValue | undefined }
export type JSONArray = JSONValue[]

The model SDKs type their payloads as Readonly<...> (Readonly<JSONObject>, readonly arrays, @ai-sdk/provider's own JSONValue). A mutable index signature does not accept a read-only one, so SharedV4ProviderOptions cannot be assigned to ProviderMetadata, and every message/stream path that touches providerOptions fails to compile:

  • sdk/src/impl/llm.ts:269, :782
  • common/src/util/messages.ts:138, :454, :461
  • packages/agent-runtime/src/tool-stream-parser.ts:142
  • packages/agent-runtime/src/tools/stream-parser.ts:805

The data really is read-only once it leaves a provider call, so the type now says so: JSONObject has a readonly index signature and JSONArray is readonly JSONValue[]. One place assembles a new payload — omitUndefined in agent-runtime/…/gravity-index.ts — and it now builds a writable Record<string, JSONValue | undefined> and returns that, which is what it was doing anyway; the annotation was the only thing forcing the mutable view.

Cause 2 — picocolors is imported but declared nowhere

cli/src/index.tsx, cli/src/login/plain-login.ts and cli/src/utils/agent-dir-trust.ts import picocolors; no package.json listed it, so once the SDK builds, the next step stops at:

error: Could not resolve: "picocolors"
    at cli/src/index.tsx:28:42

Declared as ^1.1.1 in cli/package.json; bun.lock updated. This is the only dependency change in the PR.

Verification — the four steps CI runs, in order, on this branch

bun install --frozen-lockfile                → exit 0   (lock and package.json agree)
bun run build:sdk                            → exit 0   (was: 7 TS errors, bundling failed)
bun freebuff/cli/build.ts 0.0.0-ci           → exit 0   (was: Could not resolve picocolors)
cli/bin/freebuff --version                   → 0.0.0-ci
bun cli/scripts/smoke-binary.ts cli/bin/freebuff → OK (matched /Press ENTER to login/, attempt 1)

cd sdk && bun run typecheck is exit 0, zero errors (was seven).

Why this is the durable fix, not a suppression

  • No any, no @ts-expect-error, no cast at the failing call sites: the seven errors disappear because the type describes the data correctly.
  • The read-only model matches the direction the SDKs already moved (their JSONValue is Readonly), so a future provider bump does not reintroduce it.
  • The one write site is fixed where writing actually happens, rather than by making the shared type mutable again.

Effect on other PRs

This is the only thing standing between the repo and a green build-and-test: the step fails before any test runs, so every open PR inherits it regardless of content. Once this lands, the other open PRs get a green run on a rebase.

`bun run build:sdk` fails on main for every recent commit, and the binary build
stops behind it. Two independent causes:

1. common's JSON types were mutable - `{ [key: string]: JSONValue }` and
   `JSONValue[]` - while the model SDKs type their payloads as `Readonly<...>`.
   A mutable index signature does not accept a read-only one, so every
   providerOptions assignment was a type error: seven of them, from
   sdk/src/impl/llm.ts:269 through common/src/util/messages.ts and
   agent-runtime's stream parsers. JSON that crosses a boundary is read-only,
   so the type now says so. The one place that assembles a new payload
   (agent-runtime's gravity-index `omitUndefined`) builds a writable
   `Record<string, JSONValue | undefined>` and returns that.

2. cli/src imports `picocolors` in three files and it was declared in no
   package.json, so the binary build stopped at `Could not resolve:
   "picocolors"`. Declared at ^1.1.1.

Verified with the four steps CI runs, in that order, from a clean tree:
  bun install --frozen-lockfile                     exit 0
  bun run build:sdk                                 exit 0 (was 7 TS errors and
                                                    "declaration bundling failed")
  bun freebuff/cli/build.ts 0.0.0-ci                exit 0
  cli/bin/freebuff --version + smoke-binary.ts      OK, boot matched
The compiled binary bakes NEXT_PUBLIC_* in at build time. The workflow set them
only on the smoke step, so the build ran with none of them: the values were
baked in as undefined, every invocation died in common/src/env.ts, and the smoke
step reported "--smoke-api-url exited 1 without printing a URL".

Reproduced from a clean environment (env -i, both directions):
  build without NEXT_PUBLIC_*   → --smoke-api-url exits 1 in the env schema
  build with this env block     → probe prints the URL; tree-sitter, dotenv
                                  isolation and boot all pass
@Salhi-zh

Copy link
Copy Markdown
Contributor Author

@obadakhalili this is now the critical blocker: main's last three merges all failed build-and-test, so every open PR (#1583, #1584, #1571, +further) inherits the red check and is unmergeable through normal channels.

The fix in this PR is exactly what's needed to unbreak the chain. Once this merges, I'll rebase the ones I care about onto green main so their CI re-runs pass the new check-run and land cleanly.

Concrete merge order I'd suggest:

  1. build: fix the two breaks that keep CI red on main #1575 (this) — unblocks everything else
  2. Then I'll rebase + land cli: stop storing the turn's run state in chat message metadata #1583 (freebuff RAM), cli: skip checkpoint writes when the state is unchanged, and one fsync group per drain #1584 (checkpoint efficiency), sdk: host-configurable state snapshot interval, and snapshots that share messages #1571, and the rest in sequence.

Let me know if you want anything else changed here before merging — happy to fix.

@codebuff-team

Copy link
Copy Markdown
Contributor

Good diagnostic work: the readonly/mutable mismatch between JSONObject/JSONArray and the Readonly<...> types used by the provider SDKs is a real, specific cause, and tightening common/src/types/json.ts to readonly (plus fixing the one mutation site in gravity-index.ts to build a plain Record instead) is the right layer to fix it at rather than casting at each call site. The missing picocolors entry in cli/package.json/bun.lock is an equally clear, minimal fix.

Two things worth flagging before this is ported:

  1. The .github/workflows/ci.yml env-var addition (NEXT_PUBLIC_* placeholders) isn't mentioned anywhere in the PR description's two named causes, even though it's a meaningful, separate change (inlining env at build time for the smoke test). Please call it out explicitly — a reviewer skimming the prose would miss it entirely.
  2. Flipping JSONObject/JSONArray to readonly is a fairly broad type change. You found and fixed the one mutation site inside agent-runtime, but since this type is exported from common, it's worth double-checking there isn't a write site elsewhere in the private tree that the public mirror doesn't show (e.g. anything building provider options or stream state mutably). Your own typecheck run is good evidence, but it only covers what's visible here.

Overall this looks like exactly the sort of build-breakage fix worth porting by hand — just tighten the write-up to cover all three changes so whoever ports it doesn't have to reverse-engineer the CI diff.

@codebuff-team codebuff-team added bot:triaged Classified by the community triage bot pr:port-candidate Worth porting into the private source tree labels Oct 30, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bot:triaged Classified by the community triage bot pr:port-candidate Worth porting into the private source tree

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants