Skip to content

chore(package): migrate to pnpm workspace and update Docker contexts - #520

Closed
l1ttps wants to merge 2 commits into
mainfrom
chore/migrate-npm-to-pnpm
Closed

l1ttps wants to merge 2 commits into
mainfrom
chore/migrate-npm-to-pnpm

Conversation

@l1ttps

@l1ttps l1ttps commented Jul 7, 2026

Copy link
Copy Markdown
Member

Summary by CodeRabbit

  • Chores
    • Standardized installs/builds on pnpm across the project, including updated container build pipelines for the console and core API.
    • Adjusted CI workflows to use pnpm, workspace-aware filters, and refined path triggers.
    • Expanded ignore rules and added workspace configuration and package manager metadata.
  • Bug Fixes
    • Improved TypeScript handling in the core API’s MCP message streaming boundaries.
    • Fixed Docker build contexts so images reliably include the intended files and produce the correct output locations.

@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 823535e1-5e7c-42d9-95d3-20693701011e

📥 Commits

Reviewing files that changed from the base of the PR and between 080abed and d7976cb.

📒 Files selected for processing (5)
  • .github/workflows/check-lint.yml
  • .github/workflows/check-test.yml
  • .github/workflows/frontend-tests.yml
  • console/Dockerfile
  • core-api/Dockerfile

📝 Walkthrough

Walkthrough

This PR migrates the repo to pnpm-based workspace, Docker, task, and CI flows, while updating ignore rules and removing redundant MCP transport type casts.

Changes

pnpm Workspace Migration

Layer / File(s) Summary
pnpm workspace and root configuration
pnpm-workspace.yaml, .npmrc, package.json, .dockerignore, .gitignore
Adds pnpm workspace settings and package manager pinning, and expands ignore rules for build, cache, and console-generated artifacts.
Dockerfile migration to pnpm
console/Dockerfile, core-api/Dockerfile
Reworks both service images to install and build with pnpm and updated runtime artifact locations.
CI workflow migration to pnpm and docker context updates
docker-compose.yml, .github/workflows/*
Changes Docker build contexts and switches build, lint, test, and release/nightly workflows to pnpm-based commands and filters.
Taskfile command migration
taskfile.yml, console/taskfile.yml, core-api/taskfile.yml
Replaces npm/npx task commands with pnpm and pnpm exec across root and service task definitions.
Package scripts and dependency updates
console/package.json
Updates console scripts and adds the leaflet dependency.

MCP Service Type Casting Cleanup

Layer / File(s) Summary
Remove redundant type casts
core-api/src/mcp/mcp.service.ts
Removes node:http type imports and passes request/response objects directly to the MCP transport calls.

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

Possibly related PRs

🚥 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 accurately summarizes the main change: migrating to a pnpm workspace and updating Docker build contexts.
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 unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch chore/migrate-npm-to-pnpm

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 7

🧹 Nitpick comments (1)
pnpm-workspace.yaml (1)

5-20: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicate build-approval config: onlyBuiltDependencies and allowBuilds list the same packages.

Both settings encode the identical package list. allowBuilds is the newer, preferred mechanism (added in pnpm 10.26) and fully replaces onlyBuiltDependencies, which pnpm v11 removes entirely (silently ignored if present). Keeping both is redundant and creates a maintenance burden — any future package added to one list but not the other could cause inconsistent behavior depending on the pnpm version resolved by CI/dev machines.

♻️ Suggested consolidation (keep only allowBuilds)
 packages:
   - 'core-api'
   - 'console'

-onlyBuiltDependencies:
-  - '`@scarf/scarf`'
-  - '`@swc/core`'
-  - 'esbuild'
-  - 'grpc-tools'
-  - 'msgpackr-extract'
-  - 'msw'
-  - 'protobufjs'
 allowBuilds:
   '`@scarf/scarf`': true
   '`@swc/core`': true
   esbuild: true
   grpc-tools: true
   msgpackr-extract: true
   msw: true
   protobufjs: true

Since the actual pnpm version pin (packageManager field in package.json) isn't in the reviewed files, please confirm which pnpm major version this repo targets to ensure onlyBuiltDependencies isn't simply dead/ignored config.

🤖 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 `@pnpm-workspace.yaml` around lines 5 - 20, The workspace config duplicates the
same build-approval package list in both onlyBuiltDependencies and allowBuilds,
so consolidate the settings in pnpm-workspace.yaml by keeping only allowBuilds
and removing onlyBuiltDependencies. Make sure the package set stays identical
under allowBuilds for all entries currently listed, and verify the repo’s pnpm
target version before deleting the legacy key if needed.
🤖 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 @.github/workflows/check-lint.yml:
- Around line 36-51: The lint workflow step is passing --filter to the lint
script instead of to pnpm, so the command runs at the root package and misses
the service-specific script. Update the run command in the workflow to scope
pnpm first, using the same matrix.service value with pnpm --filter before run
lint, so the existing lint script is executed in the intended package.

In @.github/workflows/check-test.yml:
- Around line 28-29: The Checkout code step in the workflow leaves git
credentials persisted, which can expose the GITHUB_TOKEN later in the job.
Update the actions/checkout usage in the check-test workflow to explicitly
disable credential persistence by setting persist-credentials to false on the
Checkout code step so the repository config does not retain the token after
checkout.
- Around line 23-46: The test step is passing --filter as an argument to the
test script instead of scoping pnpm to the core-api workspace, so it still
resolves the root package’s test script. Update the Run tests step in the
check-test workflow to apply pnpm’s filter before the run command, using the
existing core-api filter target so the workspace test script is executed
correctly.

In @.github/workflows/frontend-tests.yml:
- Around line 20-33: The frontend test workflow is passing `--filter` to the
script instead of pnpm, so the `test:run` and `test:coverage` commands are
resolved from the root package instead of the `console` package. Update the
workflow commands in the frontend tests job to use pnpm’s filter flag before
`run`, and keep the same `test:run` and `test:coverage` script names so they
execute in the `console` workspace.

In `@console/Dockerfile`:
- Around line 15-20: The frozen workspace install in the console Docker build is
missing the core-api workspace manifest, so pnpm cannot resolve the full
workspace consistently. Update the Dockerfile copy step used before the pnpm
install --frozen-lockfile command to include core-api/package.json alongside
console/package.json, keeping the workspace manifests in sync for the install
stage.

In `@core-api/Dockerfile`:
- Around line 37-42: The runtime stage in the Dockerfile is only copying the
workspace root node_modules, but core-api’s direct dependency links live under
the package-local node_modules tree. Update the Dockerfile near the existing
COPY steps for the runtime image so the core-api package-local node_modules are
also included alongside dist, public, and proto, or otherwise make the image
self-contained the same way the builder resolves dependencies.
- Around line 15-20: The Dockerfile install step is missing the workspace
package needed by pnpm, which can make the frozen install fail due to a
workspace mismatch. Update the COPY block before `pnpm install
--frozen-lockfile` in the `core-api/Dockerfile` so the `console` workspace is
included as well, or adjust the workspace context to only include `core-api`;
use the existing `COPY pnpm-lock.yaml pnpm-workspace.yaml package.json .npmrc
./` and `COPY core-api/package.json ./core-api/package.json` section as the
location to fix.

---

Nitpick comments:
In `@pnpm-workspace.yaml`:
- Around line 5-20: The workspace config duplicates the same build-approval
package list in both onlyBuiltDependencies and allowBuilds, so consolidate the
settings in pnpm-workspace.yaml by keeping only allowBuilds and removing
onlyBuiltDependencies. Make sure the package set stays identical under
allowBuilds for all entries currently listed, and verify the repo’s pnpm target
version before deleting the legacy key if needed.
🪄 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 Plus

Run ID: c72f4f2f-219e-49ab-b8f5-fa3dd51623b7

📥 Commits

Reviewing files that changed from the base of the PR and between 7613114 and 080abed.

⛔ Files ignored due to path filters (3)
  • console/pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • package-lock.json is excluded by !**/package-lock.json
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (19)
  • .dockerignore
  • .github/workflows/build-nightly.yml
  • .github/workflows/build-release.yml
  • .github/workflows/check-build.yml
  • .github/workflows/check-lint.yml
  • .github/workflows/check-test.yml
  • .github/workflows/frontend-tests.yml
  • .gitignore
  • .npmrc
  • console/Dockerfile
  • console/package.json
  • console/taskfile.yml
  • core-api/Dockerfile
  • core-api/src/mcp/mcp.service.ts
  • core-api/taskfile.yml
  • docker-compose.yml
  • package.json
  • pnpm-workspace.yaml
  • taskfile.yml

Comment on lines +36 to +51
- name: Install pnpm
uses: pnpm/action-setup@v6
with:
version: 11

- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: '22'
cache: 'npm'
cache-dependency-path: package-lock.json
cache: 'pnpm'

- name: Install dependencies
run: npm ci --ignore-scripts
run: pnpm install --frozen-lockfile

- name: Run lint
run: npm run lint --workspace=${{ matrix.service }}
run: pnpm run lint --filter=${{ matrix.service }}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== workflow ==\n'
sed -n '1,120p' .github/workflows/check-lint.yml

printf '\n== package manifests ==\n'
for f in core-api/package.json console/package.json; do
  if [ -f "$f" ]; then
    echo "-- $f"
    sed -n '1,80p' "$f"
  else
    echo "-- missing: $f"
  fi
done

Repository: oasm-platform/open-asm

Length of output: 6823


🏁 Script executed:

#!/bin/bash
set -euo pipefail

if command -v pnpm >/dev/null 2>&1; then
  printf '\n== pnpm version ==\n'
  pnpm --version

  printf '\n== pnpm run help excerpt ==\n'
  pnpm run --help | sed -n '1,220p'
else
  echo "pnpm not installed in this environment"
fi

Repository: oasm-platform/open-asm

Length of output: 10220


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== root package.json ==\n'
if [ -f package.json ]; then
  sed -n '1,120p' package.json
else
  echo "missing package.json"
fi

printf '\n== pnpm docs excerpt (local help) ==\n'
pnpm help run | sed -n '1,180p'

Repository: oasm-platform/open-asm

Length of output: 11014


🌐 Web query:

pnpm run options listed after the script's name are passed to the executed script --filter after script name

💡 Result:

In pnpm, options listed after a script's name are passed directly to the executed script, while options for the pnpm run command itself must be placed before the script's name [1][2]. Regarding your specific question about the --filter flag: the --filter option is a command-level option used to restrict which packages a command runs on [3][4]. Because it is a pnpm command-level option, it must be placed before the script name to be parsed by pnpm [4]. If you place --filter after the script name (e.g., pnpm run <script> --filter ), pnpm will not interpret it as a filtering instruction for the command [5]. Instead, it will pass the --filter argument directly to the script you are executing, which may cause the script to fail if it does not recognize that argument [1][2][5]. To correctly use filtering with a script, structure your command as follows: pnpm --filter <package_selector> run <script_name> This ensures the filter is applied to the pnpm command, and any additional arguments intended for your script can then be appended after the script name [2].

Citations:


Move --filter before run
pnpm run lint --filter=${{ matrix.service }} forwards --filter to the lint script instead of scoping pnpm, so this step resolves to the root package and fails because the root package.json has no lint script. Use pnpm --filter=${{ matrix.service }} run lint instead.

Proposed fix
-        run: pnpm run lint --filter=${{ matrix.service }}
+        run: pnpm --filter=${{ matrix.service }} run lint
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- name: Install pnpm
uses: pnpm/action-setup@v6
with:
version: 11
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: '22'
cache: 'npm'
cache-dependency-path: package-lock.json
cache: 'pnpm'
- name: Install dependencies
run: npm ci --ignore-scripts
run: pnpm install --frozen-lockfile
- name: Run lint
run: npm run lint --workspace=${{ matrix.service }}
run: pnpm run lint --filter=${{ matrix.service }}
- name: Install pnpm
uses: pnpm/action-setup@v6
with:
version: 11
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: '22'
cache: 'pnpm'
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Run lint
run: pnpm --filter=${{ matrix.service }} run lint
🤖 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 @.github/workflows/check-lint.yml around lines 36 - 51, The lint workflow
step is passing --filter to the lint script instead of to pnpm, so the command
runs at the root package and misses the service-specific script. Update the run
command in the workflow to scope pnpm first, using the same matrix.service value
with pnpm --filter before run lint, so the existing lint script is executed in
the intended package.

Comment on lines 23 to +46
jobs:
test:
name: Check Test
runs-on: ubuntu-latest
defaults:
run:
working-directory: core-api
steps:
- name: Checkout code
uses: actions/checkout@v5

- name: Install pnpm
uses: pnpm/action-setup@v6
with:
version: 11

- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: '22'
cache: 'npm'
cache: 'pnpm'

- name: Install dependencies
run: npm ci --ignore-scripts
working-directory: core-api
run: pnpm install --frozen-lockfile

- name: Run tests
run: npm run test
working-directory: core-api
run: pnpm run test --filter core-api

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== Files ==\n'
git ls-files .github/workflows/check-test.yml .github/workflows/check-lint.yml || true

printf '\n== check-test.yml ==\n'
sed -n '1,220p' .github/workflows/check-test.yml

printf '\n== check-lint.yml ==\n'
sed -n '1,220p' .github/workflows/check-lint.yml

printf '\n== Search for working-directory and filter usage ==\n'
rg -n "defaults\.run\.working-directory|--filter|pnpm run test|pnpm --filter" .github/workflows

Repository: oasm-platform/open-asm

Length of output: 2589


🌐 Web query:

pnpm run options listed after the script's name are passed to the executed script --filter before run documentation

💡 Result:

In pnpm, command-line arguments and options placed after the script name are passed directly to the executed script [1][2]. Any options intended for the pnpm CLI itself must be placed before the script name [1][2]. Regarding the --filter option: 1. Placement: The --filter option is a pnpm CLI option used to restrict commands to specific subsets of packages in a workspace [3][4]. Because it is an option for the pnpm CLI, it must be placed before the script's name (or before the run command itself) to be correctly parsed and executed [5][2]. 2. Syntax: The correct structure for using a filter with a run command is: pnpm --filter <package_selector> run <script_name> [args_for_script] Placing --filter after the script name would result in it being passed as an argument to the script itself, rather than being interpreted by pnpm as a workspace filtering command [1][2].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path

for path in [Path('.github/workflows/check-test.yml'), Path('.github/workflows/check-lint.yml')]:
    print(f'## {path}')
    if path.exists():
        for i, line in enumerate(path.read_text().splitlines(), 1):
            if 'defaults.run.working-directory' in line or '--filter' in line or 'pnpm run test' in line or 'pnpm --filter' in line:
                print(f'{i}: {line}')
    else:
        print('missing')
PY

Repository: oasm-platform/open-asm

Length of output: 343


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== root package.json ==\n'
sed -n '1,220p' package.json

printf '\n== core-api package.json ==\n'
sed -n '1,220p' core-api/package.json

printf '\n== workspace package list ==\n'
find . -maxdepth 2 -name package.json -not -path './node_modules/*' | sort

Repository: oasm-platform/open-asm

Length of output: 5370


Use pnpm’s filter before run

pnpm run test --filter core-api doesn’t scope the workspace; --filter is forwarded as a script arg, so pnpm still looks for test in the root package. Since the root has no test script, this step fails instead of running core-api tests.

Proposed fix
-        run: pnpm run test --filter core-api
+        run: pnpm --filter core-api run test
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
jobs:
test:
name: Check Test
runs-on: ubuntu-latest
defaults:
run:
working-directory: core-api
steps:
- name: Checkout code
uses: actions/checkout@v5
- name: Install pnpm
uses: pnpm/action-setup@v6
with:
version: 11
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: '22'
cache: 'npm'
cache: 'pnpm'
- name: Install dependencies
run: npm ci --ignore-scripts
working-directory: core-api
run: pnpm install --frozen-lockfile
- name: Run tests
run: npm run test
working-directory: core-api
run: pnpm run test --filter core-api
jobs:
test:
name: Check Test
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v5
- name: Install pnpm
uses: pnpm/action-setup@v6
with:
version: 11
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: '22'
cache: 'pnpm'
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Run tests
run: pnpm --filter core-api run test
🧰 Tools
🪛 zizmor (1.26.1)

[warning] 28-29: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)

🤖 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 @.github/workflows/check-test.yml around lines 23 - 46, The test step is
passing --filter as an argument to the test script instead of scoping pnpm to
the core-api workspace, so it still resolves the root package’s test script.
Update the Run tests step in the check-test workflow to apply pnpm’s filter
before the run command, using the existing core-api filter target so the
workspace test script is executed correctly.

Comment on lines 28 to 29
- name: Checkout code
uses: actions/checkout@v5

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Checkout doesn't disable credential persistence.

zizmor flags this checkout for artifact credential persistence (artipacked): persist-credentials: false isn't set, so the GITHUB_TOKEN remains in the local git config for the rest of the job.

🛡️ Proposed fix
       - name: Checkout code
         uses: actions/checkout@v5
+        with:
+          persist-credentials: false
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- name: Checkout code
uses: actions/checkout@v5
- name: Checkout code
uses: actions/checkout@v5
with:
persist-credentials: false
🧰 Tools
🪛 zizmor (1.26.1)

[warning] 28-29: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)

🤖 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 @.github/workflows/check-test.yml around lines 28 - 29, The Checkout code
step in the workflow leaves git credentials persisted, which can expose the
GITHUB_TOKEN later in the job. Update the actions/checkout usage in the
check-test workflow to explicitly disable credential persistence by setting
persist-credentials to false on the Checkout code step so the repository config
does not retain the token after checkout.

Source: Linters/SAST tools

Comment on lines +20 to +33

- name: Install pnpm
uses: pnpm/action-setup@v6
with:
version: 11

- uses: actions/setup-node@v6
with:
node-version: '22'
cache: 'npm'
cache-dependency-path: package-lock.json
cache: 'pnpm'

- run: npm ci
- run: npm run test:run --workspace=console
- run: npm run test:coverage --workspace=console
- run: pnpm install --frozen-lockfile
- run: pnpm run test:run --filter console
- run: pnpm run test:coverage --filter console

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'Workflow excerpt:\n'
sed -n '1,120p' .github/workflows/frontend-tests.yml

printf '\nRelevant package scripts:\n'
git ls-files '**/package.json' | while read -r f; do
  if rg -n '"test:run"|"test:coverage"' "$f" >/dev/null; then
    printf '\n--- %s ---\n' "$f"
    rg -n '"test:run"|"test:coverage"|"name"' "$f"
  fi
done

printf '\nSearch for pnpm filter usage in workflows:\n'
rg -n "pnpm .*--filter|--filter .*pnpm|pnpm run .*--filter" .github . -g '!**/node_modules/**'

Repository: oasm-platform/open-asm

Length of output: 1690


🏁 Script executed:

#!/bin/bash
set -euo pipefail

node - <<'JS'
const {spawnSync} = require('child_process');
function run(args){
  const r = spawnSync('pnpm', args, {encoding:'utf8'});
  console.log(`$ pnpm ${args.join(' ')}`);
  console.log('exit', r.status);
  if (r.stdout) console.log('stdout:\n' + r.stdout.trim());
  if (r.stderr) console.log('stderr:\n' + r.stderr.trim());
  console.log('---');
}
run(['--version']);
JS

Repository: oasm-platform/open-asm

Length of output: 203


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'Workspace config:\n'
sed -n '1,120p' pnpm-workspace.yaml

printf '\nRoot package scripts:\n'
if [ -f package.json ]; then
  rg -n '"test:run"|"test:coverage"|"scripts"' package.json
  sed -n '1,140p' package.json
fi

printf '\npnpm run help excerpts:\n'
pnpm help run | sed -n '1,220p'

Repository: oasm-platform/open-asm

Length of output: 11361


🌐 Web query:

pnpm run --filter after script name forwarded to script pnpm CLI documentation

💡 Result:

In pnpm, any options or arguments provided after the script name are passed directly to the executed script, not to the pnpm CLI [1][2]. If you intend to use pnpm-specific flags—such as --filter, --parallel, or --stream—you must place them before the script name or before the run command itself [1][3][2][4]. For example, if you want to run a script named build with a filter, the command should be structured as follows: pnpm --filter <package_selector> run build Alternatively, you can place the pnpm flags before the run subcommand: pnpm run --filter <package_selector> build If you place these flags after the script name (e.g., pnpm run build --filter <package_selector>), pnpm will attempt to pass those arguments to the build script itself rather than using them to configure the pnpm execution [3][4]. This behavior was standardized in pnpm v7 to ensure that all arguments following the script name are treated as part of the script's own arguments [3][5][4].

Citations:


Move --filter before run

pnpm run test:run --filter console and pnpm run test:coverage --filter console pass --filter to vitest, so pnpm still looks for those scripts in the root package.json and the job fails. Use pnpm --filter console run test:run and pnpm --filter console run test:coverage instead.

🤖 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 @.github/workflows/frontend-tests.yml around lines 20 - 33, The frontend test
workflow is passing `--filter` to the script instead of pnpm, so the `test:run`
and `test:coverage` commands are resolved from the root package instead of the
`console` package. Update the workflow commands in the frontend tests job to use
pnpm’s filter flag before `run`, and keep the same `test:run` and
`test:coverage` script names so they execute in the `console` workspace.

Comment thread console/Dockerfile
Comment on lines +15 to +20
# Copy root workspace config and console package.json
COPY pnpm-lock.yaml pnpm-workspace.yaml package.json .npmrc ./
COPY console/package.json ./console/package.json

ENV NODE_ENV production
# Install all dependencies
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Inspect the actual workspace membership and .npmrc settings
cat pnpm-workspace.yaml
echo "---"
cat .npmrc
echo "---"
# Confirm whether core-api/package.json (or others) is required for a frozen install at /app
fd -HI 'package.json' -d 2

Repository: oasm-platform/open-asm

Length of output: 648


Copy the core-api manifest before the frozen workspace install

pnpm-workspace.yaml includes both core-api and console, but this stage only copies console/package.json before pnpm install --frozen-lockfile. Add core-api/package.json as well so the workspace install resolves consistently.

🤖 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 `@console/Dockerfile` around lines 15 - 20, The frozen workspace install in the
console Docker build is missing the core-api workspace manifest, so pnpm cannot
resolve the full workspace consistently. Update the Dockerfile copy step used
before the pnpm install --frozen-lockfile command to include
core-api/package.json alongside console/package.json, keeping the workspace
manifests in sync for the install stage.

Comment thread core-api/Dockerfile
Comment on lines +15 to +20
# Copy root workspace config and core-api package.json
COPY pnpm-lock.yaml pnpm-workspace.yaml package.json .npmrc ./
COPY core-api/package.json ./core-api/package.json

# Install all dependencies (including devDependencies for build)
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== Files ==\n'
git ls-files core-api/Dockerfile .npmrc pnpm-workspace.yaml pnpm-lock.yaml package.json core-api/package.json || true

printf '\n== core-api/Dockerfile (lines 1-120) ==\n'
cat -n core-api/Dockerfile | sed -n '1,120p'

printf '\n== pnpm-workspace.yaml ==\n'
cat -n pnpm-workspace.yaml

printf '\n== root package.json ==\n'
cat -n package.json

printf '\n== core-api/package.json ==\n'
cat -n core-api/package.json

printf '\n== .npmrc ==\n'
cat -n .npmrc

printf '\n== Workspace member references in lockfile ==\n'
python3 - <<'PY'
from pathlib import Path
import re

text = Path('pnpm-lock.yaml').read_text()
# Print top-level importer keys and package refs that mention core-api or other workspaces.
importers = re.findall(r'^ {2}([^:\n]+):\n', text, flags=re.M)
print("importers:", importers[:20])
for needle in ['core-api', 'console']:
    hits = [m.start() for m in re.finditer(re.escape(needle), text)]
    print(f"{needle}: {len(hits)} hits")
PY

Repository: oasm-platform/open-asm

Length of output: 9221


🌐 Web query:

pnpm workspace install missing package.json workspace globs frozen-lockfile behavior

💡 Result:

In pnpm, the --frozen-lockfile flag is designed to ensure that the installed dependencies exactly match the pnpm-lock.yaml file without modification [1]. When using a workspace, this flag enforces consistency between the lockfile and the package manifests (package.json files) across the entire monorepo [2][3]. Behavior and Constraints: 1. Consistency Enforcement: If the pnpm-lock.yaml is not synchronized with any package.json within the workspace (including changes to dependencies, devDependencies, or workspace catalog definitions), pnpm will throw an ERR_PNPM_OUTDATED_LOCKFILE error and fail the installation [2][3][4]. 2. Workspace Glob/Catalog Mismatches: A known limitation is that while --frozen-lockfile checks for standard dependency mismatches, it may not always detect if workspace-specific configurations (such as pnpm-workspace.yaml catalogs) are out of sync with the lockfile, potentially allowing installs to proceed even when the catalog definitions have drifted from the lockfile [5]. 3. Common Failure Causes: - Dependency Drift: Manually editing package.json files or resolving git merge conflicts in the lockfile without running a full pnpm install [5]. - Version/Setting Mismatch: Using different pnpm versions or configuration settings (e.g., auto-install-peers) between the machine that generated the lockfile and the machine running the CI install [4]. - Workspace Settings: Mismatches in critical workspace settings (e.g., injectWorkspacePackages) between the workspace configuration and the lockfile will trigger an ERR_PNPM_LOCKFILE_CONFIG_MISMATCH [6]. 4. Recommended CI Workaround: In environments where you must update the lockfile (e.g., after using tools like Changesets), the standard practice is to run pnpm install --no-frozen-lockfile to regenerate the lockfile, commit the changes, and ensure subsequent CI runs use --frozen-lockfile [2]. If you are performing pruned installs for specific projects within a workspace, ensure the pruning process correctly handles all dependency types (dependencies, devDependencies, etc.) to avoid false-positive mismatches [3].

Citations:


🌐 Web query:

pnpm missing workspace package.json absent workspace member install behavior pnpm-workspace.yaml

💡 Result:

In a pnpm workspace, a directory must contain a valid package manifest (such as package.json) to be recognized as an active workspace package [1][2]. If a directory is identified as part of the workspace via pnpm-workspace.yaml but lacks a package.json, pnpm generally does not treat it as a package, which can lead to specific behavioral issues [1]. Key behaviors when a package.json is missing or a directory is misconfigured within a workspace include: 1. Installation Ambiguity: If you attempt to run pnpm install or pnpm add in a directory that is part of the workspace but lacks a package.json, pnpm may trigger a warning or error [1]. Specifically, if you try to add a dependency in such a directory, pnpm may attempt to add the package to the workspace root instead, as it does not recognize the current directory as a valid package context [1]. 2. Workspace Detection: pnpm automatically searches upward for the nearest pnpm-workspace.yaml file to define the workspace context [3]. If a directory falls within the pattern defined in pnpm-workspace.yaml but lacks its own package.json, pnpm will not consider it a workspace member project [1]. 3. Workarounds: If you need to include a directory in the workspace that does not contain code dependencies (e.g., for tooling or scripts), the standard solution is to run pnpm init in that directory to generate a minimal package.json [1]. 4. "Active" Workspace Conflict: If you run pnpm commands in a directory that is technically outside the workspace (e.g., excluded in pnpm-workspace.yaml) but contains a package.json, pnpm may still mistakenly attempt to link it to the parent workspace or default to workspace-level behavior [4][5]. To treat such a directory as a standalone project, you can use the --ignore-workspace flag [4][5]. In summary, pnpm relies on the presence of a manifest file (package.json, package.yaml, or package.json5) to identify active projects [1][2]. Directories without these files are not treated as packages, which often leads to errors or unintended installation behavior when attempting to manage dependencies within them [1].

Citations:


🌐 Web query:

pnpm frozen-lockfile workspace importer missing package.json pnpm-lock.yaml ERR_PNPM_OUTDATED_LOCKFILE

💡 Result:

The error ERR_PNPM_OUTDATED_LOCKFILE occurs when the pnpm-lock.yaml file is not synchronized with the package.json files in your project or workspace [1]. When using the --frozen-lockfile flag (often the default in CI/CD environments), pnpm prevents installation if the lockfile requires updates to match the current dependencies, ensuring deterministic builds [1][2]. Common causes and solutions include: 1. Uncommitted Changes: If package.json files were modified (e.g., adding or updating dependencies) but the corresponding changes to pnpm-lock.yaml were not generated or committed, the lockfile becomes stale [1][3]. - Solution: Run pnpm install locally to regenerate the lockfile, then commit the updated pnpm-lock.yaml [3][4]. 2. CI/CD Environment Issues: In CI pipelines, --frozen-lockfile is typically enabled to prevent accidental lockfile changes. If your build process involves automated dependency updates (e.g., using tools like Changesets), the build may fail because the lockfile is now outdated [5]. - Solution: Run pnpm install --no-frozen-lockfile to allow pnpm to update the lockfile during the build, or perform an update locally before pushing to the repository [5][4]. 3. Workspace/Submodule Configuration: In complex setups like git submodules or nested workspaces, pnpm may struggle to resolve the correct root or scope, leading to synchronization errors [2][6]. - Solution: Ensure all package.json files in the workspace are correctly referenced. In some scenarios, using the --merge-git-branch-lockfiles flag can help if working with multiple branch-specific lockfiles [2]. 4. Auto-install Peers: Changes in peer dependency settings (e.g., auto-install-peers being enabled) between pnpm versions can sometimes cause discrepancies between the lockfile and package.json [7][8]. - Solution: Verify if toggling auto-install-peers or updating your pnpm version resolves the discrepancy [7]. If you are certain your dependencies are correct, the most reliable fix is to regenerate the lockfile locally and ensure it is included in your source control [3][4].

Citations:


🌐 Web query:

pnpm lockfile importers missing workspace package.json frozen-lockfile console workspace

💡 Result:

The issue of missing workspace package entries in the importers section of a pnpm-lock.yaml file—often resulting in failures when running pnpm install --frozen-lockfile—typically stems from how pnpm handles workspace projects with no dependencies or specific monorepo orchestration tools (like Turborepo or Nx) that manipulate the lockfile [1][2][3]. ### Why importers entries go missing In a pnpm workspace, the importers section of the lockfile tracks the dependencies for every package within the workspace [4]. * Empty Importers: Historically, if a workspace package has zero dependencies, pnpm might omit its entry from the importers section of the lockfile [1]. However, pnpm install --frozen-lockfile expects every defined workspace package to have a corresponding entry in the lockfile, leading to errors if it is absent [1]. * Build Tool Interference: Tools like Turborepo or Nx, which often perform "lockfile pruning" (creating a subset of the lockfile for specific deployments), have previously struggled with correctly preserving or backfilling these empty entries [1][2][3]. If a tool fails to include these "empty" importers during pruning, the resulting lockfile becomes inconsistent with the actual package.json files, triggering ERR_PNPM_OUTDATED_LOCKFILE or similar errors [1][3]. ### Troubleshooting and Resolutions If you encounter this error in a CI/CD environment or local development, consider the following approaches: 1. Update Tools: If you are using monorepo orchestration tools (e.g., Turborepo, Nx), ensure they are updated to the latest versions. Recent patches (such as those in Turborepo [1] and Nx [2]) have specifically addressed the "backfilling" of missing empty workspace importers to ensure compatibility with frozen-lockfile requirements. 2. Verify Workspace Definitions: Ensure that your pnpm-workspace.yaml correctly lists all packages. If a package is listed in package.json but not properly integrated into the workspace or if its dependencies are inconsistently defined, pnpm may fail to generate the correct lockfile entries [5]. 3. Force Re-generation: If the lockfile is corrupted or out of sync, the standard solution is to delete the pnpm-lock.yaml file and regenerate it by running pnpm install. This forces pnpm to re-scan the workspace and reconstruct the importers block correctly [6]. 4. Check for Partial Dependency Handling: If using tools that prune the lockfile, ensure they are configured to include all dependency types (dependencies, devDependencies, peerDependencies, etc.). Known issues have occurred where workspace packages were ignored by pruning tools if they were only listed in devDependencies [3]. If the error persists after regenerating the lockfile, it may indicate a deeper issue with the workspace configuration or a bug in the specific pnpm version being used. Ensure your environment uses consistent pnpm versions across all developer machines and CI pipelines [7].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== pnpm-lock.yaml importers block ==\n'
python3 - <<'PY'
from pathlib import Path
text = Path('pnpm-lock.yaml').read_text().splitlines()
start = None
for i, line in enumerate(text):
    if line.strip() == 'importers:':
        start = i
        break
if start is None:
    print('importers block not found')
    raise SystemExit(0)

for line in text[start:start+120]:
    print(line)
PY

printf '\n== importer headings by line number ==\n'
rg -n '^(  [^[:space:]].*:)$$' pnpm-lock.yaml | sed -n '1,40p'

Repository: oasm-platform/open-asm

Length of output: 7452


🌐 Web query:

pnpm extra importers in lockfile missing workspace package hard mismatch frozen-lockfile

💡 Result:

The error "extra importers in lockfile" combined with "workspace package hard mismatch" and "frozen-lockfile" failures typically points to issues where a tool (such as an Nx or Turborepo prune executor) has generated an inconsistent or incomplete pnpm-lock.yaml file [1][2][3]. When you run pnpm install --frozen-lockfile, pnpm validates the lockfile against the manifest (package.json) files in your workspace [4]. A "hard mismatch" or "outdated lockfile" error during this process usually occurs because the pruning process stripped necessary information or failed to update references correctly [1][2]. Common causes include: 1. Incomplete Pruning: Tools like nx prune-lockfile or turborepo prune may incorrectly exclude workspace packages or transitive dependencies from the importers or packages sections of the lockfile [1][2][3]. If a workspace package is referenced in a package.json (e.g., via workspace:* specifiers) but is missing from the lockfile's importer snapshots, pnpm will fail to resolve the dependency during a frozen install [1][2]. 2. Specifier Mismatch: Pruning tools often rewrite workspace:* specifiers to file: or link: protocol paths to support deployment [1]. If the tool fails to update the lockfile to match these rewritten paths in the package.json, pnpm encounters a mismatch between the manifest and the lockfile [1][2]. 3. Dependency Type Oversight: Some pruning implementations only inspect dependencies sections and ignore devDependencies, peerDependencies, or optionalDependencies [2]. If your workspace package is listed in these other sections, the pruned lockfile will lack the necessary entries [2]. To resolve these issues: - Verify the pruning tool configuration: Ensure you are using the latest version of your build tool (Nx, Turbo, etc.), as these bugs are frequently patched in releases [1][3]. - Manual Verification: If the tool produces a broken lockfile, check the importers section in pnpm-lock.yaml for the specific workspace package reported in the error [5][6]. Ensure its entry exists and matches the dependency declaration in the generated package.json [2]. - Use --no-frozen-lockfile for debugging: If you are in a CI/CD pipeline, temporarily allow pnpm to regenerate the lockfile to see if it resolves the missing entries, then compare the result with your pruned version to identify what was erroneously stripped [4]. - Workspace Protocol: Ensure all workspace dependencies are correctly resolved within your workspace [4]. If you are using pnpm features like catalogs, overrides, or patchedDependencies, ensure your environment configuration (e.g., pnpm-workspace.yaml) is correctly copied and present in the build container [7][8][9].

Citations:


Copy the missing workspace manifest before pnpm install --frozen-lockfile
pnpm-workspace.yaml includes console, and the lockfile has a console importer. With only core-api/package.json copied here, the frozen install can fail on a workspace mismatch. Copy console/package.json too, or prune the workspace to core-api only.

🤖 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 `@core-api/Dockerfile` around lines 15 - 20, The Dockerfile install step is
missing the workspace package needed by pnpm, which can make the frozen install
fail due to a workspace mismatch. Update the COPY block before `pnpm install
--frozen-lockfile` in the `core-api/Dockerfile` so the `console` workspace is
included as well, or adjust the workspace context to only include `core-api`;
use the existing `COPY pnpm-lock.yaml pnpm-workspace.yaml package.json .npmrc
./` and `COPY core-api/package.json ./core-api/package.json` section as the
location to fix.

Comment thread core-api/Dockerfile
Comment on lines +37 to 42
WORKDIR /app/core-api

COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/public ./public
COPY --from=builder /app/core-api/dist ./dist
COPY --from=builder /app/core-api/public ./public
COPY --from=builder /tmp/proto ./proto

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
cat .npmrc
echo "---"
grep -n "node-linker\|hoist" .npmrc pnpm-workspace.yaml 2>/dev/null

Repository: oasm-platform/open-asm

Length of output: 262


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n## core-api/Dockerfile\n'
cat -n core-api/Dockerfile | sed -n '1,220p'

printf '\n## root package.json\n'
cat -n package.json | sed -n '1,240p'

printf '\n## core-api package.json\n'
cat -n core-api/package.json | sed -n '1,240p'

printf '\n## pnpm-workspace.yaml\n'
cat -n pnpm-workspace.yaml | sed -n '1,200p'

printf '\n## files mentioning node_modules copy in Dockerfiles\n'
rg -n --glob 'Dockerfile' 'node_modules|pnpm|core-api' .

Repository: oasm-platform/open-asm

Length of output: 9624


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n## core-api/Dockerfile\n'
cat -n core-api/Dockerfile | sed -n '1,220p'

printf '\n## root package.json\n'
cat -n package.json | sed -n '1,240p'

printf '\n## core-api package.json\n'
cat -n core-api/package.json | sed -n '1,240p'

printf '\n## pnpm-workspace.yaml\n'
cat -n pnpm-workspace.yaml | sed -n '1,200p'

printf '\n## any pnpm deploy/install hints\n'
rg -n --glob 'Dockerfile' --glob '*.md' --glob 'package.json' --glob '.npmrc' 'pnpm deploy|pnpm install|node-linker|shamefully-hoist|public-hoist|hoist' .

Repository: oasm-platform/open-asm

Length of output: 8592


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n## core-api/Dockerfile\n'
cat -n core-api/Dockerfile | sed -n '1,220p'

printf '\n## package.json files\n'
for f in package.json core-api/package.json; do
  printf '\n### %s\n' "$f"
  cat -n "$f" | sed -n '1,240p'
done

printf '\n## lockfile/workspace hints\n'
rg -n --glob 'pnpm-lock.yaml' --glob 'pnpm-workspace.yaml' --glob '.npmrc' --glob 'core-api/Dockerfile' \
  'pnpm install|pnpm deploy|node_modules|shamefully-hoist|public-hoist|hoist|workspace' .

Repository: oasm-platform/open-asm

Length of output: 8497


Include core-api’s package-local node_modules in the runtime image. The production stage only copies /app/node_modules, but this pnpm workspace install leaves core-api’s direct-dependency symlinks under /app/core-api/node_modules. With no hoist config in .npmrc, node dist/main.js can hit Cannot find module unless the package-local tree is copied too or the image is built via a self-contained deploy step.

🤖 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 `@core-api/Dockerfile` around lines 37 - 42, The runtime stage in the
Dockerfile is only copying the workspace root node_modules, but core-api’s
direct dependency links live under the package-local node_modules tree. Update
the Dockerfile near the existing COPY steps for the runtime image so the
core-api package-local node_modules are also included alongside dist, public,
and proto, or otherwise make the image self-contained the same way the builder
resolves dependencies.

- Remove explicit version from pnpm/action-setup in lint, test, and frontend workflows
  - Action auto-detects version from package.json's packageManager field
  - Fixes 'Multiple versions of pnpm specified' error
- Replace bare 'corepack enable' with 'npm install -g corepack && corepack enable' in Dockerfiles
  - node:26-alpine does not bundle corepack
  - Fixes 'corepack: not found' in Docker builds
@l1ttps l1ttps closed this Jul 7, 2026
@l1ttps
l1ttps deleted the chore/migrate-npm-to-pnpm branch July 20, 2026 17:16
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