Skip to content

fix(docker): install pnpm for DeepSeek profile - #350

Merged
Ark0N merged 1 commit into
Ark0N:masterfrom
opticon454:bugfix/dsh-pnpm
Aug 31, 2026
Merged

fix(docker): install pnpm for DeepSeek profile#350
Ark0N merged 1 commit into
Ark0N:masterfrom
opticon454:bugfix/dsh-pnpm

Conversation

@opticon454

Copy link
Copy Markdown
Contributor

What

Restore clean builds of the Docker agent base image by installing pnpm and preparing the DeepSeek Harness TUI profile with its required lifecycle-script allow-list.

This preserves Codeman's ability to auto-build codeman/agent:base and then spawn isolated case containers when the base image is not already present.

When

The failure was reproduced on 27 August 2026 against upstream master at 7dfb4acf with a no-cache, pull-enabled build:

docker build --progress=plain --no-cache --pull --file docker/agent.Dockerfile .

The build stopped while adding the DeepSeek TUI profile with exit code 127:

dsh: pnpm not found on PATH — install pnpm to manage profile plugins

Why

@deepseek-ai/dsh delegates profile dependency management to pnpm. The Dockerfile installed the dsh CLI but did not install pnpm, so dsh plugin --profile dsh-tui add ... could not complete.

Because Codeman normally auto-builds this base image on the first isolated Docker case, a clean host could not create its first isolated agent container after the image build failed.

pnpm also controls dependency lifecycle scripts through the profile workspace configuration. The DeepSeek TUI dependency tree requires the @google/genai preinstall and protobufjs postinstall scripts during profile installation.

How

  • Install pnpm alongside @deepseek-ai/dsh as an image build dependency.
  • Initialise the dsh-tui profile with lifecycle scripts disabled.
  • Add a profile-local allowBuilds policy for @google/genai and protobufjs.
  • Add @deepseek-harness-tui/dsh-tui after the policy exists, allowing only those required scripts to run.
  • Retain the existing profile existence and ownership checks.

Validation

  • Confirmed the original no-cache image build fails with the missing-pnpm error.
  • Confirmed the fixed no-cache, pull-enabled image build completes successfully.
  • Confirmed the resulting image runs as the non-root agent user and contains pnpm 11.24.0, dsh 0.1.1-rc.2, and @deepseek-harness-tui/dsh-tui 0.9.3.
  • Confirmed an arbitrary runtime UID can write to the prepared Codeman home directory.
  • npm run typecheck passed.
  • npm run lint passed.
  • npm run format:check passed.
  • npm run check:frontend-syntax passed for all 34 frontend JavaScript files.
  • npm test passed: 6,283 passed and 12 skipped across 318 test files.

Ark0N pushed a commit that referenced this pull request Aug 31, 2026
… gate

Follow-up to #350, which fixed the actual blocker (issue #352): `dsh plugin` is
a thin forwarder that `spawnSync`s a literal `pnpm` with no npm fallback, so an
image without pnpm dies at exit 127 and takes the whole build with it.

That PR also pinned an allowlist of the two packages whose lifecycle scripts
pnpm blocked at the time. Replace it with a policy that cannot go stale: pnpm,
unlike npm, refuses dependency build scripts by default and FAILS the install
over it (`ERR_PNPM_IGNORED_BUILDS`, exit 1, measured on pnpm 11.24), and the
names to allow move between rebuilds because `@deepseek-harness-tui/dsh-tui` is
resolved by dist-tag, not pinned: 0.9.3 pulled `@google/genai` (whose script is
a literal `preinstall: no-op`), 0.10.0-beta.x does not. An allowlist of two
names would have let the next tree break the build the same way. Allowing them
wholesale is also the exposure this image already accepts three layers up,
where `npm install -g` runs the install scripts of every transitive dep of the
five CLIs above with no gate at all.

Also correct a comment in the `/api/deepseek/install-profile` route that
asserted the opposite of what #352 proved ("dsh bundles its own package
manager, so no system pnpm is required"). The route's behavior is already
right: dsh's own "pnpm not found on PATH" stderr reaches the caller as the
OPERATION_FAILED detail, so the UI's "add a terminal profile" button names the
fix. Documented the prerequisite in docs/deepseek-integration.md, and taught
the docker-cases image smoke test about `dsh`/`omp` plus the profile check that
`dsh --version` does NOT cover.
@Ark0N
Ark0N merged commit 7762809 into Ark0N:master Aug 31, 2026
@Ark0N

Ark0N commented Aug 31, 2026

Copy link
Copy Markdown
Owner

Merged, thanks. Your diagnosis was exactly right, and it holds up in the source: dsh plugin is a thin forwarder that spawnSyncs a literal pnpm with no npm fallback, so an image without it dies at exit 127 and takes the whole build with it.

One follow-up landed on top (d5b5f8f). I dropped the install --ignore-scripts + allowBuilds step and moved the policy onto the existing add as --config.dangerouslyAllowAllBuilds=true, for one reason: the two names in that allowlist are already stale. @deepseek-harness-tui/dsh-tui is resolved by dist-tag rather than pinned, and the tree moved under us since 27 August. 0.9.3 pulled @google/genai (whose script is a literal preinstall: no-op); 0.10.0-beta.x does not pull it at all. So the allowlist would have kept protecting against a tree that no longer exists, while the next tree with a different build-script dep broke the build exactly the way yours did. The gate itself is real, measured on pnpm 11.24: a blocked script is ERR_PNPM_IGNORED_BUILDS, exit 1, not a warning.

Verified with a full node scripts/build-agent-image.mjs --no-cache: clean build, all nine CLIs report versions in the image (claude 2.1.252, codex 0.151.0, gemini 0.57.0, opencode 1.18.25, agy 1.1.22, pi 0.84.4, grok 1.0.13, dsh 0.1.1-rc.2, omp 18.0.11), and the dsh-tui profile actually launches and paints under an arbitrary runtime uid with gid 0.

Thanks for the fix and for the write-up, it made this a five-minute confirmation instead of a hunt. Ships in the next release.

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.

2 participants