@@ -3,6 +3,8 @@ import os from "node:os";
33import path from "node:path" ;
44import { describe , expect , it } from "vitest" ;
55import { scanBundledPluginRuntimeDeps } from "../plugins/bundled-runtime-deps.js" ;
6+ import { maybeRepairBundledPluginRuntimeDeps } from "./doctor-bundled-plugin-runtime-deps.js" ;
7+ import type { DoctorPrompter } from "./doctor-prompter.js" ;
68
79function writeJson ( filePath : string , value : unknown ) {
810 fs . mkdirSync ( path . dirname ( filePath ) , { recursive : true } ) ;
@@ -117,6 +119,28 @@ describe("doctor bundled plugin runtime deps", () => {
117119 expect ( result . conflicts ) . toEqual ( [ ] ) ;
118120 } ) ;
119121
122+ it ( "can include disabled but configured bundled channel deps for doctor recovery" , ( ) => {
123+ const root = fs . mkdtempSync ( path . join ( os . tmpdir ( ) , "openclaw-doctor-bundled-" ) ) ;
124+ writeJson ( path . join ( root , "package.json" ) , { name : "openclaw" } ) ;
125+ writeBundledChannelPlugin ( root , "telegram" , { "telegram-only" : "1.0.0" } ) ;
126+
127+ const result = scanBundledPluginRuntimeDeps ( {
128+ packageRoot : root ,
129+ includeConfiguredChannels : true ,
130+ config : {
131+ plugins : { enabled : true } ,
132+ channels : {
133+ telegram : { enabled : false , botToken : "123:abc" } ,
134+ } ,
135+ } ,
136+ } ) ;
137+
138+ expect ( result . missing . map ( ( dep ) => `${ dep . name } @${ dep . version } ` ) ) . toEqual ( [
139+ 140+ ] ) ;
141+ expect ( result . conflicts ) . toEqual ( [ ] ) ;
142+ } ) ;
143+
120144 it ( "reports default-enabled bundled plugin deps" , ( ) => {
121145 const root = fs . mkdtempSync ( path . join ( os . tmpdir ( ) , "openclaw-doctor-bundled-" ) ) ;
122146 writeJson ( path . join ( root , "package.json" ) , { name : "openclaw" } ) ;
@@ -143,4 +167,47 @@ describe("doctor bundled plugin runtime deps", () => {
143167 ] ) ;
144168 expect ( result . conflicts ) . toEqual ( [ ] ) ;
145169 } ) ;
170+
171+ it ( "repairs missing deps during non-interactive doctor" , async ( ) => {
172+ const root = fs . mkdtempSync ( path . join ( os . tmpdir ( ) , "openclaw-doctor-bundled-" ) ) ;
173+ writeJson ( path . join ( root , "package.json" ) , { name : "openclaw" } ) ;
174+ writeBundledChannelPlugin ( root , "telegram" , { grammy : "1.37.0" } ) ;
175+ const installed : Array < { installRoot : string ; missingSpecs : string [ ] } > = [ ] ;
176+ const prompter = {
177+ shouldRepair : false ,
178+ shouldForce : false ,
179+ repairMode : {
180+ shouldRepair : false ,
181+ shouldForce : false ,
182+ nonInteractive : true ,
183+ canPrompt : false ,
184+ updateInProgress : false ,
185+ } ,
186+ confirm : async ( ) => false ,
187+ confirmAutoFix : async ( ) => false ,
188+ confirmAggressiveAutoFix : async ( ) => false ,
189+ confirmRuntimeRepair : async ( ) => false ,
190+ select : async ( _params : unknown , fallback : unknown ) => fallback ,
191+ } as DoctorPrompter ;
192+
193+ await maybeRepairBundledPluginRuntimeDeps ( {
194+ runtime : { error : ( ) => { } } as never ,
195+ prompter,
196+ packageRoot : root ,
197+ config : {
198+ plugins : { enabled : true } ,
199+ channels : { telegram : { enabled : true } } ,
200+ } ,
201+ installDeps : ( params ) => {
202+ installed . push ( params ) ;
203+ } ,
204+ } ) ;
205+
206+ expect ( installed ) . toEqual ( [
207+ {
208+ installRoot : root ,
209+ missingSpecs :
[ "[email protected] " ] , 210+ } ,
211+ ] ) ;
212+ } ) ;
146213} ) ;
0 commit comments