fix(gbrain-detect): a doctor spawn that throws fails closed instead of crashing detect

A JSON-null ~/.gbrain/config.json made spawnGbrain throw, which crashed
detect before Step 1.5's broken-config remediation could run. Step 5
prose now says skill checks never count, matching the code.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
garrytanandcapy-ai[bot] committed 2026-11-01 14:30:53 +00:00
1 parent 0a06cfbb86
commit 077d70fec9
4 files changed
+23 -3

No files matched your search

+7 -1
View File
@@ -145,7 +145,13 @@ interface DoctorVerdict {
}
function runDoctor(extraArgs: string[], timeoutMs: number): DoctorVerdict {
const r = spawnGbrain(["doctor", "--json", ...extraArgs, "--scope=brain"], { timeout: timeoutMs });
let r: ReturnType<typeof spawnGbrain>;
try {
r = spawnGbrain(["doctor", "--json", ...extraArgs, "--scope=brain"], { timeout: timeoutMs });
} catch (e) {
const error = `gbrain doctor could not start: ${e instanceof Error ? e.message : String(e)}`;
return { brain_ok: false, status: null, brain_failures: [], skill_failures: [], report: null, error };
}
let report: { status?: string; checks?: { name?: string; status?: string; category?: string }[] } | null = null;
try {
report = JSON.parse(r.stdout || "null");
+1 -1
View File
@@ -319,7 +319,7 @@ DOCTOR=$(~/.claude/skills/gstack/bin/gstack-gbrain-detect --doctor)
BRAIN_OK=$(echo "$DOCTOR" | jq -r .brain_ok)
```
If `BRAIN_OK` is `true`, proceed; only brain checks count. Note any
If `BRAIN_OK` is `true`, proceed; skill checks never count. Note any
`skill_failures`: gbrain graded a skills dir it found, maybe another agent's
(`~/.openclaw/workspace`). Never edit that workspace to pass. Otherwise show
`echo "$DOCTOR" | jq .` and STOP.
+1 -1
View File
@@ -234,7 +234,7 @@ DOCTOR=$(~/.claude/skills/gstack/bin/gstack-gbrain-detect --doctor)
BRAIN_OK=$(echo "$DOCTOR" | jq -r .brain_ok)
```
If `BRAIN_OK` is `true`, proceed; only brain checks count. Note any
If `BRAIN_OK` is `true`, proceed; skill checks never count. Note any
`skill_failures`: gbrain graded a skills dir it found, maybe another agent's
(`~/.openclaw/workspace`). Never edit that workspace to pass. Otherwise show
`echo "$DOCTOR" | jq .` and STOP.
+14
View File
@@ -150,6 +150,20 @@ describe('gstack-gbrain-detect --doctor', () => {
});
});
describe('gstack-gbrain-detect with a JSON-null gbrain config', () => {
test('still prints detect JSON, and --doctor fails closed with a cause', () => {
const env = { ...caseEnv('all checks pass'), HOME: path.join(tmp, 'null-config-home') };
fs.mkdirSync(path.join(env.HOME, '.gbrain'), { recursive: true });
fs.writeFileSync(path.join(env.HOME, '.gbrain', 'config.json'), 'null');
const detect = spawnSync(DETECT, [], { env, encoding: 'utf-8', timeout: 30_000 });
expect(detect.status).toBe(0);
expect(JSON.parse(detect.stdout).gbrain_doctor_ok).toBe(false);
const doctor = spawnSync(DETECT, ['--doctor'], { env, encoding: 'utf-8', timeout: 30_000 });
expect(doctor.status).toBe(1);
expect(JSON.parse(doctor.stdout).error).toContain('could not start');
});
});
describe('gstack-gbrain-detect gbrain_doctor_ok', () => {
for (const name of Object.keys(CASES)) {
const healthy = HEALTHY.includes(name);