From f8e4595914b566fe1c18f0d600cc141e185ae109 Mon Sep 17 00:00:00 2001 From: Brandon Lipman Date: Wed, 6 May 2026 13:10:15 -0400 Subject: [PATCH] fix(doctor): use autoDetectSkillsDir so OpenClaw workspaces are reachable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `gbrain doctor` was the only consumer of `findRepoRoot` from `core/repo-root.ts`. Every other consumer (check-resolvable.ts:145, skillify.ts, etc.) uses `autoDetectSkillsDir`, which has the full detection chain: 1. \$OPENCLAW_WORKSPACE 2. ~/.openclaw/workspace 3. findRepoRoot() walk from cwd 4. ./skills `findRepoRoot` only does step 3. Result: when the user runs `gbrain doctor` from any directory outside the gbrain repo or the OpenClaw workspace tree (e.g., a project's checkout), `resolver_health` reports "Could not find skills directory" even though the dispatcher exists at ~/.openclaw/workspace/skills/RESOLVER.md. Reproduces in any directory other than ~/gbrain or its descendants on a system with ~/.openclaw/workspace/skills/RESOLVER.md present: \$ cd ~/Documents \$ gbrain doctor [WARN] resolver_health: Could not find skills directory # before [WARN] resolver_health: 5 issue(s): 0 error(s), 5 warning(s) # after Switching doctor to `autoDetectSkillsDir` brings it inline with the rest of the codebase. The detected dir is also passed to `checkSkillConformance` (step 2 of the resolver_health block), which previously rebuilt the path from `repoRoot` — now uses the same detected path for consistency. All 15 existing tests in test/doctor.test.ts continue to pass. --- src/commands/doctor.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/commands/doctor.ts b/src/commands/doctor.ts index 03aec0820..0895bf916 100644 --- a/src/commands/doctor.ts +++ b/src/commands/doctor.ts @@ -3,7 +3,7 @@ import * as db from '../core/db.ts'; import { LATEST_VERSION, getIdleBlockers } from '../core/migrate.ts'; import { checkResolvable } from '../core/check-resolvable.ts'; import { autoFixDryViolations, type AutoFixReport, type FixOutcome } from '../core/dry-fix.ts'; -import { findRepoRoot } from '../core/repo-root.ts'; +import { autoDetectSkillsDir } from '../core/repo-root.ts'; import { loadCompletedMigrations } from '../core/preferences.ts'; import { compareVersions } from './migrations/index.ts'; import { createProgress, startHeartbeat, type ProgressReporter } from '../core/progress.ts'; @@ -59,9 +59,12 @@ export async function runDoctor(engine: BrainEngine | null, args: string[], dbSo // --- Filesystem checks (always run, no DB needed) --- // 1. Resolver health - const repoRoot = findRepoRoot(); - if (repoRoot) { - const skillsDir = join(repoRoot, 'skills'); + // Use the same auto-detect as `check-resolvable` so doctor sees a + // workspace/skills dir reachable via $OPENCLAW_WORKSPACE or + // ~/.openclaw/workspace, not just a `skills/` walked up from cwd. + const detected = autoDetectSkillsDir(); + const skillsDir = detected.dir; + if (skillsDir) { // --fix: run auto-repair BEFORE checkResolvable so the post-fix scan // reflects the new state. Auto-fix only targets DRY violations today; @@ -99,8 +102,7 @@ export async function runDoctor(engine: BrainEngine | null, args: string[], dbSo } // 2. Skill conformance - if (repoRoot) { - const skillsDir = join(repoRoot, 'skills'); + if (skillsDir) { const conformanceResult = checkSkillConformance(skillsDir); checks.push(conformanceResult); }