Skip to content
This repository was archived by the owner on Dec 17, 2025. It is now read-only.

Commit 7eb294f

Browse files
committed
Add Cursor support
- Skills work via a rules file and mcp server autoinstalled - Multiple clients are now supported - Lots of internal refactoring
1 parent ba42fed commit 7eb294f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+3793
-775
lines changed

cmd/skills/main.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,21 @@ import (
77

88
"github.com/sleuth-io/skills/internal/autoupdate"
99
"github.com/sleuth-io/skills/internal/buildinfo"
10+
"github.com/sleuth-io/skills/internal/clients"
11+
"github.com/sleuth-io/skills/internal/clients/claude_code"
12+
"github.com/sleuth-io/skills/internal/clients/cursor"
1013
"github.com/sleuth-io/skills/internal/commands"
1114
"github.com/sleuth-io/skills/internal/git"
1215
"github.com/sleuth-io/skills/internal/logger"
1316
"github.com/spf13/cobra"
1417
)
1518

19+
func init() {
20+
// Register all clients
21+
clients.Register(claude_code.NewClient())
22+
clients.Register(cursor.NewClient()) // TODO: Uncomment after thorough testing
23+
}
24+
1625
func main() {
1726
// Log command invocation
1827
log := logger.Get()
@@ -56,6 +65,7 @@ from remote Sleuth servers or Git repositories.`,
5665
rootCmd.AddCommand(commands.NewUpdateTemplatesCommand())
5766
rootCmd.AddCommand(commands.NewUpdateCommand())
5867
rootCmd.AddCommand(commands.NewReportUsageCommand())
68+
rootCmd.AddCommand(commands.NewServeCommand())
5969

6070
if err := rootCmd.Execute(); err != nil {
6171
os.Exit(1)

go.mod

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ require (
66
github.com/BurntSushi/toml v1.5.0
77
github.com/Masterminds/semver/v3 v3.4.0
88
github.com/creativeprojects/go-selfupdate v1.5.1
9-
github.com/gen2brain/beeep v0.11.1
109
github.com/gofrs/flock v0.13.0
1110
github.com/google/uuid v1.6.0
11+
github.com/modelcontextprotocol/go-sdk v1.1.0
1212
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c
1313
github.com/schollz/progressbar/v3 v3.18.0
1414
github.com/spf13/cobra v1.10.1
@@ -17,31 +17,24 @@ require (
1717

1818
require (
1919
code.gitea.io/sdk/gitea v0.22.0 // indirect
20-
git.sr.ht/~jackmordaunt/go-toast v1.1.2 // indirect
2120
github.com/42wim/httpsig v1.2.3 // indirect
2221
github.com/davidmz/go-pageant v1.0.2 // indirect
23-
github.com/esiqveland/notify v0.13.3 // indirect
2422
github.com/go-fed/httpsig v1.1.0 // indirect
25-
github.com/go-ole/go-ole v1.3.0 // indirect
26-
github.com/godbus/dbus/v5 v5.2.0 // indirect
2723
github.com/google/go-github/v30 v30.1.0 // indirect
2824
github.com/google/go-querystring v1.1.0 // indirect
25+
github.com/google/jsonschema-go v0.3.0 // indirect
2926
github.com/hashicorp/go-cleanhttp v0.5.2 // indirect
3027
github.com/hashicorp/go-retryablehttp v0.7.8 // indirect
3128
github.com/hashicorp/go-version v1.7.0 // indirect
3229
github.com/inconshreveable/mousetrap v1.1.0 // indirect
33-
github.com/jackmordaunt/icns/v3 v3.0.1 // indirect
3430
github.com/kr/text v0.2.0 // indirect
3531
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect
36-
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect
3732
github.com/rivo/uniseg v0.4.7 // indirect
3833
github.com/rogpeppe/go-internal v1.14.1 // indirect
39-
github.com/sergeymakinen/go-bmp v1.0.0 // indirect
40-
github.com/sergeymakinen/go-ico v1.0.0 // indirect
4134
github.com/spf13/pflag v1.0.10 // indirect
42-
github.com/tadvi/systray v0.0.0-20190226123456-11a2b8fa57af // indirect
4335
github.com/ulikunitz/xz v0.5.14 // indirect
4436
github.com/xanzy/go-gitlab v0.115.0 // indirect
37+
github.com/yosida95/uritemplate/v3 v3.0.2 // indirect
4538
golang.org/x/crypto v0.41.0 // indirect
4639
golang.org/x/oauth2 v0.30.0 // indirect
4740
golang.org/x/sys v0.39.0 // indirect

go.sum

Lines changed: 10 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
code.gitea.io/sdk/gitea v0.22.0 h1:HCKq7bX/HQ85Nw7c/HAhWgRye+vBp5nQOE8Md1+9Ef0=
22
code.gitea.io/sdk/gitea v0.22.0/go.mod h1:yyF5+GhljqvA30sRDreoyHILruNiy4ASufugzYg0VHM=
3-
git.sr.ht/~jackmordaunt/go-toast v1.1.2 h1:/yrfI55LRt1M7H1vkaw+NaH1+L1CDxrqDltwm5euVuE=
4-
git.sr.ht/~jackmordaunt/go-toast v1.1.2/go.mod h1:jA4OqHKTQ4AFBdwrSnwnskUIIS3HYzlJSgdzCKqfavo=
53
github.com/42wim/httpsig v1.2.3 h1:xb0YyWhkYj57SPtfSttIobJUPJZB9as1nsfo7KWVcEs=
64
github.com/42wim/httpsig v1.2.3/go.mod h1:nZq9OlYKDrUBhptd77IHx4/sZZD+IxTBADvAPI9G/EM=
75
github.com/BurntSushi/toml v1.5.0 h1:W5quZX/G/csjUnuI8SUYlsHs9M38FC7znL0lIO+DvMg=
@@ -14,34 +12,27 @@ github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6N
1412
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
1513
github.com/creativeprojects/go-selfupdate v1.5.1 h1:fuyEGFFfqcC8SxDGolcEPYPLXGQ9Mcrc5uRyRG2Mqnk=
1614
github.com/creativeprojects/go-selfupdate v1.5.1/go.mod h1:2uY75rP8z/D/PBuDn6mlBnzu+ysEmwOJfcgF8np0JIM=
17-
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
1815
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
1916
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
2017
github.com/davidmz/go-pageant v1.0.2 h1:bPblRCh5jGU+Uptpz6LgMZGD5hJoOt7otgT454WvHn0=
2118
github.com/davidmz/go-pageant v1.0.2/go.mod h1:P2EDDnMqIwG5Rrp05dTRITj9z2zpGcD9efWSkTNKLIE=
22-
github.com/esiqveland/notify v0.13.3 h1:QCMw6o1n+6rl+oLUfg8P1IIDSFsDEb2WlXvVvIJbI/o=
23-
github.com/esiqveland/notify v0.13.3/go.mod h1:hesw/IRYTO0x99u1JPweAl4+5mwXJibQVUcP0Iu5ORE=
2419
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
2520
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
26-
github.com/gen2brain/beeep v0.11.1 h1:EbSIhrQZFDj1K2fzlMpAYlFOzV8YuNe721A58XcCTYI=
27-
github.com/gen2brain/beeep v0.11.1/go.mod h1:jQVvuwnLuwOcdctHn/uyh8horSBNJ8uGb9Cn2W4tvoc=
2821
github.com/go-fed/httpsig v1.1.0 h1:9M+hb0jkEICD8/cAiNqEB66R87tTINszBRTjwjQzWcI=
2922
github.com/go-fed/httpsig v1.1.0/go.mod h1:RCMrTZvN1bJYtofsG4rd5NaO5obxQ5xBkdiS7xsT7bM=
30-
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
31-
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
32-
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
33-
github.com/godbus/dbus/v5 v5.2.0 h1:3WexO+U+yg9T70v9FdHr9kCxYlazaAXUhx2VMkbfax8=
34-
github.com/godbus/dbus/v5 v5.2.0/go.mod h1:3AAv2+hPq5rdnr5txxxRwiGjPXamgoIHgz9FPBfOp3c=
3523
github.com/gofrs/flock v0.13.0 h1:95JolYOvGMqeH31+FC7D2+uULf6mG61mEZ/A8dRYMzw=
3624
github.com/gofrs/flock v0.13.0/go.mod h1:jxeyy9R1auM5S6JYDBhDt+E2TCo7DkratH4Pgi8P+Z0=
3725
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
38-
github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM=
3926
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
27+
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
28+
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
4029
github.com/google/go-github/v30 v30.1.0 h1:VLDx+UolQICEOKu2m4uAoMti1SxuEBAl7RSEG16L+Oo=
4130
github.com/google/go-github/v30 v30.1.0/go.mod h1:n8jBpHl45a/rlBUtRJMOG4GhNADUQFEufcolZ95JfU8=
4231
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
4332
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
4433
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
34+
github.com/google/jsonschema-go v0.3.0 h1:6AH2TxVNtk3IlvkkhjrtbUc4S8AvO0Xii0DxIygDg+Q=
35+
github.com/google/jsonschema-go v0.3.0/go.mod h1:r5quNTdLOYEz95Ru18zA0ydNbBuYoo9tgaYcxEYhJVE=
4536
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
4637
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
4738
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
@@ -54,8 +45,6 @@ github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKe
5445
github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
5546
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
5647
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
57-
github.com/jackmordaunt/icns/v3 v3.0.1 h1:xxot6aNuGrU+lNgxz5I5H0qSeCjNKp8uTXB1j8D4S3o=
58-
github.com/jackmordaunt/icns/v3 v3.0.1/go.mod h1:5sHL59nqTd2ynTnowxB/MDQFhKNqkK8X687uKNygaSQ=
5948
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
6049
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
6150
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
@@ -68,8 +57,8 @@ github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6T
6857
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
6958
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ=
7059
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw=
71-
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
72-
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
60+
github.com/modelcontextprotocol/go-sdk v1.1.0 h1:Qjayg53dnKC4UZ+792W21e4BpwEZBzwgRW6LrjLWSwA=
61+
github.com/modelcontextprotocol/go-sdk v1.1.0/go.mod h1:6fM3LCm3yV7pAs8isnKLn07oKtB0MP9LHd3DfAcKw10=
7362
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
7463
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
7564
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
@@ -81,29 +70,19 @@ github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7
8170
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
8271
github.com/schollz/progressbar/v3 v3.18.0 h1:uXdoHABRFmNIjUfte/Ex7WtuyVslrw2wVPQmCN62HpA=
8372
github.com/schollz/progressbar/v3 v3.18.0/go.mod h1:IsO3lpbaGuzh8zIMzgY3+J8l4C8GjO0Y9S69eFvNsec=
84-
github.com/sergeymakinen/go-bmp v1.0.0 h1:SdGTzp9WvCV0A1V0mBeaS7kQAwNLdVJbmHlqNWq0R+M=
85-
github.com/sergeymakinen/go-bmp v1.0.0/go.mod h1:/mxlAQZRLxSvJFNIEGGLBE/m40f3ZnUifpgVDlcUIEY=
86-
github.com/sergeymakinen/go-ico v1.0.0 h1:uL3khgvKkY6WfAetA+RqsguClBuu7HpvBB/nq/Jvr80=
87-
github.com/sergeymakinen/go-ico v1.0.0/go.mod h1:wQ47mTczswBO5F0NoDt7O0IXgnV4Xy3ojrroMQzyhUk=
8873
github.com/spf13/cobra v1.10.1 h1:lJeBwCfmrnXthfAupyUTzJ/J4Nc1RsHC/mSRU2dll/s=
8974
github.com/spf13/cobra v1.10.1/go.mod h1:7SmJGaTHFVBY0jW4NXGluQoLvhqFQM+6XSKD+P4XaB0=
9075
github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
9176
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
9277
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
93-
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
94-
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
95-
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
96-
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
97-
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
98-
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
9978
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
10079
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
101-
github.com/tadvi/systray v0.0.0-20190226123456-11a2b8fa57af h1:6yITBqGTE2lEeTPG04SN9W+iWHCRyHqlVYILiSXziwk=
102-
github.com/tadvi/systray v0.0.0-20190226123456-11a2b8fa57af/go.mod h1:4F09kP5F+am0jAwlQLddpoMDM+iewkxxt6nxUQ5nq5o=
10380
github.com/ulikunitz/xz v0.5.14 h1:uv/0Bq533iFdnMHZdRBTOlaNMdb1+ZxXIlHDZHIHcvg=
10481
github.com/ulikunitz/xz v0.5.14/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
10582
github.com/xanzy/go-gitlab v0.115.0 h1:6DmtItNcVe+At/liXSgfE/DZNZrGfalQmBRmOcJjOn8=
10683
github.com/xanzy/go-gitlab v0.115.0/go.mod h1:5XCDtM7AM6WMKmfDdOiEpyRWUqui2iS9ILfvCZ2gJ5M=
84+
github.com/yosida95/uritemplate/v3 v3.0.2 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zIM+UJPGz4=
85+
github.com/yosida95/uritemplate/v3 v3.0.2/go.mod h1:ILOh0sOhIJR3+L/8afwt/kE++YT040gmv5BQTMR2HP4=
10786
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
10887
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
10988
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
@@ -129,13 +108,14 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
129108
golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE=
130109
golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
131110
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
111+
golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo=
112+
golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg=
132113
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
133114
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
134115
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
135116
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
136117
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
137118
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
138119
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
139-
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
140120
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
141121
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

internal/artifact/types.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,3 +85,22 @@ func (t *Type) UnmarshalText(text []byte) error {
8585
*t = FromString(string(text))
8686
return nil
8787
}
88+
89+
// AllTypes returns all defined artifact types
90+
func AllTypes() []Type {
91+
return []Type{
92+
TypeMCP,
93+
TypeMCPRemote,
94+
TypeSkill,
95+
TypeAgent,
96+
TypeCommand,
97+
TypeHook,
98+
}
99+
}
100+
101+
// Artifact represents a simple artifact with just name, version, and type
102+
type Artifact struct {
103+
Name string
104+
Version string
105+
Type Type
106+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package detectors
2+
3+
import (
4+
"github.com/sleuth-io/skills/internal/artifact"
5+
"github.com/sleuth-io/skills/internal/metadata"
6+
)
7+
8+
// AgentHandler handles agent artifact installation
9+
type AgentDetector struct{}
10+
11+
// Compile-time interface checks
12+
var (
13+
_ ArtifactTypeDetector = (*AgentDetector)(nil)
14+
_ UsageDetector = (*AgentDetector)(nil)
15+
)
16+
17+
// DetectType returns true if files indicate this is an agent artifact
18+
func (h *AgentDetector) DetectType(files []string) bool {
19+
for _, file := range files {
20+
if file == "AGENT.md" || file == "agent.md" {
21+
return true
22+
}
23+
}
24+
return false
25+
}
26+
27+
// GetType returns the artifact type string
28+
func (h *AgentDetector) GetType() string {
29+
return "agent"
30+
}
31+
32+
// CreateDefaultMetadata creates default metadata for an agent
33+
func (h *AgentDetector) CreateDefaultMetadata(name, version string) *metadata.Metadata {
34+
return &metadata.Metadata{
35+
MetadataVersion: "1.0",
36+
Artifact: metadata.Artifact{
37+
Name: name,
38+
Version: version,
39+
Type: artifact.TypeAgent,
40+
},
41+
Agent: &metadata.AgentConfig{
42+
PromptFile: "AGENT.md",
43+
},
44+
}
45+
}
46+
47+
// DetectUsageFromToolCall detects agent usage from tool calls
48+
func (h *AgentDetector) DetectUsageFromToolCall(toolName string, toolInput map[string]interface{}) (string, bool) {
49+
if toolName != "Task" {
50+
return "", false
51+
}
52+
agentName, ok := toolInput["subagent_type"].(string)
53+
return agentName, ok
54+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package detectors
2+
3+
import (
4+
"strings"
5+
6+
"github.com/sleuth-io/skills/internal/artifact"
7+
"github.com/sleuth-io/skills/internal/metadata"
8+
)
9+
10+
// CommandHandler handles command artifact installation
11+
type CommandDetector struct{}
12+
13+
// Compile-time interface checks
14+
var (
15+
_ ArtifactTypeDetector = (*CommandDetector)(nil)
16+
_ UsageDetector = (*CommandDetector)(nil)
17+
)
18+
19+
// DetectType returns true if files indicate this is a command artifact
20+
func (h *CommandDetector) DetectType(files []string) bool {
21+
for _, file := range files {
22+
if file == "COMMAND.md" || file == "command.md" {
23+
return true
24+
}
25+
}
26+
return false
27+
}
28+
29+
// GetType returns the artifact type string
30+
func (h *CommandDetector) GetType() string {
31+
return "command"
32+
}
33+
34+
// CreateDefaultMetadata creates default metadata for a command
35+
func (h *CommandDetector) CreateDefaultMetadata(name, version string) *metadata.Metadata {
36+
return &metadata.Metadata{
37+
MetadataVersion: "1.0",
38+
Artifact: metadata.Artifact{
39+
Name: name,
40+
Version: version,
41+
Type: artifact.TypeCommand,
42+
},
43+
Command: &metadata.CommandConfig{
44+
PromptFile: "COMMAND.md",
45+
},
46+
}
47+
}
48+
49+
// DetectUsageFromToolCall detects command usage from tool calls
50+
func (h *CommandDetector) DetectUsageFromToolCall(toolName string, toolInput map[string]interface{}) (string, bool) {
51+
if toolName != "SlashCommand" {
52+
return "", false
53+
}
54+
command, ok := toolInput["command"].(string)
55+
if !ok {
56+
return "", false
57+
}
58+
// Strip leading slash: "/my-command" -> "my-command"
59+
commandName := strings.TrimPrefix(command, "/")
60+
return commandName, true
61+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package detectors
2+
3+
import (
4+
"github.com/sleuth-io/skills/internal/metadata"
5+
)
6+
7+
// ArtifactTypeDetector detects artifact types from file structures
8+
type ArtifactTypeDetector interface {
9+
// DetectType returns true if the file list matches this artifact type
10+
DetectType(files []string) bool
11+
12+
// GetType returns the artifact type string
13+
GetType() string
14+
15+
// CreateDefaultMetadata creates default metadata for this type
16+
CreateDefaultMetadata(name, version string) *metadata.Metadata
17+
}
18+
19+
// UsageDetector provides methods to detect artifact usage from tool calls
20+
type UsageDetector interface {
21+
// DetectUsageFromToolCall checks if this handler's artifact type was used in a tool call
22+
// Returns (artifact_name, detected)
23+
DetectUsageFromToolCall(toolName string, toolInput map[string]interface{}) (string, bool)
24+
}
25+
26+
// detectorRegistry holds all registered detectors
27+
var detectorRegistry []func() ArtifactTypeDetector
28+
29+
// RegisterDetector registers a detector factory function
30+
func RegisterDetector(factory func() ArtifactTypeDetector) {
31+
detectorRegistry = append(detectorRegistry, factory)
32+
}
33+
34+
// DetectArtifactType detects the artifact type from a list of files
35+
func DetectArtifactType(files []string, name, version string) *metadata.Metadata {
36+
for _, factory := range detectorRegistry {
37+
detector := factory()
38+
if detector.DetectType(files) {
39+
return detector.CreateDefaultMetadata(name, version)
40+
}
41+
}
42+
43+
// Default to skill if nothing detected
44+
return (&SkillDetector{}).CreateDefaultMetadata(name, version)
45+
}
46+
47+
func init() {
48+
// Register all detectors
49+
RegisterDetector(func() ArtifactTypeDetector { return &SkillDetector{} })
50+
RegisterDetector(func() ArtifactTypeDetector { return &AgentDetector{} })
51+
RegisterDetector(func() ArtifactTypeDetector { return &CommandDetector{} })
52+
RegisterDetector(func() ArtifactTypeDetector { return &HookDetector{} })
53+
RegisterDetector(func() ArtifactTypeDetector { return &MCPDetector{} })
54+
}

0 commit comments

Comments
 (0)