@@ -289,30 +289,76 @@ describe("SkillInstaller.getSupportedPlatforms", () => {
289289 expect ( typeof p . rootDir . win32 ) . toBe ( "string" ) ;
290290 expect ( typeof p . rootDir . linux ) . toBe ( "string" ) ;
291291 expect ( typeof p . skillsRelativePath ) . toBe ( "string" ) ;
292- }
293- } ) ;
292+ }
293+ } ) ;
294+ } ) ;
295+
296+ describe ( "SkillInstaller.scanRemoteGithub" , ( ) => {
297+ it ( "accepts HTTPS Gitea URLs (not just SSH)" , async ( ) => {
298+ await SkillInstaller . init ( ) ;
294299
295- it ( "platform IDs are unique" , ( ) => {
296- const ids = SkillInstaller . getSupportedPlatforms ( ) . map ( ( p ) => p . id ) ;
297- expect ( new Set ( ids ) . size ) . toBe ( ids . length ) ;
300+ vi . spyOn ( skillInstallerUtils , "gitClone" ) . mockResolvedValue ( undefined ) ;
301+ vi . spyOn ( SkillInstaller , "scanLocalPreview" ) . mockResolvedValue ( [
302+ {
303+ name : "gitea-skill" ,
304+ description : "A skill from Gitea" ,
305+ version : "1.0.0" ,
306+ author : "icelemon" ,
307+ tags : [ "gitea" ] ,
308+ instructions : "# Gitea skill\n\nContent" ,
309+ filePath : "/tmp/gitea-skill/SKILL.md" ,
310+ localPath : "/tmp/gitea-skill" ,
311+ platforms : [ "claude" ] ,
312+ protocol_type : "skill" ,
313+ } ,
314+ ] ) ;
315+
316+ const result = await SkillInstaller . scanRemoteGithub (
317+ "https://gitea.example.com/icelemon/skills" ,
318+ [ ] ,
319+ ) ;
320+
321+ expect ( result ) . toHaveLength ( 1 ) ;
322+ expect ( result [ 0 ] . slug ) . toBe ( "gitea-skill" ) ;
323+ expect ( result [ 0 ] . author ) . toBe ( "icelemon" ) ;
324+ expect ( skillInstallerUtils . gitClone ) . toHaveBeenCalled ( ) ;
298325 } ) ;
299326
300- it ( "includes Kilo Code instead of Roo Code" , ( ) => {
301- const platforms = SkillInstaller . getSupportedPlatforms ( ) ;
302- expect ( platforms . some ( ( platform ) => platform . id === "kilo" ) ) . toBe ( true ) ;
303- expect ( platforms . some ( ( platform ) => platform . id === "roo" ) ) . toBe ( false ) ;
304-
305- const kilo = platforms . find ( ( platform ) => platform . id === "kilo" ) ;
306- expect ( kilo ) . toMatchObject ( {
307- name : "Kilo Code" ,
308- rootDir : {
309- darwin : "~/.kilo" ,
310- win32 : "%USERPROFILE%\\.kilo" ,
311- linux : "~/.kilo" ,
327+ it ( "accepts SSH Gitea URLs" , async ( ) => {
328+ await SkillInstaller . init ( ) ;
329+
330+ vi . spyOn ( skillInstallerUtils , "gitClone" ) . mockResolvedValue ( undefined ) ;
331+ vi . spyOn ( SkillInstaller , "scanLocalPreview" ) . mockResolvedValue ( [
332+ {
333+ name : "ssh-skill" ,
334+ description : "SSH skill" ,
335+ version : "1.0.0" ,
336+ author : "owner" ,
337+ tags : [ "ssh" ] ,
338+ instructions : "# SSH skill" ,
339+ filePath : "/tmp/ssh-skill/SKILL.md" ,
340+ localPath : "/tmp/ssh-skill" ,
341+ platforms : [ "claude" ] ,
342+ protocol_type : "skill" ,
312343 } ,
313- skillsRelativePath : "skills" ,
314- } ) ;
344+ ] ) ;
345+
346+ const result = await SkillInstaller . scanRemoteGithub (
347+ "git@gitea.example.com:icelemon/skills.git" ,
348+ [ ] ,
349+ ) ;
350+
351+ expect ( result ) . toHaveLength ( 1 ) ;
352+ expect ( result [ 0 ] . slug ) . toBe ( "ssh-skill" ) ;
315353 } ) ;
354+
355+ it ( "rejects invalid git repository URLs" , async ( ) => {
356+ await SkillInstaller . init ( ) ;
357+
358+ await expect (
359+ SkillInstaller . scanRemoteGithub ( "not-a-url" , [ ] ) ,
360+ ) . rejects . toThrow ( "Invalid git repository URL" ) ;
361+ } ) ;
316362} ) ;
317363
318364describe ( "SkillInstaller.copyRepoByPathToDirectory" , ( ) => {
0 commit comments