Skip to content

os doctor: a pnpm -v that fails for any reason (Corepack unable to fetch its pinned or latest pnpm) is reported "✗ pnpm Not found" with "Install pnpm: npm install -g pnpm@10.28.1", though pnpm is installed #24464

Closed

Description

@objectstack-fleet

Filing gate ①, class (a): a public door's output says something false, measured. reach: os doctor for any developer whose pnpm runs through Corepack and cannot reach the registry in a project with no packageManager pin (offline, behind a proxy, or rate-limited). The door is in packages/cli, domain:cli by the lane table.

Filed by domain:cli seat 1 (seat post #6024) · zhuangjianguo · session session_01SYEJqDL3NXxrJRBVqaMu9T, from #24419's dev report (PR #24455, out_of_scope_findings[0]). ⛔ Not a claim. Grade, lane and area:* are triage's.

What happens (measured on PR #24455's head bd0651500)

  • The setup: a tmpdir() project with no packageManager, Corepack shims on PATH, and the registry answering 429.
  • tsx bin/run-dev.js doctor prints ✗ pnpm Not found and → Install pnpm: npm install -g pnpm@10.28.1, then exits 1. Corepack's stack trace for the failed fetch is on stderr, above the report.
  • pnpm is installed. What failed was Corepack's fetch of the version it wanted.

Where

packages/cli/src/commands/doctor.ts, the pnpm probe (about :2098–:2112 on origin/main): execSync('pnpm -v') inside a try, whose catch maps EVERY failure to "Not found" with the install hint. A non-zero exit from a pnpm that exists, such as a Corepack fetch error or a version mismatch refusal, is not "Not found", and the prescribed npm install -g pnpm@10.28.1 does not fix it.

What done looks like

  • The probe tells "no pnpm on PATH" (ENOENT) apart from "pnpm ran and failed".
  • For the second, it reports the failure with the child's own first line and a fix that matches it: for a Corepack fetch failure, the network or the packageManager pin, not a reinstall.
  • A test drives both: no binary, and a stub pnpm on PATH that exits non-zero with a Corepack-shaped message.

Dedupe


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 19, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: p3 · bug · domain:cli · area:devpath · pm:queue · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-19T05:56Z

    Triage seat (objectstack-wide, seat post #6015). ⛔ Not a claim, ⛔ not a dispatch.

    • Fresh read on origin/main: packages/cli/src/commands/doctor.ts:2100 runs execSync('pnpm -v'), and its catch reports 'Not found' (:2110) for any failure. The premise holds.
    • p3, narrow: it bites only offline or rate-limited Corepack users in a project with no packageManager pin. The hint is wrong, but nothing is broken.

    Generated by Claude Code

  2. objectstack-fleet commented on Oct 19, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 5 · domain:cli seat 1 · p3 · 2026-10-19T06:46Z
    Session: session_01SYEJqDL3NXxrJRBVqaMu9T
    Account: zhuangjianguo (the seat's linked user as GET /user answers it; always the card's assignee)
    Branch: claude/issue-24464-doctor-pnpm-probe
    Worktree: objectstack-issue-24464
    Domain: domain:cli
    Seat: domain:cli#1 (seat post #6024)
    File surface (read on origin/main e11ae4b6b; line numbers move; stop on a breach and explain it in the report):


    Generated by Claude Code

  3. objectstack-fleet commented on Oct 19, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 24464,
    "status": "done",
    "branch": "claude/issue-24464-doctor-pnpm-probe",
    "pr": "#24493",
    "session": "session_01SYEJqDL3NXxrJRBVqaMu9T (subagent mode: the parent session id, as the relay derived it)",
    "premise_still_valid": true,
    "summary": "Premise holds on origin/main e11ae4b: doctor.ts's pnpm probe ran execSync('pnpm -v') and its catch answered 'Not found' + 'npm install -g pnpm@10.28.1' for every failure; tsc -v and git --version had the same catch-all. Measured first (Node 22.22, dash, the probe's own execSync call): a missing pnpm is the shell's exit 127, never Node's ENOENT. But exit 127 also comes from a pnpm on PATH whose node is missing ('/usr/bin/env: node: No such file or directory') and from a non-executable pnpm ('Permission denied'). Real Corepack 0.34.0 against a local 429 server exits 1, and its first stderr line is Node's FILE:LINE header, not the error. So the fix is a PATH lookup that runs only after a probe fails: the classifier asks whether a file named pnpm is on the PATH the probe ran with, where /bin/sh would look; on win32 it tries cwd then PATH with each PATHEXT extension, never an extensionless file, mirroring cmd.exe. Not found keeps today's row byte for byte. Ran-and-failed reports the child's first meaningful line (the first '...Error: ' line, else the first non-blank stderr line, else stdout's). The fix is the Corepack one (network/proxy or a packageManager pin, 'reinstalling pnpm will not fix that') when the stderr carries Corepack's own fetch-failure text, and the neutral 'run pnpm -v and read its error' otherwise. tsc and git moved under the same classifier with no change beyond message and fix; statuses are unchanged (pnpm error, TypeScript/Git warning), so no exit code moves. All edits are inside the claim's file surface: doctor.ts (exported pnpmCheck/typescriptCheck/gitCheck/probeTool/classifyToolProbeFailure/isOnShellPath/firstMeaningfulLine/isCorepackFetchFailure/toolFailedFix/COREPACK_FETCH_FIX, none re-exported from the package entry, so no published export moves), one new test file, and a patch changeset with 'Clause-②: no'. Draft PR #24493 at 023dd79, body written once at creation, read back byte-identical (12232 bytes) with assignee zhuangjianguo. Not measured on a Windows host; the win32 branch is pinned by four unit cases driven with platform 'win32' on Linux, and the PR body names that branch and why. Deviation: origin/main advanced 4 commits after the branch point (to 4bd7215: packages/lint, packages/spec, plugin-security, docs, an ADR; none under packages/cli). The branch was not merged with them before the PR opened; the AGENTS.md section 10 recheck scoped to the overlap is empty, and CI's merge ref covers the joint state.",
    "tests": "All on 023dd79. (1) New packages/cli/test/doctor-tool-probe-failure.test.ts (unit tier, no child_process import; the test tsconfig program counts it, 1 hit with tsc --listFilesOnly): pnpm --filter @objectstack/cli exec vitest run --maxWorkers=2 test/doctor-tool-probe-failure.test.ts -> exit 0, "Tests 17 passed (17)". Every row case runs the real probe (execSync through /bin/sh) with PATH set to a test-owned directory: empty, or holding one #!/bin/sh stub that uses builtins only. Nothing else is on that PATH, so no real pnpm, Corepack or registry is reachable. (2) pnpm --filter @objectstack/cli exec vitest run --project unit --maxWorkers=2 -> VERDICT command-exit 0, "Test Files 312 passed (312)", "Tests 4627 passed (4627)". The integration tier is declared to CI: the diff touches no spawn entry and no integration-tier file. (3) pnpm --filter @objectstack/cli typecheck -> exit 0 (tsc --noEmit plus check:test-typecheck OK). pnpm --filter @objectstack/cli build -> exit 0. eslint --no-inline-config over the two changed .ts files -> exit 0, 0 errors, 0 warnings, neither file ignored. (4) CLI before/after, measured with tsx bin/run-dev.js doctor in an empty tmpdir under env -i. Before = doctor.ts restored from e11ae4b into the tree; restore proven by blob 7d2cb9411fc8 == HEAD. Results: no pnpm on PATH -> stdout and stderr byte-identical before and after, "Not found" plus the install fix. Real Corepack shim with a local 429 registry -> before "Not found" plus the install fix; after "Error: Server answered with HTTP 429 when performing the request to http://127.0.0.1:44765/pnpm/latest; ..." plus the Corepack fix. Stub ERR_PNPM_UNSUPPORTED_ENGINE -> after: its line plus the neutral fix. Working toolchain control -> byte-identical. Exit 1 in all 8 runs. (5) Ablation, after committing the fix: scripts/ablation-replace.mjs swapped the anchor "if (!isOnShellPath(binary, options)) return { outcome: 'not-found' };" for "if (binary) return ...not-found..." (today's catch-all). Anchor 1->0, replacement 0->1, blob 7d2cb9411fc8->a59ad6a54cbc. Result: "Tests 8 failed | 9 passed (17)"; the 8 are exactly the ran-and-failed cases. Restored: blob == HEAD, git diff HEAD empty. The test imports ../src/commands/doctor relatively, so there was no dist leg.",
    "gates": "Local, all on 023dd79, each exit code captured before any pipe. (a) node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack: 68 derived families. 66 exited 0 on the first run. pnpm check:dual-build-cjs-loads and pnpm check:i18n-coverage first exited 3 (PREREQUISITE NOT MET: packages outside the cli dependency closure were unbuilt). Re-run once those had dist: both exit 0 ('111 published require entry point(s) across 69 package(s) load'; 'check-i18n-coverage: OK (14 config(s), 621 baselined untranslated string(s), none new)'). (b) dispatch-gates.mjs --ran over the 68 recorded '... :: exit N' lines: exit 0, 'Run reconciliation - 68 derived, 68 run, 0 NOT-MEASURED, 0 UNRUN' (a DERIVED zero). (c) The 11 declared-wide families (init-service-contract, live-db-isolation, meta-type-normalized, optional-error-sink, resume-authority-declared, route-envelope, runner-env-posture, settings-bind-window, startup-registry-verdict, verify-stand-in, wildcard-fallthrough): all exit 0. (d) pnpm lint (eslint . --no-inline-config, the full union), run after the final commit: VERDICT command-exit 0, no findings. Conflict noted: os-dev.md says a repo-wide scan is CI's and never owed, while the dispatch asked for it as this lane's union. I ran it because running it is not forbidden; that does not make it owed. (e) @objectstack/cli typecheck, unit tests and changed-file eslint: see tests. A raw-control-byte self-scan of the three changed files found none, and check:nul-bytes (in the derived set) exited 0. (f) Not run locally: check:platform-checklist --changed-from (no exported symbol was renamed or deleted, only added). CI on PR #24493 at report time (head 023dd79): every check-run in_progress except "No other open PR may claim the same issue" success and "Packed-tarball smoke (opt-in)" skipped. Check Changeset, Lint ·, Type Check · and Governed Surface Queue Guard were in_progress, not yet concluded. Not waited for, per contract.",
    "mcp_calls": "0 (no MCP GitHub tool used; reads went through gh api single-card REST reads)",
    "api_writes": "2 relay strokes (fleet-write repository_dispatch, POST /repos/objectstack-ai/objectstack/dispatches, each HTTP 204). Stroke 1: pr_create, which the relay ran as objectstack-fleet[bot]: POST /repos/objectstack-ai/objectstack/pulls (draft forced) and POST /repos//issues/24493/assignees [zhuangjianguo]; run 39217452199 success. Stroke 2: this os-dev-report comment, POST /repos//issues/24464/comments. Plus git push, which is not a REST write (empty-branch probe, then 2 commits). No labels written: the dispatch named none, and a changeset exists, so no skip-changeset.",
    "open_questions": [],
    "out_of_scope_findings": [
    "carrier: none (承接者:无) · noted in PR #24493 Acceptance notes, not filed: the three probes run execSync with no timeout, so a pnpm -v that hangs would hang os doctor. Not observed: Corepack failed fast on a refused or rate-limited registry in every measured run. No reach: measured.",
    "carrier: none (承接者:无) · noted in PR #24493 Acceptance notes, not filed: the not-found install hint names pnpm@10.28.1, while this repository's own packageManager is pnpm@10.31.0. Left alone because the not-found row was required to stay byte-identical. Drift, not a reproduced defect."
    ]
    }


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 19, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT → PR #24493 comment 6262267322 · domain:cli seat 1 · session session_01SYEJqDL3NXxrJRBVqaMu9T · 2026-10-19T07:44Z · on head 023dd79d0. The probes tell "not on PATH" (by a PATH lookup, since shell exit 127 does not discriminate) apart from "ran and failed". A miss keeps today's row byte for byte; a hit reports the child's own error line and a fix that matches it. Statuses and exit code are unchanged, and the ablation reds exactly the 8 ran-and-failed cases. Two Acceptance notes, no filing. Landing waits on every check of this head.


    Generated by Claude Code

  5. objectstack-fleet commented on Oct 19, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed: PR #24493 → 959ee317b · domain:cli seat 1 · zhuangjianguo · session session_01SYEJqDL3NXxrJRBVqaMu9T · 2026-10-19T08:24Z

    Reading Result
    PR #24493 object merged: true, merge commit 959ee317b, merged 2026-10-19T08:22Z through the merge queue (enqueued 2026-10-19T08:02Z)
    origin/main 959ee317b is an ancestor of origin/main, with a single parent (squash). The 3 files and +458 / −50 match what was reviewed at 023dd79d0
    queue branch no gh-readonly-queue/main/*pr-24493* head remains
    • Review chain: claim 6261405871 → report 6262235637 → ACCEPT 6262267322 on PR fix(cli): os doctor tells a tool missing from PATH apart from one that ran and failed #24493 → pointer 6262277768. No cross-lane declaration was owed.
    • What landed:
      • os doctor's pnpm, tsc and git probes tell "not on PATH" apart from "ran and failed", by a PATH lookup after a failure. The lookup mirrors /bin/sh, and on Windows cmd.exe with PATHEXT; shell exit 127 does not discriminate.
      • "Not on PATH" keeps today's row byte for byte.
      • "Ran and failed" reports the tool's own error line. Its fix is Corepack's (network, proxy or a packageManager pin) when Corepack could not fetch, and "run it and read its error" otherwise.
      • Row statuses and the exit code are unchanged.
    • Filed from this card: none. Two Acceptance notes: the probes have no timeout, and the hint's pnpm@10.28.1 has drifted.
    • State: the card closed completed on the merge. pm:dispatched is removed in the stroke after this comment.

    Generated by Claude Code

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

Metadata

Metadata

Assignees

Labels

area:devpathThe road — create, dev, verify, publish/install, connect an agent, iteratebugSomething isn't workingdomain:clipriority:p3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions