



















@@ -8,6 +8,12 @@ import {
8899const mocks = vi.hoisted(() => ({
1010maybeRunConfiguredPluginInstallReleaseStep: vi.fn(),
11+registerCoreHealthChecks: vi.fn(),
12+registerBundledHealthChecks: vi.fn(),
13+runDoctorHealthRepairs: vi.fn(),
14+listHealthChecks: vi.fn(),
15+resolveAgentWorkspaceDir: vi.fn(() => "/tmp/openclaw-workspace"),
16+resolveDefaultAgentId: vi.fn(() => "default"),
1117note: vi.fn(),
1218replaceConfigFile: vi.fn().mockResolvedValue(undefined),
1319readConfigFileSnapshot: vi.fn().mockResolvedValue({
@@ -26,6 +32,27 @@ vi.mock("../commands/doctor/shared/release-configured-plugin-installs.js", () =>
2632maybeRunConfiguredPluginInstallReleaseStep: mocks.maybeRunConfiguredPluginInstallReleaseStep,
2733}));
283435+vi.mock("./doctor-core-checks.js", () => ({
36+registerCoreHealthChecks: mocks.registerCoreHealthChecks,
37+}));
38+39+vi.mock("./bundled-health-checks.js", () => ({
40+registerBundledHealthChecks: mocks.registerBundledHealthChecks,
41+}));
42+43+vi.mock("./doctor-repair-flow.js", () => ({
44+runDoctorHealthRepairs: mocks.runDoctorHealthRepairs,
45+}));
46+47+vi.mock("./health-check-registry.js", () => ({
48+listHealthChecks: mocks.listHealthChecks,
49+}));
50+51+vi.mock("../agents/agent-scope.js", () => ({
52+resolveAgentWorkspaceDir: mocks.resolveAgentWorkspaceDir,
53+resolveDefaultAgentId: mocks.resolveDefaultAgentId,
54+}));
55+2956vi.mock("../terminal/note.js", () => ({
3057note: mocks.note,
3158}));
@@ -86,6 +113,30 @@ function buildDoctorPrompter(shouldRepair: boolean): DoctorPrompter {
86113describe("doctor health contributions", () => {
87114beforeEach(() => {
88115mocks.maybeRunConfiguredPluginInstallReleaseStep.mockReset();
116+mocks.registerCoreHealthChecks.mockReset();
117+mocks.registerBundledHealthChecks.mockReset();
118+mocks.runDoctorHealthRepairs.mockReset();
119+mocks.runDoctorHealthRepairs.mockResolvedValue({
120+config: {},
121+findings: [],
122+remainingFindings: [],
123+changes: [],
124+warnings: [],
125+diffs: [],
126+effects: [],
127+checksRun: 0,
128+checksRepaired: 0,
129+checksValidated: 0,
130+});
131+mocks.listHealthChecks.mockReset();
132+mocks.listHealthChecks.mockReturnValue([
133+{ id: "core/doctor/shell-completion" },
134+{ id: "core/doctor/unrelated" },
135+]);
136+mocks.resolveAgentWorkspaceDir.mockReset();
137+mocks.resolveAgentWorkspaceDir.mockReturnValue("/tmp/openclaw-workspace");
138+mocks.resolveDefaultAgentId.mockReset();
139+mocks.resolveDefaultAgentId.mockReturnValue("default");
89140mocks.note.mockReset();
90141mocks.readConfigFileSnapshot.mockReset();
91142mocks.readConfigFileSnapshot.mockResolvedValue({
@@ -210,6 +261,27 @@ describe("doctor health contributions", () => {
210261);
211262});
212263264+it("keeps legacy positional shell completion out of the broad structured repair pass", async () => {
265+const contribution = requireDoctorContribution("doctor:structured-health-repairs");
266+const ctx = {
267+cfg: {},
268+configResult: { cfg: {} },
269+sourceConfigValid: true,
270+prompter: buildDoctorPrompter(true),
271+runtime: { log: vi.fn(), error: vi.fn(), exit: vi.fn() },
272+options: {},
273+cfgForPersistence: {},
274+configPath: "/tmp/fake-openclaw.json",
275+env: {},
276+} as Parameters<(typeof contribution)["run"]>[0];
277+278+await contribution.run(ctx);
279+280+expect(mocks.runDoctorHealthRepairs).toHaveBeenCalledWith(expect.any(Object), {
281+checks: [{ id: "core/doctor/unrelated" }],
282+});
283+});
284+213285it("skips doctor config writes under legacy update parents", () => {
214286expect(
215287shouldSkipLegacyUpdateDoctorConfigWrite({
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。