Summary
openclaw doctor can misclassify a source checkout as "not a git checkout" when the CLI is launched through a global npm/pnpm shim whose node_modules/openclaw entry is a Windows junction/symlink to the real repo checkout.
The install is actually source-backed, and openclaw update --dry-run --json correctly reports git mode, but doctor's pre-update offer uses a raw string comparison and shows package-manager guidance instead of offering the git update flow.
Repro shape
- Have a real OpenClaw git checkout.
- Expose it through a global npm/pnpm command shim where the package root is a junction/symlink to that checkout.
- Run
openclaw doctor interactively.
Observed doctor output includes:
This install is not a git checkout.
Run `openclaw update` to update via your package manager (npm/pnpm), then rerun doctor.
But the same environment resolves as a git install through the update command:
{
"installKind": "git",
"mode": "git",
"updateInstallKind": "git",
"actions": [
"Run git update flow on channel dev (fetch/rebase/build/doctor)"
]
}
Root cause
src/commands/doctor-update.ts detects a git checkout with:
return res.stdout.trim() === root ? "git" : "not-git";
On Windows junction/symlink installs, git -C <linked package root> rev-parse --show-toplevel returns the real checkout path, while root can still be the linked global package path. These refer to the same location but are not equal as raw strings.
src/infra/update-runner.ts already handles this class of problem with realpath-style comparison for the update flow, which is why openclaw update --dry-run --json reports git mode correctly.
Expected behavior
Doctor should canonicalize both paths before comparing them. If the install root and git rev-parse --show-toplevel refer to the same filesystem location, doctor should offer:
Update OpenClaw from git before running doctor?
Local proof
A focused local patch that compares canonicalized real paths makes doctor-update detection recognize the junction-backed checkout while preserving the real non-git package-manager guidance.
Validation run:
node scripts/run-vitest.mjs src/commands/doctor-update.test.ts
# Test Files 1 passed (1)
# Tests 2 passed (2)
pnpm oxlint src/commands/doctor-update.ts src/commands/doctor-update.test.ts
# Found 0 warnings and 0 errors.
openclaw update --dry-run --json
# installKind: git
# mode: git
# action: Run git update flow on channel dev (fetch/rebase/build/doctor)
Affected surface
src/commands/doctor-update.ts
- Windows/global npm or pnpm source installs that use a junction/symlink into a git checkout
Summary
openclaw doctorcan misclassify a source checkout as "not a git checkout" when the CLI is launched through a global npm/pnpm shim whosenode_modules/openclawentry is a Windows junction/symlink to the real repo checkout.The install is actually source-backed, and
openclaw update --dry-run --jsoncorrectly reports git mode, but doctor's pre-update offer uses a raw string comparison and shows package-manager guidance instead of offering the git update flow.Repro shape
openclaw doctorinteractively.Observed doctor output includes:
But the same environment resolves as a git install through the update command:
{ "installKind": "git", "mode": "git", "updateInstallKind": "git", "actions": [ "Run git update flow on channel dev (fetch/rebase/build/doctor)" ] }Root cause
src/commands/doctor-update.tsdetects a git checkout with:On Windows junction/symlink installs,
git -C <linked package root> rev-parse --show-toplevelreturns the real checkout path, whilerootcan still be the linked global package path. These refer to the same location but are not equal as raw strings.src/infra/update-runner.tsalready handles this class of problem with realpath-style comparison for the update flow, which is whyopenclaw update --dry-run --jsonreports git mode correctly.Expected behavior
Doctor should canonicalize both paths before comparing them. If the install root and
git rev-parse --show-toplevelrefer to the same filesystem location, doctor should offer:Local proof
A focused local patch that compares canonicalized real paths makes doctor-update detection recognize the junction-backed checkout while preserving the real non-git package-manager guidance.
Validation run:
Affected surface
src/commands/doctor-update.ts