


























@@ -121,27 +121,44 @@ function expectNoLegacyRuntimeDepsManifest(installRoot: string): void {
121121expect(fs.existsSync(path.join(installRoot, ".openclaw-runtime-deps.json"))).toBe(false);
122122}
123123124-function createNonInteractivePrompter(
125-options: { updateInProgress?: boolean } = {},
124+function createNonInteractiveDoctorPrompter(
125+options: {
126+repair?: boolean;
127+updateInProgress?: boolean;
128+confirmAutoFix?: DoctorPrompter["confirmAutoFix"];
129+} = {},
126130): DoctorPrompter {
131+const shouldRepair = options.repair ?? false;
127132return {
128-shouldRepair: false,
133+ shouldRepair,
129134shouldForce: false,
130135repairMode: {
131-shouldRepair: false,
136+ shouldRepair,
132137shouldForce: false,
133138nonInteractive: true,
134139canPrompt: false,
135140updateInProgress: options.updateInProgress ?? false,
136141},
137142confirm: async () => false,
138-confirmAutoFix: async () => false,
143+confirmAutoFix: options.confirmAutoFix ?? (async () => false),
139144confirmAggressiveAutoFix: async () => false,
140145confirmRuntimeRepair: async () => false,
141146select: async (_params: unknown, fallback: unknown) => fallback,
142147} as DoctorPrompter;
143148}
144149150+function createPlainNonInteractivePrompter(
151+options: { confirmAutoFix?: DoctorPrompter["confirmAutoFix"] } = {},
152+): DoctorPrompter {
153+return createNonInteractiveDoctorPrompter(options);
154+}
155+156+function createNonInteractiveRepairPrompter(
157+options: { updateInProgress?: boolean } = {},
158+): DoctorPrompter {
159+return createNonInteractiveDoctorPrompter({ ...options, repair: true });
160+}
161+145162function createRuntime(options: { logs?: string[]; errors?: string[] } = {}): RuntimeEnv {
146163return {
147164log: (message: unknown) => {
@@ -487,7 +504,7 @@ describe("doctor bundled plugin runtime deps", () => {
487504488505await maybeRepairBundledPluginRuntimeDeps({
489506runtime: createRuntime(),
490-prompter: createNonInteractivePrompter(),
507+prompter: createNonInteractiveRepairPrompter(),
491508packageRoot: root,
492509config: {
493510plugins: { enabled: true },
@@ -501,6 +518,36 @@ describe("doctor bundled plugin runtime deps", () => {
501518expect(installed).toEqual([]);
502519});
503520521+it("does not repair missing runtime deps during plain non-interactive doctor", async () => {
522+const root = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-doctor-bundled-"));
523+writeJson(path.join(root, "package.json"), { name: "openclaw" });
524+writeBundledProviderPlugin(root, "bedrock", ["bedrock"], {
525+"bedrock-only": "1.0.0",
526+});
527+const installed = createInstalledRuntimeDeps();
528+const confirmAutoFix = vi.fn(async () => true);
529+530+await maybeRepairBundledPluginRuntimeDeps({
531+runtime: createRuntime(),
532+prompter: createPlainNonInteractivePrompter({ confirmAutoFix }),
533+packageRoot: root,
534+config: {
535+plugins: {
536+enabled: true,
537+allow: ["bedrock"],
538+entries: { bedrock: { enabled: true } },
539+},
540+},
541+installDeps: (params) => {
542+installed.push(params);
543+materializeRuntimeDeps(params);
544+},
545+});
546+547+expect(installed).toEqual([]);
548+expect(confirmAutoFix).not.toHaveBeenCalled();
549+});
550+504551it("repairs explicitly enabled provider deps", async () => {
505552const root = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-doctor-bundled-"));
506553writeJson(path.join(root, "package.json"), { name: "openclaw" });
@@ -519,7 +566,7 @@ describe("doctor bundled plugin runtime deps", () => {
519566520567await maybeRepairBundledPluginRuntimeDeps({
521568runtime: createRuntime(),
522-prompter: createNonInteractivePrompter(),
569+prompter: createNonInteractiveRepairPrompter(),
523570packageRoot: root,
524571config: {
525572plugins: {
@@ -553,7 +600,7 @@ describe("doctor bundled plugin runtime deps", () => {
553600554601await maybeRepairBundledPluginRuntimeDeps({
555602runtime: createRuntime(),
556-prompter: createNonInteractivePrompter(),
603+prompter: createNonInteractiveRepairPrompter(),
557604packageRoot: root,
558605config: {
559606plugins: { enabled: true },
@@ -588,7 +635,7 @@ describe("doctor bundled plugin runtime deps", () => {
588635589636await maybeRepairBundledPluginRuntimeDeps({
590637runtime: createRuntime(),
591-prompter: createNonInteractivePrompter(),
638+prompter: createNonInteractiveRepairPrompter(),
592639packageRoot: root,
593640config: {
594641plugins: { enabled: true },
@@ -624,15 +671,15 @@ describe("doctor bundled plugin runtime deps", () => {
624671]);
625672});
626673627-it("repairs missing deps during non-interactive doctor", async () => {
674+it("repairs missing deps during doctor --fix --non-interactive", async () => {
628675const root = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-doctor-bundled-"));
629676writeJson(path.join(root, "package.json"), { name: "openclaw" });
630677writeBundledChannelPlugin(root, "telegram", { grammy: "1.37.0" });
631678const installed = createInstalledRuntimeDeps();
632679633680await maybeRepairBundledPluginRuntimeDeps({
634681runtime: createRuntime(),
635-prompter: createNonInteractivePrompter(),
682+prompter: createNonInteractiveRepairPrompter(),
636683packageRoot: root,
637684config: {
638685plugins: { enabled: true },
@@ -659,7 +706,7 @@ describe("doctor bundled plugin runtime deps", () => {
659706expectNoLegacyRuntimeDepsManifest(installRoot);
660707});
661708662-it("repairs a previous incomplete runtime deps install during non-interactive doctor", async () => {
709+it("repairs a previous incomplete runtime deps install during doctor --fix --non-interactive", async () => {
663710const root = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-doctor-bundled-"));
664711writeJson(path.join(root, "package.json"), { name: "openclaw" });
665712writeBundledChannelPlugin(root, "telegram", { grammy: "1.37.0" });
@@ -672,7 +719,7 @@ describe("doctor bundled plugin runtime deps", () => {
672719673720await maybeRepairBundledPluginRuntimeDeps({
674721runtime: createRuntime(),
675-prompter: createNonInteractivePrompter(),
722+prompter: createNonInteractiveRepairPrompter(),
676723packageRoot: root,
677724config: {
678725plugins: { enabled: true },
@@ -701,7 +748,7 @@ describe("doctor bundled plugin runtime deps", () => {
701748702749await maybeRepairBundledPluginRuntimeDeps({
703750runtime: createRuntime({ logs }),
704-prompter: createNonInteractivePrompter(),
751+prompter: createNonInteractiveRepairPrompter(),
705752packageRoot: root,
706753config: {
707754plugins: { enabled: true },
@@ -728,7 +775,7 @@ describe("doctor bundled plugin runtime deps", () => {
728775729776const repair = maybeRepairBundledPluginRuntimeDeps({
730777runtime: createRuntime({ logs }),
731-prompter: createNonInteractivePrompter(),
778+prompter: createNonInteractiveRepairPrompter(),
732779packageRoot: root,
733780config: {
734781plugins: { enabled: true },
@@ -760,7 +807,7 @@ describe("doctor bundled plugin runtime deps", () => {
760807761808const repair = maybeRepairBundledPluginRuntimeDeps({
762809runtime: { error: () => {}, log: () => {} } as never,
763-prompter: createNonInteractivePrompter(),
810+prompter: createNonInteractiveRepairPrompter(),
764811packageRoot: root,
765812config: {
766813plugins: { enabled: true },
@@ -790,7 +837,7 @@ describe("doctor bundled plugin runtime deps", () => {
790837791838await maybeRepairBundledPluginRuntimeDeps({
792839runtime: createRuntime(),
793-prompter: createNonInteractivePrompter(),
840+prompter: createNonInteractiveRepairPrompter(),
794841packageRoot: root,
795842config: {
796843plugins: { enabled: true },
@@ -820,7 +867,7 @@ describe("doctor bundled plugin runtime deps", () => {
820867821868await maybeRepairBundledPluginRuntimeDeps({
822869runtime: createRuntime(),
823-prompter: createNonInteractivePrompter(),
870+prompter: createNonInteractiveRepairPrompter(),
824871packageRoot: root,
825872config: {
826873plugins: {
@@ -851,7 +898,7 @@ describe("doctor bundled plugin runtime deps", () => {
851898await expect(
852899maybeRepairBundledPluginRuntimeDeps({
853900runtime: createRuntime({ errors }),
854-prompter: createNonInteractivePrompter(),
901+prompter: createNonInteractiveRepairPrompter(),
855902packageRoot: root,
856903config: {
857904plugins: { enabled: true },
@@ -876,7 +923,7 @@ describe("doctor bundled plugin runtime deps", () => {
876923877924await maybeRepairBundledPluginRuntimeDeps({
878925runtime: createRuntime(),
879-prompter: createNonInteractivePrompter({ updateInProgress: true }),
926+prompter: createNonInteractiveRepairPrompter({ updateInProgress: true }),
880927packageRoot: root,
881928includeConfiguredChannels: true,
882929config: {
@@ -909,7 +956,7 @@ describe("doctor bundled plugin runtime deps", () => {
909956910957await maybeRepairBundledPluginRuntimeDeps({
911958runtime: createRuntime(),
912-prompter: createNonInteractivePrompter(),
959+prompter: createNonInteractiveRepairPrompter(),
913960 env,
914961packageRoot: root,
915962config: {
@@ -963,7 +1010,7 @@ describe("doctor bundled plugin runtime deps", () => {
96310109641011await maybeRepairBundledPluginRuntimeDeps({
9651012runtime: createRuntime(),
966-prompter: createNonInteractivePrompter(),
1013+prompter: createNonInteractiveRepairPrompter(),
9671014 env,
9681015packageRoot: root,
9691016config: {
@@ -999,7 +1046,7 @@ describe("doctor bundled plugin runtime deps", () => {
999104610001047await maybeRepairBundledPluginRuntimeDeps({
10011048runtime: createRuntime(),
1002-prompter: createNonInteractivePrompter(),
1049+prompter: createNonInteractiveRepairPrompter(),
10031050packageRoot: root,
10041051includeConfiguredChannels: true,
10051052config: {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。