@@ -2188,6 +2188,52 @@ describe("updateNpmInstalledPlugins", () => {
21882188 expect ( result . outcomes [ 0 ] ?. message ) . toBe (
21892189 "Updated openclaw-codex-app-server: unknown -> 0.2.6. (warning: beta channel fallback used openclaw-codex-app-server because openclaw-codex-app-server@beta could not be used)." ,
21902190 ) ;
2191+ expect ( result . outcomes [ 0 ] ?. channelFallback ) . toEqual ( {
2192+ requestedSpec : "openclaw-codex-app-server@beta" ,
2193+ usedSpec : "openclaw-codex-app-server" ,
2194+ requestedLabel : "@beta" ,
2195+ usedLabel : "@latest" ,
2196+ reason : "unavailable" ,
2197+ message :
2198+ "plugin channel fallback: openclaw-codex-app-server used @latest because @beta was unavailable" ,
2199+ } ) ;
2200+ } ) ;
2201+
2202+ it ( "reports npm beta fallback as tentative during dry-run checks" , async ( ) => {
2203+ installPluginFromNpmSpecMock
2204+ . mockResolvedValueOnce ( {
2205+ ok : false ,
2206+ error :
2207+ "npm ERR! code ETARGET\nnpm ERR! No matching version found for openclaw-codex-app-server@beta." ,
2208+ } )
2209+ . mockResolvedValueOnce (
2210+ createSuccessfulNpmUpdateResult ( {
2211+ pluginId : "openclaw-codex-app-server" ,
2212+ targetDir : "/tmp/openclaw-codex-app-server" ,
2213+ version : "0.2.6" ,
2214+ npmResolution : {
2215+ name : "openclaw-codex-app-server" ,
2216+ version : "0.2.6" ,
2217+ resolvedSpec :
"[email protected] " , 2218+ } ,
2219+ } ) ,
2220+ ) ;
2221+
2222+ const result = await updateNpmInstalledPlugins ( {
2223+ config : createCodexAppServerInstallConfig ( {
2224+ spec : "openclaw-codex-app-server" ,
2225+ } ) ,
2226+ pluginIds : [ "openclaw-codex-app-server" ] ,
2227+ updateChannel : "beta" ,
2228+ dryRun : true ,
2229+ } ) ;
2230+
2231+ expect ( result . outcomes [ 0 ] ?. message ) . toBe (
2232+ "Would update openclaw-codex-app-server: unknown -> 0.2.6. (warning: beta channel fallback would use openclaw-codex-app-server because openclaw-codex-app-server@beta could not be used)." ,
2233+ ) ;
2234+ expect ( result . outcomes [ 0 ] ?. channelFallback ?. message ) . toBe (
2235+ "plugin channel fallback: openclaw-codex-app-server would use @latest because @beta was unavailable" ,
2236+ ) ;
21912237 } ) ;
21922238
21932239 it ( "falls back to the default npm spec when the beta package exists but is invalid" , async ( ) => {
@@ -2233,6 +2279,12 @@ describe("updateNpmInstalledPlugins", () => {
22332279 expect ( result . outcomes [ 0 ] ?. message ) . toBe (
22342280 "Updated openclaw-codex-app-server: unknown -> 0.2.6. (warning: beta channel fallback used openclaw-codex-app-server because openclaw-codex-app-server@beta could not be used)." ,
22352281 ) ;
2282+ expect ( result . outcomes [ 0 ] ?. channelFallback ) . toMatchObject ( {
2283+ requestedLabel : "@beta" ,
2284+ usedLabel : "@latest" ,
2285+ reason : "failed" ,
2286+ message : "plugin channel fallback: openclaw-codex-app-server used @latest after @beta failed" ,
2287+ } ) ;
22362288 } ) ;
22372289
22382290 it ( "reports the fallback npm spec when beta fallback also fails" , async ( ) => {
@@ -2262,6 +2314,55 @@ describe("updateNpmInstalledPlugins", () => {
22622314 status : "error" ,
22632315 message :
22642316 "Failed to update openclaw-codex-app-server: npm package not found for openclaw-codex-app-server." ,
2317+ channelFallback : {
2318+ requestedSpec : "openclaw-codex-app-server@beta" ,
2319+ usedSpec : "openclaw-codex-app-server" ,
2320+ requestedLabel : "@beta" ,
2321+ usedLabel : "@latest" ,
2322+ reason : "failed" ,
2323+ message :
2324+ "plugin channel fallback: openclaw-codex-app-server used @latest after @beta failed" ,
2325+ } ,
2326+ } ,
2327+ ] ) ;
2328+ } ) ;
2329+
2330+ it ( "keeps fallback metadata when a dry-run beta fallback also fails" , async ( ) => {
2331+ installPluginFromNpmSpecMock
2332+ . mockResolvedValueOnce ( {
2333+ ok : false ,
2334+ error : "Installed plugin package uses a TypeScript entry without compiled runtime output." ,
2335+ } )
2336+ . mockResolvedValueOnce ( {
2337+ ok : false ,
2338+ code : "npm_package_not_found" ,
2339+ error : "npm package not found" ,
2340+ } ) ;
2341+
2342+ const result = await updateNpmInstalledPlugins ( {
2343+ config : createCodexAppServerInstallConfig ( {
2344+ spec : "openclaw-codex-app-server" ,
2345+ } ) ,
2346+ pluginIds : [ "openclaw-codex-app-server" ] ,
2347+ updateChannel : "beta" ,
2348+ dryRun : true ,
2349+ } ) ;
2350+
2351+ expect ( result . outcomes ) . toEqual ( [
2352+ {
2353+ pluginId : "openclaw-codex-app-server" ,
2354+ status : "error" ,
2355+ message :
2356+ "Failed to check openclaw-codex-app-server: npm package not found for openclaw-codex-app-server." ,
2357+ channelFallback : {
2358+ requestedSpec : "openclaw-codex-app-server@beta" ,
2359+ usedSpec : "openclaw-codex-app-server" ,
2360+ requestedLabel : "@beta" ,
2361+ usedLabel : "@latest" ,
2362+ reason : "failed" ,
2363+ message :
2364+ "plugin channel fallback: openclaw-codex-app-server would use @latest after @beta failed" ,
2365+ } ,
22652366 } ,
22662367 ] ) ;
22672368 } ) ;
0 commit comments