Skip to content

Confine the build to type resolution and emit declarations, not JavaScript (Closes #2983) - #3102

Merged
acoliver merged 5 commits into
mainfrom
issue2983
Aug 6, 2026
Merged

Confine the build to type resolution and emit declarations, not JavaScript (Closes #2983)#3102
acoliver merged 5 commits into
mainfrom
issue2983

Conversation

@acoliver

@acoliver acoliver commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator

TLDR

The TypeScript build exists to serve type-aware lint and tsc --noEmit. This PR confines it to that job.

  • Four of six test_shard legs stop building. Tests never read compiled output: every workspace declares a bun export condition resolving to TypeScript source, and packages/cli/vitest.config.ts aliases cross-workspace imports at source.
  • The retained lint/typecheck build stops transpiling. npm run build:types runs tsc --build --emitDeclarationOnly, producing 2771 .d.ts files and zero compiler-emitted JavaScript.
  • The release path is untouched. release.yml still runs npm run build:packages with full emit, because every published library workspace declares main: dist/index.js and ships dist.

Removing the build surfaced four places that quietly depended on compiled output. All four are fixed at the import/spawn site rather than by restoring the build.

Reviewers should look hardest at two things: the decision to keep a build on the agents and scripts legs (explained below, with measurements), and the fact that a partially built workspace is worse than an unbuilt one under Bun.

Dive Deeper

What actually consumes packages/*/dist

Consumer Reads dist?
Type-aware lint and tsc --noEmit Yes — cli -> tools, core -> mcp, a2a-server -> settings/storage/tools map at dist/*.d.ts
npm consumers of the published library packages Yes — main/import point at dist/*.js when a consumer resolves without the bun condition
The PR test path No
The published CLI No — raw TypeScript plus the separate publish-time bundle at packages/cli/bundle/llxprt.js (#2999 / #3013), which prepack builds and this PR never touches

Hidden consumers the change surfaced

Measured by deleting packages/*/dist and running every shard.

  1. scripts/start.ts imported parseBootstrapArgs from packages/cli/dist/src/config/profileBootstrap.js and threw the result away. The call was added by the JS-to-TS script migration and duplicates what the spawned CLI already does. Removed.
  2. Three CLI integration files spawned node packages/cli/dist/index.js (34 failing cases). Their own comments already described the child as booting from TypeScript source, so they now spawn packages/cli/index.ts with the Bun binary running the suite — which is what the shipped launcher does. They are also noticeably faster.
  3. packages/auth's package-boundary test asserted dist/index.js and dist/index.d.ts exist on disk. That only held because the shard built first, so it measured the CI harness. Its coverage is replaced by an end-to-end build test (below); the published contract stays pinned by the main/types/exports assertions in the same file.
  4. packages/cli's build chains chmod_executable.ts dist/index.js, which does not exist in declaration-only mode. The script now treats an absent target as a no-op only in that mode and still fails loudly otherwise.

Why the agents and scripts legs still build

Both run the agents API-surface guard — agents through its package pretest hook, scripts through scripts/tests/check-agents-api-surface.test.ts. Despite its docblock, that guard needs dependency declarations: its temp tsconfig resolves @vybestack/llxprt-code-{telemetry,mcp} and several storage/* subpaths through node_modules to dist/*.d.ts, because packages/agents/tsconfig.json has no source mapping for them. Those subpaths are not expressible as wildcard paths entries — @vybestack/llxprt-code-storage/storage/secure-store.js resolves to src/secure-store/secure-store.ts, and @vybestack/llxprt-code-tools/doubleEscapeUtils.js to src/formatters/doubleEscapeUtils.ts. Repointing them is #2618, and the issue lists that work under Out of scope.

Everything else on those legs is fine without a build: with dist deleted, bun scripts/test.ts --shard agents --skip-pretest passes 337/340 files, and the three stragglers pass in isolation (they are load-sensitive 30s timeouts, not resolution failures).

The redundant per-shard Run agents API-surface guard step is removed: lint_javascript already runs it after its own build, and the agents shard covers it through the package pretest hook.

Why those legs need the FULL build, not build:types

Bun applies tsconfig paths at runtime. packages/core/tsconfig.json maps @vybestack/llxprt-code-mcp to ../mcp/dist/mcp/index.d.ts, and that mapping wins over the package's bun export condition whenever the file exists. With a declaration-only dist, cross-package imports therefore resolve to a .d.ts whose relative re-export has no JavaScript behind it.

Measured: 178 of 340 agents test files die at import with Cannot find module './src/index.js' from packages/mcp/dist/mcp/index.d.ts, and bun scripts/start.ts fails the same way. With no dist, resolution falls through to the bun condition and everything passes.

A complete dist works. No dist works. A partial one does not. build:types is therefore confined to lint_javascript, which executes no application code, and both ci.yml and the test suite pin that constraint so nobody moves it.

Build plumbing

  • scripts/build_package.ts appends --emitDeclarationOnly when LLXPRT_EMIT_DECLARATIONS_ONLY=1. Build mode accepts the flag, so no parallel tsconfig tree is needed — one pipeline, two emit modes. Only the exact value 1 enables it, so a stray 0 cannot change what the release build emits.
  • Root build:types sets that variable and delegates to build. build and build:packages are untouched.
  • scripts/build.ts skips two workspaces in declaration-only mode, because neither contributes declarations that any tsconfig maps: vscode-ide-companion ends its build in esbuild (which resolves workspace deps at dist/*.js), and lsp builds with a bare tsc -p that never sees the flag. Both still build normally on the release path, and lsp is reached at runtime by module resolution from a spawned process, never imported.

Reviewer Test Plan

Confirm the emit contract:

rm -rf packages/*/dist node_modules/.cache/tsbuildinfo
npm run build:types
find packages/*/dist -name '*.js' -o -name '*.js.map'

Only two files should appear, both example-extension assets copied verbatim by copy_files.ts (examples/mcp-server/example.js, examples/hooks/scripts/on-start.js). No compiler output. Then check find packages/*/dist -name '*.d.ts' | wc -l is in the thousands, and that lint and typecheck still pass against it:

npm run typecheck
npm run lint:ci
npm run lint:agents-api-surface
npm run lint:affected-shards
npm run gate:agents-neutral

Confirm the shards no longer need a build:

rm -rf packages/*/dist node_modules/.cache/tsbuildinfo
bun scripts/test.ts --shard cli
bun scripts/test.ts --shard core
bun scripts/test.ts --shard providers
bun scripts/test.ts --shard rest
bun scripts/start.ts --profile-load <your profile> "write me a haiku and nothing else"

Confirm the release path is intact:

npm run build
ls -l packages/cli/dist/index.js        # present and mode 0755
npm run bundle:cli                       # publish-time CLI bundle still builds
npm run build:types                      # declaration build must not delete it
ls -l packages/cli/bundle/llxprt.js

And the focused suite:

bun test scripts/tests/issue-2983-declaration-build.test.ts

Note: run the CLI integration files through bun scripts/test.ts --shard cli, not a single combined bun test a.ts b.ts c.ts. The CLI runner spawns one process per file and the suite relies on that isolation for LLXPRT_CONFIG_HOME; sharing one process leaks settings between files. That is pre-existing and unrelated to this PR.

Testing Matrix

🍏 🪟 🐧
npm run
npx
Docker
Podman - -
Seatbelt - -

Verified on macOS: npm run test, npm run lint:ci, npm run lint:eslint-guard, npm run typecheck, npm run format:check, npm run build, npm run build:types, npm run bundle:cli, and the CLI smoke run. Windows and Linux are covered by the CI matrix; the two platform-sensitive spots are chmod_executable.ts (already a no-op on Windows) and build:types, which uses cross-env.

Linked issues / bugs

Closes #2983

Contributes to #2702 (CI execution optimization) and #2578 (all-Bun).
Coordinates with #2999 / #3013: the publish-time CLI bundle stays decoupled from the declaration build, and no build path deletes packages/cli/bundle/.
Blocked on #2618 for the last two shard builds.

Summary by CodeRabbit

  • Build & CI

    • Improved build workflows by separating declaration generation from full JavaScript builds.
    • Limited full builds to the workflows that require generated runtime files.
  • Bug Fixes

    • Improved CLI integration test reliability by running TypeScript entry points directly.
    • Added handling for process-launch failures so tests complete with clear error results.
  • Tests

    • Added comprehensive coverage for declaration-only builds, release builds, workspace selection, asset handling, and executable permissions.

The TypeScript build exists to serve type-aware lint and `tsc --noEmit`.
Nothing else reads it: every workspace declares a `bun` export condition
resolving to source, packages/cli/vitest.config.ts aliases cross-workspace
imports at source, and the published CLI ships raw TypeScript plus the
separate publish-time bundle from #2999/#3013.

Remove the build from four of six test shard legs and give the retained
lint/typecheck build a declaration-only mode.

Emit mode
- scripts/build_package.ts appends --emitDeclarationOnly to `tsc --build`
  when LLXPRT_EMIT_DECLARATIONS_ONLY=1, and guards top-level execution
  behind import.meta.main so the mode helpers are testable.
- Root `build:types` sets that variable; `build` and `build:packages` are
  untouched, so the release path keeps full JavaScript emit for the
  workspaces that publish `main: dist/index.js`.
- scripts/build.ts skips the VS Code companion in declaration-only mode:
  its esbuild step resolves workspace deps at `dist/*.js`, and it is built
  on its own track by `npm run build:vscode`.
- scripts/chmod_executable.ts treats an absent target as a no-op only in
  declaration-only mode, and still fails loudly otherwise.

Consumers of compiled output that the removal surfaced
- scripts/start.ts imported parseBootstrapArgs from
  packages/cli/dist/src/config/profileBootstrap.js and discarded the
  result. The call was added by the JS-to-TS script migration and
  duplicates what the spawned CLI already does; drop it.
- Three CLI integration files spawned `node packages/cli/dist/index.js`.
  Their own comments already described the child as booting from
  TypeScript source; spawn packages/cli/index.ts with the Bun binary
  running the suite instead.
- packages/auth's package-boundary test asserted dist/index.js and
  dist/index.d.ts exist on disk, which only held because the shard built
  first. The published contract stays pinned by the main/types/exports
  assertions.

CI
- lint_javascript builds declarations only.
- test_shard builds only on the `agents` and `scripts` legs, which run the
  agents API-surface guard. That guard resolves telemetry, mcp, and several
  storage subpaths through node_modules to `dist/*.d.ts` because
  packages/agents/tsconfig.json has no source mapping for them; repointing
  those is #2618.
- Those legs need the FULL build. Bun applies tsconfig `paths` at runtime,
  so a declaration-only dist makes core's mcp mapping resolve to a `.d.ts`
  with no JavaScript behind it: 178 of 340 agents test files then die at
  import. A complete dist or no dist both work; a partial one does not.
- The per-shard agents API-surface guard step is removed as redundant with
  lint_javascript and the agents package pretest hook.
- The stale comment citing "storage, settings" now names the real
  dependents: cli to tools, core to mcp, a2a-server to settings/storage/tools.

Refs #2983
Review remediation for #2983.

- scripts/build.ts: skip packages/lsp in declaration-only mode. Its build is
  a bare `tsc -p tsconfig.json` that never sees --emitDeclarationOnly, so it
  emitted JavaScript into a build whose purpose is not to. Nothing imports
  the package or maps it in a tsconfig — it is reached by module resolution
  from a spawned process — so no declarations are lost. Guard the script's
  top-level execution behind import.meta.main so the selector is importable.
  A clean `npm run build:types` now leaves 2771 declarations and zero
  compiler-emitted JavaScript.
- scripts/tests/issue-2983-declaration-build.test.ts: add an end-to-end run
  of the real build_package.ts against a throwaway workspace laid out like a
  real one, asserting the emitted file set in both modes. This is the
  coverage that replaces the auth build-artifact assertions: it proves a full
  build writes index.js, index.d.ts, staged assets and .last_build, and that
  a declaration build writes no .js or .js.map. Also pin the lsp skip as safe
  by asserting no tsconfig references the package.
- Correct the claim that nothing consumes packages/*/dist/*.js. Published
  library workspaces do, through main/import, whenever a consumer resolves
  without the `bun` export condition. Only the PR path does not.

Refs #2983
Second review pass for #2983.

- packages/cli/src/integration-tests: the spawned-CLI helpers listened for
  'close' but not 'error'. A spawn failure (a moved or deleted CLI entry)
  emits only 'error', so the promise never settled and the case hung until
  the runner's own timeout with no cause reported. Settle with exit code -1
  and the spawn message on stderr, matching the existing timeout path.
- scripts/build.ts: name the workspace when reading or parsing its
  package.json fails. A bare SyntaxError left the reader to guess which of
  sixteen manifests was malformed.
- scripts/tests/issue-2983-declaration-build.test.ts: guard the two
  indexOf-based lookups. A renamed ci.yml marker returned -1, which sliced
  most of the file and still contained every expected phrase, so the test
  would have passed on stale content; and an empty build-step list produced
  a misleading assertion message instead of naming the real problem.

Refs #2983
@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your recent review volume is higher than typical usage, so adaptive limits are currently applied.

Next review available in: 21 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 0cce843d-8e0c-40bf-9b64-4b483b765eb8

📥 Commits

Reviewing files that changed from the base of the PR and between 85b8d0d and e909a74.

📒 Files selected for processing (4)
  • packages/cli/src/integration-tests/cli-args-test-helpers.ts
  • packages/cli/src/integration-tests/loadbalancer.integration.test.ts
  • scripts/build.ts
  • scripts/tests/issue-2983-declaration-build.test.ts
📝 Walkthrough

Walkthrough

The PR adds declaration-only build support, narrows full builds in CI, updates CLI integration tests to execute TypeScript entry points, and adds coverage for build behavior, workspace selection, executable handling, and workflow wiring.

Changes

Declaration-only build pipeline

Layer / File(s) Summary
Declaration-only package builds
scripts/build_package.ts, scripts/chmod_executable.ts, scripts/tests/issue-2983-declaration-build.test.ts
Build scripts support declaration-only TypeScript output, preserve asset staging, and handle missing executable artifacts in that mode. Tests cover declaration and release builds.
Workspace build selection
scripts/build.ts, package.json, scripts/start.ts
The root build selects workspaces from package manifests and excludes configured workspaces during declaration-only builds. The build:types script invokes this mode.
CI build wiring and package contracts
.github/workflows/ci.yml, packages/auth/src/__tests__/package-boundary.test.ts, scripts/tests/issue-2983-declaration-build.test.ts, tsconfig.scripts.json
CI performs declaration builds before linting and full builds only on required shards. Tests no longer require local package artifacts and validate the workflow rules.
TypeScript CLI integration launchers
packages/cli/src/integration-tests/cli-args-test-helpers.ts, packages/cli/src/integration-tests/loadbalancer.integration.test.ts
Integration tests spawn the TypeScript CLI entry point with the current runtime and return exit code -1 when spawning fails.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related issues

  • vybestack/llxprt-code#2983: The PR implements declaration-only builds and removes unnecessary test-shard builds described by the issue.

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 37.50% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: limiting the build to declaration emission instead of JavaScript output.
Description check ✅ Passed The description covers the required sections, explains the changes, provides a test plan, records testing status, and links related issues.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue2983

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

This PR changes 12 file(s).

  • project-plans/issue2983/plan.md: (per-file summary unavailable)
  • scripts/tests/issue-2983-declaration-build.test.ts: (per-file summary unavailable)
  • packages/auth/src/__tests__/package-boundary.test.ts: (per-file summary unavailable)
  • package.json: (per-file summary unavailable)
  • scripts/chmod_executable.ts: (per-file summary unavailable)
  • packages/cli/src/integration-tests/cli-args-test-helpers.ts: (per-file summary unavailable)
  • .github/workflows/ci.yml: (per-file summary unavailable)
  • scripts/build.ts: (per-file summary unavailable)
  • tsconfig.scripts.json: (per-file summary unavailable)
  • scripts/build_package.ts: (per-file summary unavailable)
  • scripts/start.ts: (per-file summary unavailable)
  • packages/cli/src/integration-tests/loadbalancer.integration.test.ts: (per-file summary unavailable)

Changes

Layer File(s) Summary
project-plans/issue2983 project-plans/issue2983/plan.md Changes in project-plans/issue2983
scripts/tests scripts/tests/issue-2983-declaration-build.test.ts Changes in scripts/tests
packages/auth/src/tests packages/auth/src/tests/package-boundary.test.ts Changes in packages/auth/src/tests
. package.json, tsconfig.scripts.json Changes in .
scripts scripts/chmod_executable.ts, scripts/build.ts, scripts/build_package.ts, scripts/start.ts Changes in scripts
packages/cli/src/integration-tests packages/cli/src/integration-tests/cli-args-test-helpers.ts, packages/cli/src/integration-tests/loadbalancer.integration.test.ts Changes in packages/cli/src/integration-tests
.github/workflows .github/workflows/ci.yml Changes in .github/workflows

Magnitude

🎯 3 (L)
1080 additions, 84 deletions, 12 changed files across 2 packages, 31 acceptance criteria

Related

No related items found.


Walkthrough generated by LLxprt PR Review. Planner issue: #2256

@github-actions github-actions Bot added the maintainer:e2e:ok Trusted contributor; maintainer-approved E2E run label Aug 6, 2026
Comment thread scripts/build.ts Outdated
Comment thread scripts/build.ts
@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

OpenCodeReview — automatic reviews suspended

Automatic OCR reviews are suspended for this PR after 2 of 2 automatic reviews.

To get more reviews you can:

  • Check the box below to re-enable automatic reviews (resets the counter), or

  • Comment /review, /ocr, or /open-code-review to request a single review on demand.

  • Re-enable automatic reviews


OpenCodeReview — PR #3102

  • Reviewed head SHA: 85b8d0dc72fafd2a26ba612bd798ba205f194d6a
  • Merge base: 42ca2a9898600c0cc558c4c932d3c0cd1aa96379
  • Range: incremental from 93e76ffe635400d1a9291b67868e710cfe2244e6
  • Range fallback: none
  • Scope: selected 2 file(s), +31/-3; cumulative 12 file(s), +1038/-84
  • Tokens: 98134 total (83666 input, 14468 output, 36224 cache)
  • OCR version: open-code-review v1.8.4 (e78474478) linux/amd64 built at: 2026-08-01T03:27:37Z https://github.com/alibaba/open-code-review
  • Phase: review
  • Exit code: 0
  • Run: https://github.com/vybestack/llxprt-code/actions/runs/31088650983
  • 3 finding(s) (3 posted inline).
  • Artifacts: ocr-review-output contains raw JSON, stdout, stderr, preview, phase, and exit-code diagnostics.
  • WARNING: Changed-file coverage 1/2 preview files covered is below the 90% threshold.

@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Code Coverage Summary

Package Lines Statements Functions Branches
CLI N/A% N/A% N/A% N/A%
Core N/A% N/A% N/A% N/A%
CLI Package - Full Text Report
CLI full-text-summary.txt not found at: coverage_cli/packages/cli/coverage/full-text-summary.txt
Core Package - Full Text Report
Core full-text-summary.txt not found at: coverage_core/packages/core/coverage/full-text-summary.txt

For detailed HTML reports, please see the 'coverage-reports-24.x-ubuntu-latest' artifact from the main CI run.

PR review remediation for #2983.

- scripts/build.ts: the workspace-name pattern rejected uppercase. It exists
  to keep names shell-safe where they are interpolated into the npm command
  line, not to enforce npm naming policy — and npm still resolves legacy
  names containing uppercase, so the stricter rule could have thrown on a
  valid workspace. Accept uppercase in both scope and name segments and say
  in the comment what the pattern is for.
- scripts/tests/issue-2983-declaration-build.test.ts: pin the entry-point
  contract that the import.meta.main guards introduced. The case spawns
  build_package.ts from outside packages/ and asserts it exits 1 with
  "must be invoked from a package directory" — the first statement inside
  the guarded main(), so reaching it proves entry-point execution survived.
  Nothing in the repo imports either build script for side effects; the only
  importer is this test, and it takes the workspace selector alone.

Refs #2983
Comment thread scripts/tests/issue-2983-declaration-build.test.ts
Comment thread scripts/tests/issue-2983-declaration-build.test.ts
Comment thread scripts/tests/issue-2983-declaration-build.test.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
scripts/tests/issue-2983-declaration-build.test.ts (1)

445-476: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Optional: extract the repeated build-step filter.

Three tests repeat the same filter over test_shard steps at Lines 446, 453, and 470. A single helper removes the repetition and keeps the matcher string in one place.

♻️ Proposed helper
function shardBuildSteps(): WorkflowStep[] {
  return jobSteps(ciJobs()['test_shard']).filter((step) =>
    String(step.run ?? '').includes('npm run build'),
  );
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/tests/issue-2983-declaration-build.test.ts` around lines 445 - 476,
Extract the repeated build-step filtering logic into a helper such as
shardBuildSteps(), using the existing test_shard workflow and “npm run build”
matcher. Replace the inline filters in all three tests with calls to that helper
while preserving their existing assertions.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/cli/src/integration-tests/cli-args-test-helpers.ts`:
- Around line 135-146: Update the spawn-error lifecycle comments in the error
handlers of both packages/cli/src/integration-tests/cli-args-test-helpers.ts
(lines 135-146) and
packages/cli/src/integration-tests/loadbalancer.integration.test.ts (lines
96-107): state that a spawn failure emits error and later close, while the error
handler preserves the diagnostic and exitCode -1 and the later close handler
cannot alter the already-settled promise. No behavioral code change is needed.

In `@scripts/build.ts`:
- Around line 99-106: Update workspaceBuildSelector to detect when
declarationBuildWorkspaces(readWorkspacePackageNames()) produces no workspaces
and throw an explicit error before mapping or returning the selector. Preserve
the existing non-declarations path and normal workspace flag generation for
non-empty results.

---

Nitpick comments:
In `@scripts/tests/issue-2983-declaration-build.test.ts`:
- Around line 445-476: Extract the repeated build-step filtering logic into a
helper such as shardBuildSteps(), using the existing test_shard workflow and
“npm run build” matcher. Replace the inline filters in all three tests with
calls to that helper while preserving their existing assertions.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 099267af-0e86-48b9-a3d2-3ec96cd82612

📥 Commits

Reviewing files that changed from the base of the PR and between 42ca2a9 and 85b8d0d.

⛔ Files ignored due to path filters (1)
  • project-plans/issue2983/plan.md is excluded by !project-plans/**
📒 Files selected for processing (11)
  • .github/workflows/ci.yml
  • package.json
  • packages/auth/src/__tests__/package-boundary.test.ts
  • packages/cli/src/integration-tests/cli-args-test-helpers.ts
  • packages/cli/src/integration-tests/loadbalancer.integration.test.ts
  • scripts/build.ts
  • scripts/build_package.ts
  • scripts/chmod_executable.ts
  • scripts/start.ts
  • scripts/tests/issue-2983-declaration-build.test.ts
  • tsconfig.scripts.json
💤 Files with no reviewable changes (1)
  • scripts/start.ts

Comment thread packages/cli/src/integration-tests/cli-args-test-helpers.ts
Comment thread scripts/build.ts
Third review pass for #2983.

- scripts/build.ts: throw when the declaration build selects no workspaces.
  An empty selector left a bare `npm run build`, which re-enters this script
  instead of fanning out — the declaration build would report success while
  building nothing it intended. Unreachable today, reachable the moment the
  exclusion set grows, and silent either way.
- scripts/tests/issue-2983-declaration-build.test.ts: add the parallel
  entry-point case for build.ts. It has no cwd guard — it anchors on
  import.meta.url — so spawning it from a temp directory would run a real
  build. Instead the case empties PATH, which makes its first guarded action
  (`npm run generate`) fail immediately; reaching that failure proves main()
  ran while doing no work. Also pin the empty-selector guard.
- packages/cli/src/integration-tests: correct the spawn-failure comments. A
  failed spawn emits 'error' and then 'close' with a null exit code; the
  earlier text claimed 'close' never fires. The behaviour was already right
  (the first settle wins) but the stated mechanism was not.

Refs #2983
@acoliver

acoliver commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator Author

Scope note: one acceptance criterion is intentionally not fully met

The issue asks that npm run build no longer run in test_shard and that all shards pass with no dist/ present. This PR removes the build from four of six legs. The agents and scripts legs still build. That is a deliberate deferral, and here is the evidence behind it.

Why those two legs. Both run the agents API-surface guard — agents through its package pretest hook, scripts through scripts/tests/check-agents-api-surface.test.ts. Nothing else on either leg needs a build: with dist deleted, bun scripts/test.ts --shard agents --skip-pretest passes 337/340 files, and the three stragglers pass individually (load-sensitive 30s timeouts, not resolution failures).

Why the guard needs it. Its docblock claims it is clean-CI safe, but that is not true today. Its temp tsconfig extends packages/agents/tsconfig.json, which has no source mapping for @vybestack/llxprt-code-telemetry or @vybestack/llxprt-code-mcp and no correct one for several storage/* and tools/* subpaths, so those specifiers fall through to node resolution and land on dist/*.d.ts. Twenty distinct specifiers fail without a build.

Why it is not a small fix. The failing subpaths are not expressible as wildcard paths entries, because the published subpath and the source layout diverge:

@vybestack/llxprt-code-storage/storage/secure-store.js  ->  src/secure-store/secure-store.ts
@vybestack/llxprt-code-tools/doubleEscapeUtils.js       ->  src/formatters/doubleEscapeUtils.ts

Each needs an explicit per-subpath mapping across four packages. That is repointing cross-workspace mappings at source, which the issue lists under Out of scope and which #2618 owns. It also carries real risk: the guard compares against a checked-in API-surface snapshot, so changing how it resolves types can shift the parsed surface.

Second constraint, discovered while implementing. Those two legs must run the FULL build, not build:types. Bun applies tsconfig paths at runtime, so packages/core/tsconfig.json's @vybestack/llxprt-code-mcp -> ../mcp/dist/mcp/index.d.ts mapping beats the package's bun export condition whenever the file exists. With a declaration-only dist, 178 of 340 agents test files die at import with Cannot find module './src/index.js' from packages/mcp/dist/mcp/index.d.ts. A complete dist works and no dist works; a partial one does not. build:types is therefore confined to lint_javascript, which runs no application code, and both ci.yml and the test suite pin that so nobody moves it.

What was delivered. Four of six shard legs stop building, the retained lint/typecheck build stops transpiling, and four genuine dist/*.js consumers were fixed at the import site rather than by restoring the build. Removing the last two builds is unblocked by #2618.

@acoliver
acoliver merged commit dfd0091 into main Aug 6, 2026
44 checks passed
@acoliver

acoliver commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator Author

Follow-up filed: #3104 — removes the last two test-shard builds once the agents API-surface guard resolves at source. Blocked by #2618, milestone 0.12.0.

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

Labels

maintainer:e2e:ok Trusted contributor; maintainer-approved E2E run

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Remove the build from the test path; keep it for lint/typecheck only and emit declarations, not JS

1 participant