@@ -72,6 +72,7 @@ const mocks = vi.hoisted(() => {
7272 return skillStatusReportFixture ;
7373 } ) ;
7474 return {
75+ callGatewayMock : vi . fn ( ) ,
7576 loadConfigMock : vi . fn ( ( ) => ( { } ) ) ,
7677 resolveDefaultAgentIdMock : vi . fn ( ( _configForTest : unknown ) => "main" ) ,
7778 resolveAgentIdByWorkspacePathMock : vi . fn (
@@ -102,6 +103,7 @@ const mocks = vi.hoisted(() => {
102103} ) ;
103104
104105const {
106+ callGatewayMock,
105107 loadConfigMock,
106108 resolveDefaultAgentIdMock,
107109 resolveAgentIdByWorkspacePathMock,
@@ -169,6 +171,10 @@ vi.mock("../runtime.js", () => ({
169171 defaultRuntime : mocks . defaultRuntime ,
170172} ) ) ;
171173
174+ vi . mock ( "../gateway/call.js" , ( ) => ( {
175+ callGateway : ( ...args : unknown [ ] ) => mocks . callGatewayMock ( ...args ) ,
176+ } ) ) ;
177+
172178vi . mock ( "../utils.js" , async ( importOriginal ) => ( {
173179 ...( await importOriginal < typeof import ( "../utils.js" ) > ( ) ) ,
174180 CONFIG_DIR : "/tmp/openclaw-config" ,
@@ -250,6 +256,7 @@ describe("skills cli commands", () => {
250256 runtimeLogs . length = 0 ;
251257 runtimeStdout . length = 0 ;
252258 runtimeErrors . length = 0 ;
259+ callGatewayMock . mockReset ( ) ;
253260 loadConfigMock . mockReset ( ) ;
254261 resolveDefaultAgentIdMock . mockReset ( ) ;
255262 resolveAgentIdByWorkspacePathMock . mockReset ( ) ;
@@ -268,6 +275,7 @@ describe("skills cli commands", () => {
268275 fetchClawHubSkillCardMock . mockReset ( ) ;
269276 buildWorkspaceSkillStatusMock . mockReset ( ) ;
270277
278+ callGatewayMock . mockRejectedValue ( new Error ( "gateway unavailable" ) ) ;
271279 loadConfigMock . mockReturnValue ( { } ) ;
272280 resolveDefaultAgentIdMock . mockReturnValue ( "main" ) ;
273281 resolveAgentIdByWorkspacePathMock . mockReturnValue ( undefined ) ;
@@ -1195,6 +1203,60 @@ describe("skills cli commands", () => {
11951203 expectStatusWorkspaceCall ( "/tmp/workspace-writer" ) ;
11961204 } ) ;
11971205
1206+ it ( "uses gateway skills.status for read-only status commands when reachable" , async ( ) => {
1207+ routeWorkspaceByAgent ( ) ;
1208+ const gatewayReport = {
1209+ ...skillStatusReportFixture ,
1210+ agentId : "writer" ,
1211+ workspaceDir : "/gateway/workspace-writer" ,
1212+ skills : [
1213+ {
1214+ ...skillStatusReportFixture . skills [ 0 ] ,
1215+ name : "apple-notes" ,
1216+ description : "Notes helpers" ,
1217+ eligible : true ,
1218+ modelVisible : true ,
1219+ commandVisible : true ,
1220+ requirements : {
1221+ bins : [ "memo" ] ,
1222+ anyBins : [ ] ,
1223+ env : [ ] ,
1224+ config : [ ] ,
1225+ os : [ "darwin" ] ,
1226+ } ,
1227+ missing : {
1228+ bins : [ ] ,
1229+ anyBins : [ ] ,
1230+ env : [ ] ,
1231+ config : [ ] ,
1232+ os : [ ] ,
1233+ } ,
1234+ } ,
1235+ ] ,
1236+ } ;
1237+ callGatewayMock . mockResolvedValue ( gatewayReport ) ;
1238+
1239+ await runCommand ( [ "skills" , "check" , "--agent" , "writer" , "--json" ] ) ;
1240+
1241+ expect ( callGatewayMock ) . toHaveBeenCalledWith ( {
1242+ config : { } ,
1243+ method : "skills.status" ,
1244+ params : { agentId : "writer" } ,
1245+ timeoutMs : 1_500 ,
1246+ clientName : "cli" ,
1247+ mode : "cli" ,
1248+ } ) ;
1249+ expect ( buildWorkspaceSkillStatusMock ) . not . toHaveBeenCalled ( ) ;
1250+ const output = JSON . parse ( runtimeStdout . at ( - 1 ) ?? "{}" ) as {
1251+ workspaceDir ?: string ;
1252+ eligible ?: string [ ] ;
1253+ missingRequirements ?: Array < { name : string } > ;
1254+ } ;
1255+ expect ( output . workspaceDir ) . toBe ( "/gateway/workspace-writer" ) ;
1256+ expect ( output . eligible ) . toEqual ( [ "apple-notes" ] ) ;
1257+ expect ( output . missingRequirements ) . toEqual ( [ ] ) ;
1258+ } ) ;
1259+
11981260 it . each ( [
11991261 [ "list" , [ "skills" , "list" , "--agent" , "writer" , "--json" ] ] ,
12001262 [ "info" , [ "skills" , "info" , "calendar" , "--agent" , "writer" , "--json" ] ] ,
0 commit comments