Thanks to visit codestin.com
Credit goes to github.com

Skip to content

fix(cli): scaffold installs clean — seed/preserve allowBuilds, heal pnpm placeholders - #230

Merged
RohinBhargava merged 1 commit into
mainfrom
rohin/scaffold-fixes
Jul 31, 2026
Merged

fix(cli): scaffold installs clean — seed/preserve allowBuilds, heal pnpm placeholders#230
RohinBhargava merged 1 commit into
mainfrom
rohin/scaffold-fixes

Conversation

@RohinBhargava

@RohinBhargava RohinBhargava commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes the scaffold issues that force downstream consumers (ForkLaunch Studio) to patch generated files after init. Audit of the reported five items against main:

# Issue Status
1 pnpm-workspace.yaml placeholder breaks installs; re-init clobbers fixes Fixed here
2 MikroORM version skew (7.0.15 vs 7.1.8) Already fixed on main (#228): CLI pins 7.1.8, scaffold resolves a single instance
3 BullMqWorkerOptions.queueOptions TS2345 Not reproducible on main: scaffold emits concrete queueOptions, fresh init worker -t bullmq + tsc --noEmit passes with 0 errors (was collateral of the #2-era duplicate-package skew)
4 Root workspace globs apps/* Not present on main: the CLI emits no root pnpm-workspace.yaml and no apps/* glob anywhere
5 Bun temp-dir sandbox blocks module installs Mitigated here

Root cause for #1

The placeholder text is written by pnpm itself, not the CLI: the post-init pnpm format triggers pnpm 11's auto-install, which blocks unapproved build scripts and injects allowBuilds: { esbuild: set this to true or false, ... } into the workspace yaml. The CLI then made it unfixable: every init service/router/worker and change application round-tripped the yaml through a packages-only struct, silently dropping allowBuilds and any other consumer-added keys.

Changes

  • generate_pnpm_workspace seeds allowBuilds: true for the scaffold's known build-script deps, so pnpm never injects placeholders
  • The workspace struct preserves unmodeled keys (overrides, blockExoticSubdeps, ...) via serde flatten, and every rewrite heals placeholder string values to true
  • change application renders through the same preserving helper instead of a from-scratch struct
  • release create bun installs get a project-local TMPDIR so Bun's temporary-directory sandbox cannot block them
  • New fixture test (init_worker_workspace_and_typecheck.sh): scaffolds fresh, asserts no placeholders + allowBuilds seeded, asserts survival across init worker/init service, poisons the yaml with placeholders + foreign keys and asserts healing + preservation, then requires pnpm install and per-project tsc --noEmit to pass with zero patches

Test plan

  • cargo test: 327 passed
  • Fixture script run locally end-to-end: passes (install clean, tsgo --noEmit clean in core/worker/service, full build green)

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Workspace configuration now supports build-script allowlists for safer dependency installation.
    • Existing workspace settings, including custom configuration, are preserved when projects are initialized or updated.
    • Missing workspace package entries and pnpm placeholders are automatically restored.
  • Bug Fixes

    • Runtime switching now keeps workspace package definitions intact.
    • Bun dependency installation uses a project-local temporary directory, improving reliability in restricted environments.
    • Invalid build allowlist values are normalized automatically.

pnpm 10+ blocks install-time build scripts unless allowBuilds lists
them; with no seed list, pnpm writes literal 'set this to true or
false' placeholders into the workspace yaml during the post-init
install, which then fail every subsequent install. Worse, the CLI
round-tripped the yaml through a packages-only struct, so init
service/router/worker and change application clobbered any hand-added
fix (allowBuilds, blockExoticSubdeps, overrides, ...).

- generate seeds allowBuilds: true for the scaffold's known
  build-script deps
- the workspace struct now preserves unmodeled keys via flatten and
  heals placeholder values to true on every rewrite
- bun installs during release create get a project-local TMPDIR so
  Bun's temp-dir sandbox cannot block them
- fixture test scaffolds fresh, asserts yaml integrity across inits,
  and requires pnpm install + tsc --noEmit to pass with zero patches

Co-Authored-By: Claude Fable 5 <[email protected]>
@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The CLI now preserves and sanitizes pnpm workspace settings, renders updated package entries through a dedicated function, uses a local temporary directory for Bun installs, and validates the flow with an end-to-end workspace test.

Changes

Workspace configuration and installation

Layer / File(s) Summary
Workspace model, sanitization, and rendering
cli/src/core/pnpm_workspace.rs
PnpmWorkspace now supports allowBuilds and unknown YAML keys. Workspace generation and updates sanitize build permissions and preserve existing configuration.
Runtime integration and installation validation
cli/src/change/application.rs, cli/src/release/create.rs, cli/tests/init_worker_workspace_and_typecheck.sh
Runtime changes use render_pnpm_workspace_with_packages. Bun installs create .forklaunch-tmp and set TMPDIR. The integration test validates configuration preservation, repair, installation, typechecks, and the workspace build.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant CLI
  participant WorkspaceRenderer
  participant WorkspaceFile
  participant PackageManager
  participant Validation
  CLI->>WorkspaceRenderer: render workspace with package entries
  WorkspaceRenderer->>WorkspaceFile: read, preserve, sanitize, and serialize YAML
  CLI->>PackageManager: install dependencies with runtime-specific settings
  PackageManager-->>CLI: installation result
  CLI->>Validation: run typechecks and workspace build
  Validation-->>CLI: validation result
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main workspace sanitization and scaffold installation fixes in the pull request.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch rohin/scaffold-fixes

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

@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)
cli/tests/init_worker_workspace_and_typecheck.sh (1)

44-53: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

Cover the runtime workspace renderer.

This fixture checks init service, but it does not invoke change application, which calls render_pnpm_workspace_with_packages in cli/src/change/application.rs. Add a runtime-change step after writing the poisoned YAML. Assert that it preserves blockExoticSubdeps and repairs the known placeholders.

🤖 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 `@cli/tests/init_worker_workspace_and_typecheck.sh` around lines 44 - 53, Add a
runtime change step in cli/tests/init_worker_workspace_and_typecheck.sh after
writing the poisoned workspace YAML, invoking change application so
render_pnpm_workspace_with_packages in cli/src/change/application.rs executes.
Assert the resulting WORKSPACE_YAML still contains blockExoticSubdeps: false and
no longer contains the known placeholder allowBuilds values.
🤖 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 `@cli/src/core/pnpm_workspace.rs`:
- Around line 63-78: Update sanitize_allow_builds so non-boolean placeholders
are converted to true only for dependencies listed in
ALLOWED_BUILD_DEPENDENCIES; preserve unknown entries as false. Add a fixture
covering an unknown allowBuilds placeholder and verify it remains disallowed.

In `@cli/tests/init_worker_workspace_and_typecheck.sh`:
- Around line 1-8: Update the setup script around the workspace cleanup,
directory change, and cargo run command to fail immediately when any command
fails. Enable shell error propagation before these operations so an unsuccessful
mkdir, cd, or cargo run stops the script and prevents later checks from masking
the original failure.

---

Nitpick comments:
In `@cli/tests/init_worker_workspace_and_typecheck.sh`:
- Around line 44-53: Add a runtime change step in
cli/tests/init_worker_workspace_and_typecheck.sh after writing the poisoned
workspace YAML, invoking change application so
render_pnpm_workspace_with_packages in cli/src/change/application.rs executes.
Assert the resulting WORKSPACE_YAML still contains blockExoticSubdeps: false and
no longer contains the known placeholder allowBuilds values.
🪄 Autofix (Beta)

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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 466d9f0d-3b76-4eca-b08f-fcc19f720555

📥 Commits

Reviewing files that changed from the base of the PR and between 8f5ee4c and cdc02b7.

📒 Files selected for processing (4)
  • cli/src/change/application.rs
  • cli/src/core/pnpm_workspace.rs
  • cli/src/release/create.rs
  • cli/tests/init_worker_workspace_and_typecheck.sh

Comment on lines +63 to +78
fn sanitize_allow_builds(pnpm_workspace: &mut PnpmWorkspace) {
let mut allow_builds = pnpm_workspace
.allow_builds
.take()
.unwrap_or_else(default_allow_builds);
for value in allow_builds.values_mut() {
if !matches!(value, Value::Bool(_)) {
*value = Value::Bool(true);
}
}
for dep in ALLOWED_BUILD_DEPENDENCIES {
allow_builds
.entry((*dep).to_string())
.or_insert(Value::Bool(true));
}
pnpm_workspace.allow_builds = Some(allow_builds);

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.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/sh
set -eu

# Identify the pnpm version contract and all placeholder-healing coverage.
rg -n --glob 'package.json' '"packageManager"[[:space:]]*:[[:space:]]*"pnpm@' .
rg -n -C 3 'set this to true or false|sanitize_allow_builds|allowBuilds' \
  cli/src/core/pnpm_workspace.rs cli/tests/init_worker_workspace_and_typecheck.sh

Repository: forklaunch/forklaunch

Length of output: 7381


🏁 Script executed:

#!/bin/sh
set -eu

printf '%s\n' '--- pnpm_workspace.rs ---'
cat -n cli/src/core/pnpm_workspace.rs | sed -n '1,190p'

printf '%s\n' '--- related fixtures and tests ---'
rg -n -C 8 'set this to true or false|allowBuilds|ALLOWED_BUILD_DEPENDENCIES|render_pnpm_workspace' \
  cli tests .github 2>/dev/null || true

printf '%s\n' '--- repository history summary for the target file ---'
git log --oneline -8 -- cli/src/core/pnpm_workspace.rs

Repository: forklaunch/forklaunch

Length of output: 20350


🌐 Web query:

pnpm 11 settings allowBuilds "set this to true or false" placeholder behavior

💡 Result:

In pnpm v11, the allowBuilds setting in pnpm-workspace.yaml serves as a unified mechanism to manage which dependencies are permitted to execute build scripts (such as postinstall) [1][2]. Behavior and Placeholder Logic: - Structure: It is a map where keys are package name patterns (or repository URLs for git dependencies) and values are booleans (true to allow, false to disallow) [1][2]. - Default Security: By default, packages not explicitly listed in allowBuilds are disallowed [1][2]. If a dependency attempts to run a build script without being explicitly permitted, pnpm will print an error (assuming the default strictDepBuilds: true) [1][3]. - Automatic Placeholder Behavior: When pnpm detects a dependency with a build script that is not yet listed in allowBuilds, it automatically updates your pnpm-workspace.yaml file by adding the package with a placeholder value [1][4]. This allows you to inspect the dependency and manually update the entry to true or false based on whether you trust the package to execute its scripts [1][3]. - CLI Interaction: You can manage these settings interactively using the pnpm approve-builds command, which also updates the allowBuilds map in your configuration [4]. Additionally, flags like --allow-build used during pnpm add will write the corresponding entries to this file [1][4]. Migration: The allowBuilds setting replaces several older, now-deprecated configurations, including onlyBuiltDependencies, onlyBuiltDependenciesFile, neverBuiltDependencies, ignoredBuiltDependencies, and ignoreDepScripts [1][3][2]. For further details, refer to the official pnpm settings documentation.

Citations:


Preserve unknown allowBuilds entries as false.

pnpm writes placeholders for unapproved build dependencies. This loop converts every placeholder to true, including entries outside ALLOWED_BUILD_DEPENDENCIES, and permits their build scripts. Add a fixture for an unknown placeholder.

🤖 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 `@cli/src/core/pnpm_workspace.rs` around lines 63 - 78, Update
sanitize_allow_builds so non-boolean placeholders are converted to true only for
dependencies listed in ALLOWED_BUILD_DEPENDENCIES; preserve unknown entries as
false. Add a fixture covering an unknown allowBuilds placeholder and verify it
remains disallowed.

Comment on lines +1 to +8
if [ -d "output/init-worker-workspace" ]; then
rm -rf output/init-worker-workspace
fi

mkdir -p output/init-worker-workspace
cd output/init-worker-workspace

RUST_BACKTRACE=1 cargo run --release init application workspace-test-app -p workspace-test-app -o src/modules -d postgresql -f prettier -l eslint -v zod -F express -r node -t vitest -D "Workspace integrity test application" -A "Forklaunch Team" -L 'MIT'

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.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Stop on setup command failures.

The script continues after a failed cargo run. Later checks can inspect files from an earlier command and hide the failure. An unsuccessful cd can also run subsequent commands in the wrong directory.

Proposed fix
+set -e
+
 if [ -d "output/init-worker-workspace" ]; then
     rm -rf output/init-worker-workspace
 fi
 ...
-cd output/init-worker-workspace
+cd output/init-worker-workspace || exit 1
 ...
-cd workspace-test-app/src/modules
+cd workspace-test-app/src/modules || exit 1

Also applies to: 55-55

🧰 Tools
🪛 Shellcheck (0.11.0)

[warning] 6-6: Use 'cd ... || exit' or 'cd ... || return' in case cd fails.

(SC2164)

🤖 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 `@cli/tests/init_worker_workspace_and_typecheck.sh` around lines 1 - 8, Update
the setup script around the workspace cleanup, directory change, and cargo run
command to fail immediately when any command fails. Enable shell error
propagation before these operations so an unsuccessful mkdir, cd, or cargo run
stops the script and prevents later checks from masking the original failure.

Source: Linters/SAST tools

@RohinBhargava
RohinBhargava merged commit cfed5d1 into main Jul 31, 2026
13 checks passed
@RohinBhargava
RohinBhargava deleted the rohin/scaffold-fixes branch July 31, 2026 19:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant