Compare commits

...

2 Commits

Author SHA1 Message Date
92b9c356b8 ... 2025-05-23 15:11:03 +04:00
c86165f88c ... 2025-05-23 14:05:09 +04:00
92 changed files with 450 additions and 3109 deletions

11
go.mod
View File

@ -1,4 +1,4 @@
module github.com/freeflowuniverse/heroagent
module git.ourworld.tf/herocode/heroagent
go 1.23.0
@ -10,12 +10,10 @@ require (
github.com/emersion/go-smtp v0.21.3
github.com/emersion/go-webdav v0.6.0
github.com/gofiber/fiber/v2 v2.52.6
github.com/gofiber/swagger v1.1.1
github.com/gofiber/template/pug/v2 v2.1.8
github.com/knusbaum/go9p v1.18.0
github.com/redis/go-redis/v9 v9.7.1
github.com/shirou/gopsutil/v3 v3.24.5
github.com/stretchr/testify v1.10.0
github.com/tidwall/redcon v1.6.2
github.com/yuin/goldmark v1.7.8
golang.org/x/crypto v0.36.0
@ -37,7 +35,6 @@ require (
github.com/buger/jsonparser v1.1.1 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
@ -49,7 +46,6 @@ require (
github.com/go-openapi/jsonpointer v0.21.1 // indirect
github.com/go-openapi/jsonreference v0.21.0 // indirect
github.com/go-openapi/spec v0.21.0 // indirect
github.com/go-openapi/swag v0.23.1 // indirect
github.com/gofiber/template v1.8.3 // indirect
github.com/gofiber/template/jet/v2 v2.1.11 // indirect
github.com/gofiber/utils v1.1.0 // indirect
@ -69,9 +65,8 @@ require (
github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/mattn/go-sqlite3 v1.14.24 // indirect
github.com/metoro-io/mcp-golang v0.8.0 // indirect
github.com/mholt/archiver/v3 v3.5.1 // indirect
github.com/nwaples/rardecode v1.1.0 // indirect
github.com/openaiproxy/openaiproxy-go v0.1.0-beta.9 // indirect
github.com/openai/openai-go v0.1.0-beta.9 // indirect
github.com/pb33f/libopenapi v0.21.8 // indirect
github.com/pierrec/lz4/v4 v4.1.2 // indirect
github.com/pkg/errors v0.9.1 // indirect
@ -116,3 +111,5 @@ require (
modernc.org/sqlite v1.23.1 // indirect
sigs.k8s.io/yaml v1.4.0 // indirect
)
replace github.com/openaiproxy/openaiproxy-go => github.com/sashabaranov/go-openai v1.20.0

351
go.sum
View File

@ -1,351 +0,0 @@
9fans.net/go v0.0.2 h1:RYM6lWITV8oADrwLfdzxmt8ucfW6UtP9v1jg4qAbqts=
9fans.net/go v0.0.2/go.mod h1:lfPdxjq9v8pVQXUMBCx5EO5oLXWQFlKRQgs1kEkjoIM=
github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53 h1:sR+/8Yb4slttB4vD+b9btVEnWgL3Q00OBTzVT8B9C0c=
github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno=
github.com/CloudyKit/jet/v6 v6.3.1 h1:6IAo5Cx21xrHVaR8zzXN5gJatKV/wO7Nf6bfCnCSbUw=
github.com/CloudyKit/jet/v6 v6.3.1/go.mod h1:lf8ksdNsxZt7/yH/3n4vJQWA9RUq4wpaHtArHhGVMOw=
github.com/Joker/hpp v1.0.0 h1:65+iuJYdRXv/XyN62C1uEmmOx3432rNG/rKlX6V7Kkc=
github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY=
github.com/Joker/jade v1.1.3 h1:Qbeh12Vq6BxURXT1qZBRHsDxeURB8ztcL6f3EXSGeHk=
github.com/Joker/jade v1.1.3/go.mod h1:T+2WLyt7VH6Lp0TRxQrUYEs64nRc83wkMQrfeIQKduM=
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
github.com/Plan9-Archive/libauth v0.0.0-20180917063427-d1ca9e94969d/go.mod h1:UKp8dv9aeaZoQFWin7eQXtz89iHly1YAFZNn3MCutmQ=
github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/purell v1.2.1 h1:QsZ4TjvwiMpat6gBCBxEQI0rcS9ehtkKtSpiUnd9N28=
github.com/PuerkitoBio/purell v1.2.1/go.mod h1:ZwHcC/82TOaovDi//J/804umJFFmbOHPngi8iYYv/Eo=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk=
github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg=
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
github.com/buger/jsonparser v1.1.1 h1:2PnMjfWD7wBILjqQbt530v576A/cAbQvEW9gGIpYMUs=
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cpuguy83/go-md2man/v2 v2.0.6 h1:XJtiaUW6dEEqVuZiMTn1ldk455QWwEIsMIJlo5vtkx0=
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5 h1:iFaUwBSo5Svw6L7HYpRu/0lE3e0BaElwnNO1qkNQxBY=
github.com/dsnet/compress v0.0.2-0.20210315054119-f66993602bf5/go.mod h1:qssHWj60/X5sZFNxpG4HBPDHVqxNm4DfnCKgrbZOT+s=
github.com/dsnet/golib v0.0.0-20171103203638-1ea166775780/go.mod h1:Lj+Z9rebOhdfkVLjJ8T6VcRQv3SXugXy999NBtR9aFY=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/emersion/go-ical v0.0.0-20240127095438-fc1c9d8fb2b6/go.mod h1:BEksegNspIkjCQfmzWgsgbu6KdeJ/4LwUZs7DMBzjzw=
github.com/emersion/go-imap v1.2.1 h1:+s9ZjMEjOB8NzZMVTM3cCenz2JrQIGGo5j1df19WjTA=
github.com/emersion/go-imap v1.2.1/go.mod h1:Qlx1FSx2FTxjnjWpIlVNEuX+ylerZQNFE5NsmKFSejY=
github.com/emersion/go-message v0.15.0/go.mod h1:wQUEfE+38+7EW8p8aZ96ptg6bAb1iwdgej19uXASlE4=
github.com/emersion/go-message v0.18.2 h1:rl55SQdjd9oJcIoQNhubD2Acs1E6IzlZISRTK7x/Lpg=
github.com/emersion/go-message v0.18.2/go.mod h1:XpJyL70LwRvq2a8rVbHXikPgKj8+aI0kGdHlg16ibYA=
github.com/emersion/go-sasl v0.0.0-20200509203442-7bfe0ed36a21/go.mod h1:iL2twTeMvZnrg54ZoPDNfJaJaqy0xIQFuBdrLsmspwQ=
github.com/emersion/go-sasl v0.0.0-20220912192320-0145f2c60ead h1:fI1Jck0vUrXT8bnphprS1EoVRe2Q5CKCX8iDlpqjQ/Y=
github.com/emersion/go-sasl v0.0.0-20220912192320-0145f2c60ead/go.mod h1:iL2twTeMvZnrg54ZoPDNfJaJaqy0xIQFuBdrLsmspwQ=
github.com/emersion/go-smtp v0.21.3 h1:7uVwagE8iPYE48WhNsng3RRpCUpFvNl39JGNSIyGVMY=
github.com/emersion/go-smtp v0.21.3/go.mod h1:qm27SGYgoIPRot6ubfQ/GpiPy/g3PaZAVRxiO/sDUgQ=
github.com/emersion/go-textwrapper v0.0.0-20200911093747-65d896831594/go.mod h1:aqO8z8wPrjkscevZJFVE1wXJrLpC5LtJG7fqLOsPb2U=
github.com/emersion/go-vcard v0.0.0-20230815062825-8fda7d206ec9/go.mod h1:HMJKR5wlh/ziNp+sHEDV2ltblO4JD2+IdDOWtGcQBTM=
github.com/emersion/go-webdav v0.6.0 h1:rbnBUEXvUM2Zk65Him13LwJOBY0ISltgqM5k6T5Lq4w=
github.com/emersion/go-webdav v0.6.0/go.mod h1:mI8iBx3RAODwX7PJJ7qzsKAKs/vY429YfS2/9wKnDbQ=
github.com/fhs/mux9p v0.3.1 h1:x1UswUWZoA9vrA02jfisndCq3xQm+wrQUxUt5N99E08=
github.com/fhs/mux9p v0.3.1/go.mod h1:F4hwdenmit0WDoNVT2VMWlLJrBVCp/8UhzJa7scfjEQ=
github.com/glebarez/go-sqlite v1.21.2 h1:3a6LFC4sKahUunAmynQKLZceZCOzUthkRkEAl9gAXWo=
github.com/glebarez/go-sqlite v1.21.2/go.mod h1:sfxdZyhQjTM2Wry3gVYWaW072Ri1WMdWJi0k6+3382k=
github.com/glebarez/sqlite v1.11.0 h1:wSG0irqzP6VurnMEpFGer5Li19RpIRi2qvQz++w0GMw=
github.com/glebarez/sqlite v1.11.0/go.mod h1:h8/o8j5wiAsqSPoWELDUdJXhjAhsVliSn7bWZjOhrgQ=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE=
github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78=
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonpointer v0.21.1 h1:whnzv/pNXtK2FbX/W9yJfRmE2gsmkfahjMKB0fZvcic=
github.com/go-openapi/jsonpointer v0.21.1/go.mod h1:50I1STOfbY1ycR8jGz8DaMeLCdXiI6aDteEdRNNzpdk=
github.com/go-openapi/jsonreference v0.19.6 h1:UBIxjkht+AWIgYzCDSv2GN+E/togfwXUJFRTWhl2Jjs=
github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns=
github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF2+tg1TRrwQ=
github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4=
github.com/go-openapi/spec v0.20.4 h1:O8hJrt0UMnhHcluhIdUgCLRWyM2x7QkBXRvOs7m+O1M=
github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I=
github.com/go-openapi/spec v0.21.0 h1:LTVzPc3p/RzRnkQqLRndbAzjY0d0BCL72A6j3CdL9ZY=
github.com/go-openapi/spec v0.21.0/go.mod h1:78u6VdPw81XU44qEWGhtr982gJ5BWg2c0I5XwVMotYk=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.19.15 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM=
github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
github.com/go-openapi/swag v0.23.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU=
github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0=
github.com/gofiber/fiber/v2 v2.52.6 h1:Rfp+ILPiYSvvVuIPvxrBns+HJp8qGLDnLJawAu27XVI=
github.com/gofiber/fiber/v2 v2.52.6/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw=
github.com/gofiber/swagger v1.1.1 h1:FZVhVQQ9s1ZKLHL/O0loLh49bYB5l1HEAgxDlcTtkRA=
github.com/gofiber/swagger v1.1.1/go.mod h1:vtvY/sQAMc/lGTUCg0lqmBL7Ht9O7uzChpbvJeJQINw=
github.com/gofiber/template v1.8.3 h1:hzHdvMwMo/T2kouz2pPCA0zGiLCeMnoGsQZBTSYgZxc=
github.com/gofiber/template v1.8.3/go.mod h1:bs/2n0pSNPOkRa5VJ8zTIvedcI/lEYxzV3+YPXdBvq8=
github.com/gofiber/template/jet/v2 v2.1.11 h1:irnR6GeM2SGTdvg7dxFts564a5evApMUKpOn3mt/RNE=
github.com/gofiber/template/jet/v2 v2.1.11/go.mod h1:Kb1oBdrx90oEvP71MDTUB9k+IWRF082Td5OPW7SoUMQ=
github.com/gofiber/template/pug/v2 v2.1.8 h1:SNs0wE96S5P5Ggb54jNOtlP5Qads63gR31PvBBEgNns=
github.com/gofiber/template/pug/v2 v2.1.8/go.mod h1:e0Sg0YBMtC+RQMRm0swaAvqIBDJmhhDIKfFFtQRjvlQ=
github.com/gofiber/utils v1.1.0 h1:vdEBpn7AzIUJRhe+CiTOJdUcTg4Q9RK+pEa0KPbLdrM=
github.com/gofiber/utils v1.1.0/go.mod h1:poZpsnhBykfnY1Mc0KeEa6mSHrS3dV0+oBWyeQmb2e0=
github.com/golang/snappy v0.0.2 h1:aeE13tS0IiQgFjYdoL8qN3K1N2bXXtI6Vi51/y7BpMw=
github.com/golang/snappy v0.0.2/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/hanwen/go-fuse v1.0.0/go.mod h1:unqXarDXqzAk0rt98O2tVndEPIpUgLD9+rwFisZH3Ok=
github.com/hanwen/go-fuse/v2 v2.0.3/go.mod h1:0EQM6aH2ctVpvZ6a+onrQ/vaykxh2GH7hy3e13vzTUY=
github.com/invopop/jsonschema v0.12.0 h1:6ovsNSuvn9wEQVOyc72aycBMVQFKz7cPdMJn10CvzRI=
github.com/invopop/jsonschema v0.12.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/compress v1.11.4/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
github.com/klauspost/cpuid v1.2.0/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
github.com/klauspost/pgzip v1.2.5 h1:qnWYvvKqedOF2ulHpMG72XQol4ILEJ8k2wwRl/Km8oE=
github.com/klauspost/pgzip v1.2.5/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
github.com/knusbaum/go9p v1.18.0 h1:/Y67RNvNKX1ZV1IOdnO1lIetiF0X+CumOyvEc0011GI=
github.com/knusbaum/go9p v1.18.0/go.mod h1:HtMoJKqZUe1Oqag5uJqG5RKQ9gWPSP+wolsnLLv44r8=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k=
github.com/lufia/plan9stats v0.0.0-20231016141302-07b5767bb0ed h1:036IscGBfJsFIgJQzlui7nK1Ncm0tp2ktmPj8xO4N/0=
github.com/lufia/plan9stats v0.0.0-20231016141302-07b5767bb0ed/go.mod h1:ilwx/Dta8jXAgpFYFvSWEMwxmbWXyiUHkd5FwyKhb5k=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA=
github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4=
github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-sqlite3 v1.14.24 h1:tpSp2G2KyMnnQu99ngJ47EIkWVmliIizyZBfPrBWDRM=
github.com/mattn/go-sqlite3 v1.14.24/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/metoro-io/mcp-golang v0.8.0 h1:DkigHa3w7WwMFomcEz5wiMDX94DsvVm/3mCV3d1obnc=
github.com/metoro-io/mcp-golang v0.8.0/go.mod h1:ifLP9ZzKpN1UqFWNTpAHOqSvNkMK6b7d1FSZ5Lu0lN0=
github.com/mholt/archiver/v3 v3.5.1 h1:rDjOBX9JSF5BvoJGvjqK479aL70qh9DIpZCl+k7Clwo=
github.com/mholt/archiver/v3 v3.5.1/go.mod h1:e3dqJ7H78uzsRSEACH1joayhuSyhnonssnDhppzS1L4=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nwaples/rardecode v1.1.0 h1:vSxaY8vQhOcVr4mm5e8XllHWTiM4JF507A0Katqw7MQ=
github.com/nwaples/rardecode v1.1.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0=
github.com/openaiproxy/openaiproxy-go v0.1.0-beta.9 h1:ABpubc5yU/3ejee2GgRrbFta81SG/d7bQbB8mIdP0Xo=
github.com/openaiproxy/openaiproxy-go v0.1.0-beta.9/go.mod h1:g461MYGXEXBVdV5SaR/5tNzNbSfwTBBefwc+LlDCK0Y=
github.com/pb33f/libopenapi v0.21.8 h1:Fi2dAogMwC6av/5n3YIo7aMOGBZH/fBMO4OnzFB3dQA=
github.com/pb33f/libopenapi v0.21.8/go.mod h1:Gc8oQkjr2InxwumK0zOBtKN9gIlv9L2VmSVIUk2YxcU=
github.com/pierrec/lz4/v4 v4.1.2 h1:qvY3YFXRQE/XB8MlLzJH7mSzBs74eA2gg52YTk6jUPM=
github.com/pierrec/lz4/v4 v4.1.2/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b h1:0LFwY6Q3gMACTjAbMZBjXAqTOzOwFaj2Ld6cjeQ7Rig=
github.com/power-devops/perfstat v0.0.0-20221212215047-62379fc7944b/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE=
github.com/redis/go-redis/v9 v9.7.1 h1:4LhKRCIduqXqtvCUlaq9c8bdHOkICjDMrr1+Zb3osAc=
github.com/redis/go-redis/v9 v9.7.1/go.mod h1:f6zhXITC7JUJIlPEiBOTXxJgPLdZcA93GewI7inzyWw=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/shirou/gopsutil/v3 v3.24.5 h1:i0t8kL+kQTvpAYToeuiVk3TgDeKOFioZO3Ztz/iZ9pI=
github.com/shirou/gopsutil/v3 v3.24.5/go.mod h1:bsoOS1aStSs9ErQ1WWfxllSeS1K5D+U30r2NfcubMVk=
github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU=
github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k=
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/speakeasy-api/jsonpath v0.6.1 h1:FWbuCEPGaJTVB60NZg2orcYHGZlelbNJAcIk/JGnZvo=
github.com/speakeasy-api/jsonpath v0.6.1/go.mod h1:ymb2iSkyOycmzKwbEAYPJV/yi2rSmvBCLZJcyD+VVWw=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/swaggo/files/v2 v2.0.2 h1:Bq4tgS/yxLB/3nwOMcul5oLEUKa877Ykgz3CJMVbQKU=
github.com/swaggo/files/v2 v2.0.2/go.mod h1:TVqetIzZsO9OhHX1Am9sRf9LdrFZqoK49N37KON/jr0=
github.com/swaggo/swag v1.16.4 h1:clWJtd9LStiG3VeijiCfOVODP6VpHtKdQy9ELFG3s1A=
github.com/swaggo/swag v1.16.4/go.mod h1:VBsHJRsDvfYvqoiMKnsdwhNV9LEMHgEDZcyVYX0sxPg=
github.com/teambition/rrule-go v1.8.2/go.mod h1:Ieq5AbrKGciP1V//Wq8ktsTXwSwJHDD5mD/wLBGl3p4=
github.com/tidwall/btree v1.1.0 h1:5P+9WU8ui5uhmcg3SoPyTwoI0mVyZ1nps7YQzTZFkYM=
github.com/tidwall/btree v1.1.0/go.mod h1:TzIRzen6yHbibdSfK6t8QimqbUnoxUSrZfeW7Uob0q4=
github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY=
github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4=
github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/tidwall/redcon v1.6.2 h1:5qfvrrybgtO85jnhSravmkZyC0D+7WstbfCs3MmPhow=
github.com/tidwall/redcon v1.6.2/go.mod h1:p5Wbsgeyi2VSTBWOcA5vRXrOb9arFTcU2+ZzFjqV75Y=
github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
github.com/tklauser/go-sysconf v0.3.13 h1:GBUpcahXSpR2xN01jhkNAbTLRk2Yzgggk8IM08lq3r4=
github.com/tklauser/go-sysconf v0.3.13/go.mod h1:zwleP4Q4OehZHGn4CYZDipCgg9usW5IJePewFCGVEa0=
github.com/tklauser/numcpus v0.7.0 h1:yjuerZP127QG9m5Zh/mSO4wqurYil27tHrqwRoRjpr4=
github.com/tklauser/numcpus v0.7.0/go.mod h1:bb6dMVcj8A42tSE7i32fsIUCbQNllK5iDguyOZRUzAY=
github.com/ulikunitz/xz v0.5.8/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/ulikunitz/xz v0.5.9 h1:RsKRIA2MO8x56wkkcd3LbtcE/uMszhb6DpRf+3uwa3I=
github.com/ulikunitz/xz v0.5.9/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/urfave/cli/v2 v2.27.6 h1:VdRdS98FNhKZ8/Az8B7MTyGQmpIr36O1EHybx/LaZ4g=
github.com/urfave/cli/v2 v2.27.6/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA=
github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g=
github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8=
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
github.com/wk8/go-ordered-map/v2 v2.1.9-0.20240815153524-6ea36470d1bd h1:dLuIF2kX9c+KknGJUdJi1Il1SDiTSK158/BB9kdgAew=
github.com/wk8/go-ordered-map/v2 v2.1.9-0.20240815153524-6ea36470d1bd/go.mod h1:DbzwytT4g/odXquuOCqroKvtxxldI4nb3nuesHF/Exo=
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo=
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos=
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4=
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM=
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yuin/goldmark v1.7.8 h1:iERMLn0/QJeHFhxSt3p6PeN9mGnvIKSpG9YYorDMnic=
github.com/yuin/goldmark v1.7.8/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E=
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.19.0 h1:fEdghXQSo20giMthA7cd28ZC+jts4amQ3YMXiP5oMQ8=
golang.org/x/mod v0.19.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM=
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201020230747-6e5568b54d1a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.23.0 h1:SGsXPZ+2l4JsgaCKkx+FQ9YZ5XEtA1GZYuoDjenLjvg=
golang.org/x/tools v0.23.0/go.mod h1:pnu6ufv6vQkll6szChhK3C3L/ruaIv5eBeztNG8wtsI=
golang.org/x/tools v0.31.0 h1:0EedkvKDbh+qistFTd0Bcwe/YLh4vHwWEkiI0toFIBU=
golang.org/x/tools v0.31.0/go.mod h1:naFTU+Cev749tSJRXJlna0T3WxKvb1kWEx15xA4SdmQ=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/driver/sqlite v1.5.7 h1:8NvsrhP0ifM7LX9G4zPB97NwovUakUxc+2V2uuf3Z1I=
gorm.io/driver/sqlite v1.5.7/go.mod h1:U+J8craQU6Fzkcvu8oLeAQmi50TkwPEhHDEjQZXDah4=
gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8=
gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ=
modernc.org/libc v1.22.5 h1:91BNch/e5B0uPbJFgqbxXuOnxBQjlS//icfQEGmvyjE=
modernc.org/libc v1.22.5/go.mod h1:jj+Z7dTNX8fBScMVNRAYZ/jF91K8fdT2hYMThc3YjBY=
modernc.org/mathutil v1.5.0 h1:rV0Ko/6SfM+8G+yKiyI830l3Wuz1zRutdslNoQ0kfiQ=
modernc.org/mathutil v1.5.0/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/memory v1.5.0 h1:N+/8c5rE6EqugZwHii4IFsaJ7MUhoWX07J5tC/iI5Ds=
modernc.org/memory v1.5.0/go.mod h1:PkUhL0Mugw21sHPeskwZW4D6VscE/GQJOnIpCnW6pSU=
modernc.org/sqlite v1.23.1 h1:nrSBg4aRQQwq59JpvGEQ15tNxoO5pX/kUjcRNwSAGQM=
modernc.org/sqlite v1.23.1/go.mod h1:OrDj17Mggn6MhE+iPbBNf7RGKODDE9NFT0f3EwDzJqk=
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=

View File

@ -11,7 +11,7 @@ import (
"syscall"
"time"
"github.com/freeflowuniverse/heroagent/pkg/mycelium_client"
"git.ourworld.tf/herocode/heroagent/pkg/mycelium_client"
)
type config struct {

View File

@ -8,7 +8,7 @@ import (
"os"
"time"
"github.com/freeflowuniverse/heroagent/pkg/mycelium_client"
"git.ourworld.tf/herocode/heroagent/pkg/mycelium_client"
)
func main() {

View File

@ -14,7 +14,7 @@ Dedupestor is a Go package that provides a key-value store with deduplication ba
```go
import (
"github.com/freeflowuniverse/heroagent/pkg/dedupestor"
"git.ourworld.tf/herocode/heroagent/pkg/dedupestor"
)
// Create a new dedupe store

View File

@ -7,8 +7,8 @@ import (
"errors"
"path/filepath"
"github.com/freeflowuniverse/heroagent/pkg/data/ourdb"
"github.com/freeflowuniverse/heroagent/pkg/data/radixtree"
"git.ourworld.tf/herocode/heroagent/pkg/data/ourdb"
"git.ourworld.tf/herocode/heroagent/pkg/data/radixtree"
)
// MaxValueSize is the maximum allowed size for values (1MB)

View File

@ -18,7 +18,7 @@ The DocTree package provides functionality for managing collections of markdown
### Creating a DocTree
```go
import "github.com/freeflowuniverse/heroagent/pkg/doctree"
import "git.ourworld.tf/herocode/heroagent/pkg/doctree"
// Create a new DocTree with a path and name
dt, err := doctree.New("/path/to/collection", "My Collection")

View File

@ -7,7 +7,7 @@ import (
"path/filepath"
"strings"
"github.com/freeflowuniverse/heroagent/pkg/tools"
"git.ourworld.tf/herocode/heroagent/pkg/tools"
)
// Collection represents a collection of markdown pages and files

View File

@ -5,7 +5,7 @@ import (
"context"
"fmt"
"github.com/freeflowuniverse/heroagent/pkg/tools"
"git.ourworld.tf/herocode/heroagent/pkg/tools"
"github.com/redis/go-redis/v9"
"github.com/yuin/goldmark"
"github.com/yuin/goldmark/extension"

View File

@ -4,7 +4,7 @@ import (
"fmt"
"strings"
"github.com/freeflowuniverse/heroagent/pkg/tools"
"git.ourworld.tf/herocode/heroagent/pkg/tools"
)
// Global variable to track the current DocTree instance

View File

@ -34,7 +34,7 @@ import (
"fmt"
"log"
"github.com/freeflowuniverse/heroagent/pkg/ourdb"
"git.ourworld.tf/herocode/heroagent/pkg/ourdb"
)
func main() {
@ -78,7 +78,7 @@ import (
"fmt"
"log"
"github.com/freeflowuniverse/heroagent/pkg/ourdb"
"git.ourworld.tf/herocode/heroagent/pkg/ourdb"
)
func main() {

View File

@ -4,7 +4,7 @@ package radixtree
import (
"errors"
"github.com/freeflowuniverse/heroagent/pkg/data/ourdb"
"git.ourworld.tf/herocode/heroagent/pkg/data/ourdb"
)
// Node represents a node in the radix tree

View File

@ -4,7 +4,7 @@ import (
"fmt"
"time"
"github.com/freeflowuniverse/heroagent/pkg/system/stats"
"git.ourworld.tf/herocode/heroagent/pkg/system/stats"
"github.com/gofiber/fiber/v2"
)
@ -77,7 +77,7 @@ func (h *AdminHandler) getProcessStatsJSON(c *fiber.Ctx) error {
if err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
"success": false,
"error": "Failed to get process stats: " + err.Error(),
"error": "Failed to get process stats: " + err.Error(),
})
}

View File

@ -3,7 +3,7 @@ package api
import (
"time"
"github.com/freeflowuniverse/heroagent/pkg/sal/executor"
"git.ourworld.tf/herocode/heroagent/pkg/sal/executor"
"github.com/gofiber/fiber/v2"
)

View File

@ -7,9 +7,9 @@ import (
"strconv"
"time"
"github.com/freeflowuniverse/heroagent/pkg/processmanager"
"github.com/freeflowuniverse/heroagent/pkg/processmanager/interfaces"
"github.com/freeflowuniverse/heroagent/pkg/processmanager/interfaces/openrpc"
"git.ourworld.tf/herocode/heroagent/pkg/processmanager"
"git.ourworld.tf/herocode/heroagent/pkg/processmanager/interfaces"
"git.ourworld.tf/herocode/heroagent/pkg/processmanager/interfaces/openrpc"
"github.com/gofiber/fiber/v2"
)

View File

@ -12,16 +12,16 @@ import (
"syscall"
"time"
"github.com/freeflowuniverse/heroagent/pkg/heroagent/api"
"github.com/freeflowuniverse/heroagent/pkg/heroagent/handlers"
"github.com/freeflowuniverse/heroagent/pkg/heroagent/pages"
"github.com/freeflowuniverse/heroagent/pkg/processmanager"
"github.com/freeflowuniverse/heroagent/pkg/sal/executor"
"github.com/freeflowuniverse/heroagent/pkg/servers/redisserver"
"github.com/freeflowuniverse/heroagent/pkg/system/stats"
"git.ourworld.tf/herocode/heroagent/pkg/heroagent/api"
"git.ourworld.tf/herocode/heroagent/pkg/heroagent/handlers"
"git.ourworld.tf/herocode/heroagent/pkg/heroagent/pages"
"git.ourworld.tf/herocode/heroagent/pkg/processmanager"
"git.ourworld.tf/herocode/heroagent/pkg/sal/executor"
"git.ourworld.tf/herocode/heroagent/pkg/servers/redisserver"
"git.ourworld.tf/herocode/heroagent/pkg/system/stats"
// "github.com/freeflowuniverse/heroagent/pkg/vfs/interfaces"
// "github.com/freeflowuniverse/heroagent/pkg/vfs/interfaces/mock"
// "git.ourworld.tf/herocode/heroagent/pkg/vfs/interfaces"
// "git.ourworld.tf/herocode/heroagent/pkg/vfs/interfaces/mock"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/cors"
"github.com/gofiber/fiber/v2/middleware/logger"
@ -239,7 +239,7 @@ func (hl *HeroLauncher) GetUptime() string {
func (hl *HeroLauncher) startProcessManager() error {
_, filename, _, _ := runtime.Caller(0)
projectRoot := filepath.Join(filepath.Dir(filename), "../..")
processManagerPath := filepath.Join(projectRoot, "cmd/processmanager/main.go")
processManagerPath := filepath.Join(projectRoot, "pkg/processmanager/examples/openrpc/main.go")
log.Printf("Starting process manager from: %s", processManagerPath)

View File

@ -5,7 +5,7 @@ import (
"log"
"strconv" // Added strconv for JobID parsing
"github.com/freeflowuniverse/heroagent/pkg/herojobs"
"git.ourworld.tf/herocode/heroagent/pkg/herojobs"
"github.com/gofiber/fiber/v2"
)

View File

@ -10,7 +10,7 @@ import (
"net/http/httptest"
"testing"
"github.com/freeflowuniverse/heroagent/pkg/herojobs"
"git.ourworld.tf/herocode/heroagent/pkg/herojobs"
"github.com/gofiber/fiber/v2"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"

View File

@ -7,7 +7,7 @@ import (
"strings"
"time"
"github.com/freeflowuniverse/heroagent/pkg/logger"
"git.ourworld.tf/herocode/heroagent/pkg/logger"
"github.com/gofiber/fiber/v2"
)
@ -65,11 +65,11 @@ func NewLogHandler(logPath string) (*LogHandler, error) {
type LogType string
const (
LogTypeSystem LogType = "system"
LogTypeService LogType = "service"
LogTypeJob LogType = "job"
LogTypeProcess LogType = "process"
LogTypeAll LogType = "all" // Special type to retrieve logs from all sources
LogTypeSystem LogType = "system"
LogTypeService LogType = "service"
LogTypeJob LogType = "job"
LogTypeProcess LogType = "process"
LogTypeAll LogType = "all" // Special type to retrieve logs from all sources
)
// GetLogs renders the logs page with logs content
@ -90,9 +90,9 @@ func (h *LogHandler) GetLogs(c *fiber.Ctx) error {
// Create search arguments
searchArgs := logger.SearchArgs{
Category: category,
LogType: logItemType,
MaxItems: maxItems,
Category: category,
LogType: logItemType,
MaxItems: maxItems,
}
if !fromTime.IsZero() {
@ -135,9 +135,9 @@ func (h *LogHandler) GetLogs(c *fiber.Ctx) error {
// Check if the selected logger is properly initialized
if selectedLogger == nil {
return c.Render("admin/system/logs", fiber.Map{
"title": logTypeTitle,
"error": "Logger not initialized",
"logTypes": []LogType{LogTypeAll, LogTypeSystem, LogTypeService, LogTypeJob, LogTypeProcess},
"title": logTypeTitle,
"error": "Logger not initialized",
"logTypes": []LogType{LogTypeAll, LogTypeSystem, LogTypeService, LogTypeJob, LogTypeProcess},
"selectedLogType": logTypeParam,
})
}
@ -149,14 +149,13 @@ func (h *LogHandler) GetLogs(c *fiber.Ctx) error {
// Handle search error
if err != nil {
return c.Render("admin/system/logs", fiber.Map{
"title": logTypeTitle,
"error": err.Error(),
"logTypes": []LogType{LogTypeAll, LogTypeSystem, LogTypeService, LogTypeJob, LogTypeProcess},
"title": logTypeTitle,
"error": err.Error(),
"logTypes": []LogType{LogTypeAll, LogTypeSystem, LogTypeService, LogTypeJob, LogTypeProcess},
"selectedLogType": logTypeParam,
})
}
// Calculate total pages
totalLogs := len(logs)
totalPages := (totalLogs + itemsPerPage - 1) / itemsPerPage
@ -196,18 +195,18 @@ func (h *LogHandler) GetLogs(c *fiber.Ctx) error {
}
return c.Render("admin/system/logs", fiber.Map{
"title": logTypeTitle,
"logTypes": []LogType{LogTypeAll, LogTypeSystem, LogTypeService, LogTypeJob, LogTypeProcess},
"title": logTypeTitle,
"logTypes": []LogType{LogTypeAll, LogTypeSystem, LogTypeService, LogTypeJob, LogTypeProcess},
"selectedLogType": logTypeParam,
"logs": formattedLogs,
"total": totalLogs,
"showing": len(formattedLogs),
"page": page,
"totalPages": totalPages,
"categoryParam": category,
"typeParam": c.Query("type", ""),
"fromParam": c.Query("from", ""),
"toParam": c.Query("to", ""),
"logs": formattedLogs,
"total": totalLogs,
"showing": len(formattedLogs),
"page": page,
"totalPages": totalPages,
"categoryParam": category,
"typeParam": c.Query("type", ""),
"fromParam": c.Query("from", ""),
"toParam": c.Query("to", ""),
})
}
@ -227,9 +226,9 @@ func (h *LogHandler) GetLogsAPI(c *fiber.Ctx) error {
// Create search arguments
searchArgs := logger.SearchArgs{
Category: category,
LogType: logItemType,
MaxItems: maxItems,
Category: category,
LogType: logItemType,
MaxItems: maxItems,
}
if !fromTime.IsZero() {
@ -298,7 +297,7 @@ func (h *LogHandler) GetLogsAPI(c *fiber.Ctx) error {
}
return c.JSON(fiber.Map{
"logs": response,
"logs": response,
"total": len(logs),
})
}
@ -323,9 +322,9 @@ func (h *LogHandler) GetLogsFragment(c *fiber.Ctx) error {
// Create search arguments
searchArgs := logger.SearchArgs{
Category: category,
LogType: logItemType,
MaxItems: maxItems,
Category: category,
LogType: logItemType,
MaxItems: maxItems,
}
if !fromTime.IsZero() {
@ -368,9 +367,9 @@ func (h *LogHandler) GetLogsFragment(c *fiber.Ctx) error {
// Check if the selected logger is properly initialized
if selectedLogger == nil {
return c.Render("admin/system/logs_fragment", fiber.Map{
"title": logTypeTitle,
"error": "Logger not initialized",
"logTypes": []LogType{LogTypeAll, LogTypeSystem, LogTypeService, LogTypeJob, LogTypeProcess},
"title": logTypeTitle,
"error": "Logger not initialized",
"logTypes": []LogType{LogTypeAll, LogTypeSystem, LogTypeService, LogTypeJob, LogTypeProcess},
"selectedLogType": logTypeParam,
})
}
@ -382,9 +381,9 @@ func (h *LogHandler) GetLogsFragment(c *fiber.Ctx) error {
// Handle search error
if err != nil {
return c.Render("admin/system/logs_fragment", fiber.Map{
"title": logTypeTitle,
"error": err.Error(),
"logTypes": []LogType{LogTypeAll, LogTypeSystem, LogTypeService, LogTypeJob, LogTypeProcess},
"title": logTypeTitle,
"error": err.Error(),
"logTypes": []LogType{LogTypeAll, LogTypeSystem, LogTypeService, LogTypeJob, LogTypeProcess},
"selectedLogType": logTypeParam,
})
}
@ -429,15 +428,15 @@ func (h *LogHandler) GetLogsFragment(c *fiber.Ctx) error {
// Set layout to empty to disable the layout for fragment responses
return c.Render("admin/system/logs_fragment", fiber.Map{
"title": logTypeTitle,
"logTypes": []LogType{LogTypeAll, LogTypeSystem, LogTypeService, LogTypeJob, LogTypeProcess},
"title": logTypeTitle,
"logTypes": []LogType{LogTypeAll, LogTypeSystem, LogTypeService, LogTypeJob, LogTypeProcess},
"selectedLogType": logTypeParam,
"logs": formattedLogs,
"total": totalLogs,
"showing": len(formattedLogs),
"page": page,
"totalPages": totalPages,
"layout": "", // Disable layout for partial template
"logs": formattedLogs,
"total": totalLogs,
"showing": len(formattedLogs),
"page": page,
"totalPages": totalPages,
"layout": "", // Disable layout for partial template
})
}

View File

@ -4,7 +4,7 @@ import (
"fmt"
"time"
"github.com/freeflowuniverse/heroagent/pkg/system/stats"
"git.ourworld.tf/herocode/heroagent/pkg/system/stats"
"github.com/gofiber/fiber/v2"
)
@ -43,8 +43,8 @@ func (h *ProcessHandler) GetProcessStatsJSON(c *fiber.Ctx) error {
// Convert to fiber.Map for JSON response
response := fiber.Map{
"total": processData.Total,
"filtered": processData.Filtered,
"total": processData.Total,
"filtered": processData.Filtered,
"timestamp": time.Now().Unix(),
}
@ -127,8 +127,8 @@ func (h *ProcessHandler) GetProcessesData(c *fiber.Ctx) error {
// Check if StatsManager is properly initialized
if h.statsManager == nil {
return c.Render("admin/system/processes_data", fiber.Map{
"error": "System error: Stats manager not initialized",
"layout": "",
"error": "System error: Stats manager not initialized",
"layout": "",
})
}
@ -165,8 +165,8 @@ func (h *ProcessHandler) GetProcessesData(c *fiber.Ctx) error {
}
// For regular requests, render the error within the fragment
return c.Render("admin/system/processes_data", fiber.Map{
"error": "Failed to get process data: " + err.Error(),
"layout": "",
"error": "Failed to get process data: " + err.Error(),
"layout": "",
})
}
}
@ -201,5 +201,3 @@ func (h *ProcessHandler) GetProcessesData(c *fiber.Ctx) error {
// Return only the table HTML content directly to be injected into the processes-table-content div
return c.Render("admin/system/processes_data", templateData)
}

View File

@ -4,8 +4,8 @@ import (
"fmt"
"time"
"github.com/freeflowuniverse/heroagent/pkg/processmanager/interfaces"
"github.com/freeflowuniverse/heroagent/pkg/processmanager/interfaces/openrpc"
"git.ourworld.tf/herocode/heroagent/pkg/processmanager/interfaces"
"git.ourworld.tf/herocode/heroagent/pkg/processmanager/interfaces/openrpc"
"github.com/gofiber/fiber/v2"
)

View File

@ -5,7 +5,7 @@ import (
"strings"
"time"
"github.com/freeflowuniverse/heroagent/pkg/system/stats"
"git.ourworld.tf/herocode/heroagent/pkg/system/stats"
"github.com/gofiber/fiber/v2"
"github.com/shirou/gopsutil/v3/host"
)

View File

@ -7,8 +7,8 @@ import (
"strings"
"time"
"github.com/freeflowuniverse/heroagent/pkg/heroagent/handlers"
"github.com/freeflowuniverse/heroagent/pkg/system/stats"
"git.ourworld.tf/herocode/heroagent/pkg/heroagent/handlers"
"git.ourworld.tf/herocode/heroagent/pkg/system/stats"
"github.com/gofiber/fiber/v2"
"github.com/shirou/gopsutil/v3/host"
)

View File

@ -4,7 +4,7 @@ import (
"fmt"
"log"
"github.com/freeflowuniverse/heroagent/pkg/herojobs"
"git.ourworld.tf/herocode/heroagent/pkg/herojobs"
"github.com/gofiber/fiber/v2"
)

View File

@ -4,14 +4,14 @@ import (
"fmt"
"log"
"github.com/freeflowuniverse/heroagent/pkg/processmanager/interfaces/openrpc"
"git.ourworld.tf/herocode/heroagent/pkg/processmanager/interfaces/openrpc"
"github.com/gofiber/fiber/v2"
)
// ServiceHandler handles service-related page routes
type ServiceHandler struct {
client *openrpc.Client
logger *log.Logger
client *openrpc.Client
logger *log.Logger
}
// NewServiceHandler creates a new service handler with the provided socket path and secret

View File

@ -4,7 +4,7 @@ import (
"fmt"
"time"
"github.com/freeflowuniverse/heroagent/pkg/processmanager"
"git.ourworld.tf/herocode/heroagent/pkg/processmanager"
)
// ProcessDisplayInfo represents information about a process for display purposes

View File

@ -7,8 +7,8 @@ import (
"path/filepath"
"time"
"github.com/freeflowuniverse/heroagent/pkg/data/ourdb"
"github.com/freeflowuniverse/heroagent/pkg/tools"
"git.ourworld.tf/herocode/heroagent/pkg/data/ourdb"
"git.ourworld.tf/herocode/heroagent/pkg/tools"
)
// JobStatus represents the status of a job

View File

@ -6,7 +6,7 @@ import (
"strings"
"time"
"github.com/freeflowuniverse/heroagent/pkg/tools"
"git.ourworld.tf/herocode/heroagent/pkg/tools"
"github.com/redis/go-redis/v9"
)

View File

@ -35,7 +35,7 @@ Key features:
```go
import (
"fmt"
"github.com/freeflowuniverse/heroagent/pkg/heroscript/playbook"
"git.ourworld.tf/herocode/heroagent/pkg/heroscript/playbook"
)
// Create a new playbook from HeroScript text

View File

@ -7,7 +7,7 @@ import (
"os/signal"
"syscall"
"github.com/freeflowuniverse/heroagent/pkg/handlerfactory/herohandler"
"git.ourworld.tf/herocode/heroagent/pkg/handlerfactory/herohandler"
)
func main() {

View File

@ -8,7 +8,7 @@ import (
"os"
"strings"
"github.com/freeflowuniverse/heroagent/pkg/heroscript/playbook"
"git.ourworld.tf/herocode/heroagent/pkg/heroscript/playbook"
)
func main() {

View File

@ -3,8 +3,8 @@ package internal
import (
"fmt"
"github.com/freeflowuniverse/heroagent/pkg/handlerfactory"
"github.com/freeflowuniverse/heroagent/pkg/heroscript/handlers"
"git.ourworld.tf/herocode/heroagent/pkg/handlerfactory"
"git.ourworld.tf/herocode/heroagent/pkg/heroscript/handlers"
)
// ExampleHandler handles example actions

View File

@ -7,7 +7,7 @@ import (
"os"
"strings"
"github.com/freeflowuniverse/heroagent/pkg/heroscript/cmd/herohandler/internal"
"git.ourworld.tf/herocode/heroagent/pkg/heroscript/cmd/herohandler/internal"
)
func main() {

View File

@ -10,7 +10,7 @@ import (
"syscall"
"time"
"github.com/freeflowuniverse/heroagent/pkg/handlerfactory/herohandler"
"git.ourworld.tf/herocode/heroagent/pkg/handlerfactory/herohandler"
)
func main() {

View File

@ -4,7 +4,7 @@ import (
"fmt"
"log"
"github.com/freeflowuniverse/heroagent/pkg/heroscript/playbook"
"git.ourworld.tf/herocode/heroagent/pkg/heroscript/playbook"
)
const exampleScript = `

View File

@ -16,7 +16,7 @@ The VM handler example shows how to:
To run the example:
```bash
cd ~/code/github/freeflowuniverse/heroagent/pkg/handlerfactory/cmd/vmhandler
cd ~/code/github/freeflowuniverse/herocode/heroagent/pkg/handlerfactory/cmd/vmhandler
go run . tutorial
#to run just the server do
go run .

View File

@ -6,7 +6,7 @@ import (
"os"
"time"
"github.com/freeflowuniverse/heroagent/pkg/handlerfactory"
"git.ourworld.tf/herocode/heroagent/pkg/handlerfactory"
)
// runTutorial runs an interactive tutorial demonstrating the VM handler

View File

@ -4,7 +4,7 @@ import (
"fmt"
"strings"
"github.com/freeflowuniverse/heroagent/pkg/handlerfactory"
"git.ourworld.tf/herocode/heroagent/pkg/handlerfactory"
)
// VMHandler handles VM-related actions

View File

@ -8,7 +8,7 @@ import (
"path/filepath"
"syscall"
"github.com/freeflowuniverse/heroagent/pkg/handlerfactory"
"git.ourworld.tf/herocode/heroagent/pkg/handlerfactory"
)
// The tutorial functions are defined in tutorial.go

View File

@ -30,7 +30,7 @@ The Handler Factory exposes two interfaces for communication:
to get started
```bash
cd /root/code/github/freeflowuniverse/heroagent/pkg/handlerfactory/herohandler/cmd
cd /root/code/github/freeflowuniverse/herocode/heroagent/pkg/handlerfactory/herohandler/cmd
go run .
```

View File

@ -5,8 +5,8 @@ import (
"reflect"
"strings"
"github.com/freeflowuniverse/heroagent/pkg/heroscript/paramsparser"
"github.com/freeflowuniverse/heroagent/pkg/heroscript/playbook"
"git.ourworld.tf/herocode/heroagent/pkg/heroscript/paramsparser"
"git.ourworld.tf/herocode/heroagent/pkg/heroscript/playbook"
)
// Handler interface defines methods that all handlers must implement

View File

@ -5,7 +5,7 @@ import (
"reflect"
"strings"
"github.com/freeflowuniverse/heroagent/pkg/heroscript/playbook"
"git.ourworld.tf/herocode/heroagent/pkg/heroscript/playbook"
)
// HandlerFactory manages a collection of handlers

View File

@ -12,7 +12,7 @@ import (
"sync"
"syscall"
"github.com/freeflowuniverse/heroagent/pkg/heroscript/playbook"
"git.ourworld.tf/herocode/heroagent/pkg/heroscript/playbook"
)
// ANSI color codes for terminal output
@ -43,23 +43,23 @@ type TelnetServer struct {
sigCh chan os.Signal
onShutdown func()
// Map to store client preferences (like json formatting)
clientPrefs map[net.Conn]map[string]bool
prefsMutex sync.RWMutex
clientPrefs map[net.Conn]map[string]bool
prefsMutex sync.RWMutex
}
// NewTelnetServer creates a new telnet server
func NewTelnetServer(factory *HandlerFactory, secrets ...string) *TelnetServer {
ctx, cancel := context.WithCancel(context.Background())
return &TelnetServer{
factory: factory,
secrets: secrets,
clients: make(map[net.Conn]bool),
factory: factory,
secrets: secrets,
clients: make(map[net.Conn]bool),
clientPrefs: make(map[net.Conn]map[string]bool),
running: false,
ctx: ctx,
cancel: cancel,
sigCh: make(chan os.Signal, 1),
onShutdown: func() {},
running: false,
ctx: ctx,
cancel: cancel,
sigCh: make(chan os.Signal, 1),
onShutdown: func() {},
}
}
@ -466,8 +466,6 @@ func (ts *TelnetServer) addJsonFormat(script string) string {
return strings.Join(lines, "\n")
}
// formatHeroscript formats heroscript with colors for console output only
// This is not used for telnet responses, only for server-side logging
func formatHeroscript(script string) string {

View File

@ -3,7 +3,7 @@ package handlers
import (
"fmt"
"github.com/freeflowuniverse/heroagent/pkg/heroscript/handlerfactory/core"
"git.ourworld.tf/herocode/heroagent/pkg/heroscript/handlerfactory/core"
)
// AuthHandler handles authentication actions

View File

@ -5,9 +5,9 @@ import (
"reflect"
"strings"
"github.com/freeflowuniverse/heroagent/pkg/heroscript/handlerfactory/core"
"github.com/freeflowuniverse/heroagent/pkg/heroscript/paramsparser"
"github.com/freeflowuniverse/heroagent/pkg/heroscript/playbook"
"git.ourworld.tf/herocode/heroagent/pkg/heroscript/handlerfactory/core"
"git.ourworld.tf/herocode/heroagent/pkg/heroscript/paramsparser"
"git.ourworld.tf/herocode/heroagent/pkg/heroscript/playbook"
)
// BaseHandler provides common functionality for all handlers

View File

@ -4,8 +4,8 @@ import (
"fmt"
"strings"
"github.com/freeflowuniverse/heroagent/pkg/heroscript/handlerfactory/core"
"github.com/freeflowuniverse/heroagent/pkg/heroscript/playbook"
"git.ourworld.tf/herocode/heroagent/pkg/heroscript/handlerfactory/core"
"git.ourworld.tf/herocode/heroagent/pkg/heroscript/playbook"
)
// HandlerFactory manages a collection of handlers for processing HeroScript commands

View File

@ -1,7 +1,7 @@
package herohandler
import (
"github.com/freeflowuniverse/heroagent/pkg/heroscript/handlerfactory/core"
"git.ourworld.tf/herocode/heroagent/pkg/heroscript/handlerfactory/core"
)
// GetFactory returns the handler factory

View File

@ -4,7 +4,7 @@ import (
"log"
"sync"
"github.com/freeflowuniverse/heroagent/pkg/heroscript/handlerfactory/herohandler"
"git.ourworld.tf/herocode/heroagent/pkg/heroscript/handlerfactory/herohandler"
)
func main() {

View File

@ -4,10 +4,10 @@ import (
"fmt"
"log"
"github.com/freeflowuniverse/heroagent/pkg/heroscript/handlerfactory/core"
"git.ourworld.tf/herocode/heroagent/pkg/heroscript/handlerfactory/core"
// "github.com/freeflowuniverse/heroagent/pkg/handlerfactory/heroscript/handlerfactory/fakehandler"
"github.com/freeflowuniverse/heroagent/pkg/heroscript/handlerfactory/processmanagerhandler"
// "git.ourworld.tf/herocode/heroagent/pkg/handlerfactory/heroscript/handlerfactory/fakehandler"
"git.ourworld.tf/herocode/heroagent/pkg/heroscript/handlerfactory/processmanagerhandler"
)
// HeroHandler is the main handler factory that manages all registered handlers

View File

@ -3,7 +3,7 @@ package main
import (
"fmt"
"github.com/freeflowuniverse/heroagent/pkg/heroscript/playbook"
"git.ourworld.tf/herocode/heroagent/pkg/heroscript/playbook"
)
func main() {

View File

@ -3,8 +3,8 @@ package processmanagerhandler
import (
"fmt"
"github.com/freeflowuniverse/heroagent/pkg/heroscript/handlerfactory/core"
"github.com/freeflowuniverse/heroagent/pkg/processmanager"
"git.ourworld.tf/herocode/heroagent/pkg/heroscript/handlerfactory/core"
"git.ourworld.tf/herocode/heroagent/pkg/processmanager"
)
// ProcessManagerHandler handles process manager-related actions

View File

@ -19,7 +19,7 @@ A Go package for parsing and manipulating parameters from text in a key-value fo
```go
import (
"github.com/freeflowuniverse/heroagent/pkg/paramsparser"
"git.ourworld.tf/herocode/heroagent/pkg/paramsparser"
)
// Create a new parser

View File

@ -4,7 +4,7 @@ package main
import (
"fmt"
"github.com/freeflowuniverse/heroagent/pkg/heroscript/paramsparser"
"git.ourworld.tf/herocode/heroagent/pkg/heroscript/paramsparser"
)
func main() {

View File

@ -9,7 +9,7 @@ import (
"strconv"
"strings"
"github.com/freeflowuniverse/heroagent/pkg/tools"
"git.ourworld.tf/herocode/heroagent/pkg/tools"
)
// ParamsParser represents a parameter parser that can handle various parameter sources

View File

@ -3,8 +3,8 @@ package playbook
import (
"strings"
"github.com/freeflowuniverse/heroagent/pkg/heroscript/paramsparser"
"github.com/freeflowuniverse/heroagent/pkg/tools"
"git.ourworld.tf/herocode/heroagent/pkg/heroscript/paramsparser"
"git.ourworld.tf/herocode/heroagent/pkg/tools"
)
// State represents the parser state

View File

@ -7,7 +7,7 @@ import (
"sort"
"strings"
"github.com/freeflowuniverse/heroagent/pkg/heroscript/paramsparser"
"git.ourworld.tf/herocode/heroagent/pkg/heroscript/paramsparser"
)
// ActionType represents the type of action

View File

@ -11,7 +11,7 @@ import (
"strings"
"time"
"github.com/freeflowuniverse/heroagent/pkg/heroservices/billing/models"
"git.ourworld.tf/herocode/heroagent/pkg/heroservices/billing/models"
)
const (

View File

@ -7,9 +7,9 @@ import (
"os"
"path/filepath"
"github.com/freeflowuniverse/heroagent/pkg/data/ourdb"
"github.com/freeflowuniverse/heroagent/pkg/data/radixtree"
"github.com/freeflowuniverse/heroagent/pkg/tools"
"git.ourworld.tf/herocode/heroagent/pkg/data/ourdb"
"git.ourworld.tf/herocode/heroagent/pkg/data/radixtree"
"git.ourworld.tf/herocode/heroagent/pkg/tools"
)
// DBStore represents the central database store for all models

View File

@ -9,8 +9,7 @@ import (
"syscall"
"time"
openaiproxy "github.com/freeflowuniverse/heroagent/pkg/heroservices/openaiproxy"
"github.com/openai/openai-go"
openaiproxy "git.ourworld.tf/herocode/heroagent/pkg/heroservices/openaiproxy"
"github.com/openai/openai-go/option"
)

View File

@ -10,7 +10,7 @@ import (
"strings"
"time"
"github.com/freeflowuniverse/heroagent/pkg/jobsmanager"
"git.ourworld.tf/herocode/heroagent/pkg/jobsmanager"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/logger"
)

View File

@ -6,7 +6,7 @@ import (
"path/filepath"
"time"
"github.com/freeflowuniverse/heroagent/pkg/logger"
"git.ourworld.tf/herocode/heroagent/pkg/logger"
)
func main() {

View File

@ -1,209 +0,0 @@
package client
import (
"encoding/json"
"errors"
"fmt"
"net"
"github.com/freeflowuniverse/heroagent/pkg/openrpcmanager"
)
// Common errors
var (
ErrConnectionFailed = errors.New("failed to connect to OpenRPC server")
ErrRequestFailed = errors.New("failed to send request to OpenRPC server")
ErrResponseFailed = errors.New("failed to read response from OpenRPC server")
ErrUnmarshalFailed = errors.New("failed to unmarshal response")
ErrUnexpectedResponse = errors.New("unexpected response format")
ErrRPCError = errors.New("RPC error")
ErrAuthenticationFailed = errors.New("authentication failed")
)
// RPCRequest represents an outgoing RPC request
type RPCRequest struct {
Method string `json:"method"`
Params json.RawMessage `json:"params"`
ID int `json:"id"`
Secret string `json:"secret,omitempty"`
JSONRPC string `json:"jsonrpc"`
}
// RPCResponse represents an incoming RPC response
type RPCResponse struct {
Result interface{} `json:"result,omitempty"`
Error *RPCError `json:"error,omitempty"`
ID interface{} `json:"id,omitempty"`
JSONRPC string `json:"jsonrpc"`
}
// RPCError represents an RPC error
type RPCError struct {
Code int `json:"code"`
Message string `json:"message"`
Data interface{} `json:"data,omitempty"`
}
// Error returns a string representation of the RPC error
func (e *RPCError) Error() string {
if e.Data != nil {
return fmt.Sprintf("RPC error %d: %s - %v", e.Code, e.Message, e.Data)
}
return fmt.Sprintf("RPC error %d: %s", e.Code, e.Message)
}
// IntrospectionResponse represents the response from the rpc.introspect method
type IntrospectionResponse struct {
Logs []openrpcmanager.CallLog `json:"logs"`
Total int `json:"total"`
Filtered int `json:"filtered"`
}
// Client is the interface that all OpenRPC clients must implement
type Client interface {
// Discover returns the OpenRPC schema
Discover() (openrpcmanager.OpenRPCSchema, error)
// Introspect returns information about recent RPC calls
Introspect(limit int, method string, status string) (IntrospectionResponse, error)
// Request sends a request to the OpenRPC server and returns the result
Request(method string, params json.RawMessage, secret string) (interface{}, error)
// Close closes the client connection
Close() error
}
// BaseClient provides a base implementation of the Client interface
type BaseClient struct {
socketPath string
secret string
nextID int
}
// NewClient creates a new OpenRPC client
func NewClient(socketPath, secret string) *BaseClient {
return &BaseClient{
socketPath: socketPath,
secret: secret,
nextID: 1,
}
}
// Discover returns the OpenRPC schema
func (c *BaseClient) Discover() (openrpcmanager.OpenRPCSchema, error) {
result, err := c.Request("rpc.discover", json.RawMessage("{}"), "")
if err != nil {
return openrpcmanager.OpenRPCSchema{}, err
}
// Convert result to schema
resultJSON, err := json.Marshal(result)
if err != nil {
return openrpcmanager.OpenRPCSchema{}, fmt.Errorf("%w: %v", ErrUnmarshalFailed, err)
}
var schema openrpcmanager.OpenRPCSchema
if err := json.Unmarshal(resultJSON, &schema); err != nil {
return openrpcmanager.OpenRPCSchema{}, fmt.Errorf("%w: %v", ErrUnmarshalFailed, err)
}
return schema, nil
}
// Introspect returns information about recent RPC calls
func (c *BaseClient) Introspect(limit int, method string, status string) (IntrospectionResponse, error) {
// Create the params object
params := struct {
Limit int `json:"limit,omitempty"`
Method string `json:"method,omitempty"`
Status string `json:"status,omitempty"`
}{
Limit: limit,
Method: method,
Status: status,
}
// Marshal the params
paramsJSON, err := json.Marshal(params)
if err != nil {
return IntrospectionResponse{}, fmt.Errorf("failed to marshal introspection params: %v", err)
}
// Make the request
result, err := c.Request("rpc.introspect", paramsJSON, c.secret)
if err != nil {
return IntrospectionResponse{}, err
}
// Convert result to introspection response
resultJSON, err := json.Marshal(result)
if err != nil {
return IntrospectionResponse{}, fmt.Errorf("%w: %v", ErrUnmarshalFailed, err)
}
var response IntrospectionResponse
if err := json.Unmarshal(resultJSON, &response); err != nil {
return IntrospectionResponse{}, fmt.Errorf("%w: %v", ErrUnmarshalFailed, err)
}
return response, nil
}
// Request sends a request to the OpenRPC server and returns the result
func (c *BaseClient) Request(method string, params json.RawMessage, secret string) (interface{}, error) {
// Connect to the Unix socket
conn, err := net.Dial("unix", c.socketPath)
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrConnectionFailed, err)
}
defer conn.Close()
// Create the request
request := RPCRequest{
Method: method,
Params: params,
ID: c.nextID,
Secret: secret,
JSONRPC: "2.0",
}
c.nextID++
// Marshal the request
requestData, err := json.Marshal(request)
if err != nil {
return nil, fmt.Errorf("failed to marshal request: %v", err)
}
// Send the request
_, err = conn.Write(requestData)
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrRequestFailed, err)
}
// Read the response
buf := make([]byte, 4096)
n, err := conn.Read(buf)
if err != nil {
return nil, fmt.Errorf("%w: %v", ErrResponseFailed, err)
}
// Parse the response
var response RPCResponse
if err := json.Unmarshal(buf[:n], &response); err != nil {
return nil, fmt.Errorf("%w: %v", ErrUnmarshalFailed, err)
}
// Check for errors
if response.Error != nil {
return nil, fmt.Errorf("%w: %v", ErrRPCError, response.Error)
}
return response.Result, nil
}
// Close closes the client connection
func (c *BaseClient) Close() error {
// Nothing to do for the base client since we create a new connection for each request
return nil
}

View File

@ -1,283 +0,0 @@
package client
import (
"encoding/json"
"os"
"path/filepath"
"testing"
"time"
"github.com/freeflowuniverse/heroagent/pkg/openrpcmanager"
)
// MockClient implements the Client interface for testing
type MockClient struct {
BaseClient
}
// TestMethod is a test method that returns a greeting
func (c *MockClient) TestMethod(name string) (string, error) {
params := map[string]string{"name": name}
paramsJSON, err := json.Marshal(params)
if err != nil {
return "", err
}
result, err := c.Request("test.method", paramsJSON, "")
if err != nil {
return "", err
}
// Convert result to string
greeting, ok := result.(string)
if !ok {
return "", ErrUnexpectedResponse
}
return greeting, nil
}
// SecureMethod is a test method that requires authentication
func (c *MockClient) SecureMethod() (map[string]interface{}, error) {
result, err := c.Request("secure.method", json.RawMessage("{}"), c.secret)
if err != nil {
return nil, err
}
// Convert result to map
data, ok := result.(map[string]interface{})
if !ok {
return nil, ErrUnexpectedResponse
}
return data, nil
}
func TestClient(t *testing.T) {
// Create a temporary socket path
tempDir, err := os.MkdirTemp("", "openrpc-client-test")
if err != nil {
t.Fatalf("Failed to create temp directory: %v", err)
}
defer os.RemoveAll(tempDir)
socketPath := filepath.Join(tempDir, "openrpc.sock")
secret := "test-secret"
// Create test schema and handlers
schema := openrpcmanager.OpenRPCSchema{
OpenRPC: "1.2.6",
Info: openrpcmanager.InfoObject{
Title: "Test API",
Version: "1.0.0",
},
Methods: []openrpcmanager.MethodObject{
{
Name: "test.method",
Params: []openrpcmanager.ContentDescriptorObject{
{
Name: "name",
Schema: openrpcmanager.SchemaObject{"type": "string"},
},
},
Result: &openrpcmanager.ContentDescriptorObject{
Name: "result",
Schema: openrpcmanager.SchemaObject{"type": "string"},
},
},
{
Name: "secure.method",
Params: []openrpcmanager.ContentDescriptorObject{},
Result: &openrpcmanager.ContentDescriptorObject{
Name: "result",
Schema: openrpcmanager.SchemaObject{"type": "object"},
},
},
},
}
handlers := map[string]openrpcmanager.RPCHandler{
"test.method": func(params json.RawMessage) (interface{}, error) {
var request struct {
Name string `json:"name"`
}
if err := json.Unmarshal(params, &request); err != nil {
return nil, err
}
return "Hello, " + request.Name + "!", nil
},
"secure.method": func(params json.RawMessage) (interface{}, error) {
return map[string]interface{}{
"secure": true,
"data": "sensitive information",
}, nil
},
}
// Create and start OpenRPC manager and Unix server
manager, err := openrpcmanager.NewOpenRPCManager(schema, handlers, secret)
if err != nil {
t.Fatalf("Failed to create OpenRPCManager: %v", err)
}
server, err := openrpcmanager.NewUnixServer(manager, socketPath)
if err != nil {
t.Fatalf("Failed to create UnixServer: %v", err)
}
if err := server.Start(); err != nil {
t.Fatalf("Failed to start UnixServer: %v", err)
}
defer server.Stop()
// Wait for server to start
time.Sleep(100 * time.Millisecond)
// Create client
client := &MockClient{
BaseClient: BaseClient{
socketPath: socketPath,
secret: secret,
},
}
// Test Discover method
t.Run("Discover", func(t *testing.T) {
schema, err := client.Discover()
if err != nil {
t.Fatalf("Discover failed: %v", err)
}
if schema.OpenRPC != "1.2.6" {
t.Errorf("Expected OpenRPC version 1.2.6, got: %s", schema.OpenRPC)
}
if len(schema.Methods) < 2 {
t.Errorf("Expected at least 2 methods, got: %d", len(schema.Methods))
}
// Check if our test methods are in the schema
foundTestMethod := false
foundSecureMethod := false
for _, method := range schema.Methods {
if method.Name == "test.method" {
foundTestMethod = true
}
if method.Name == "secure.method" {
foundSecureMethod = true
}
}
if !foundTestMethod {
t.Error("test.method not found in schema")
}
if !foundSecureMethod {
t.Error("secure.method not found in schema")
}
})
// Test TestMethod
t.Run("TestMethod", func(t *testing.T) {
greeting, err := client.TestMethod("World")
if err != nil {
t.Fatalf("TestMethod failed: %v", err)
}
expected := "Hello, World!"
if greeting != expected {
t.Errorf("Expected greeting %q, got: %q", expected, greeting)
}
})
// Test Introspect method
t.Run("Introspect", func(t *testing.T) {
// Make several requests to generate logs
_, err := client.TestMethod("World")
if err != nil {
t.Fatalf("TestMethod failed: %v", err)
}
_, err = client.SecureMethod()
if err != nil {
t.Fatalf("SecureMethod failed: %v", err)
}
// Test introspection
response, err := client.Introspect(10, "", "")
if err != nil {
t.Fatalf("Introspect failed: %v", err)
}
// Verify we have logs
if response.Total < 2 {
t.Errorf("Expected at least 2 logs, got: %d", response.Total)
}
// Test filtering by method
response, err = client.Introspect(10, "test.method", "")
if err != nil {
t.Fatalf("Introspect with method filter failed: %v", err)
}
// Verify filtering works
for _, log := range response.Logs {
if log.Method != "test.method" {
t.Errorf("Expected only test.method logs, got: %s", log.Method)
}
}
// Test filtering by status
response, err = client.Introspect(10, "", "success")
if err != nil {
t.Fatalf("Introspect with status filter failed: %v", err)
}
// Verify status filtering works
for _, log := range response.Logs {
if log.Status != "success" {
t.Errorf("Expected only success logs, got: %s", log.Status)
}
}
})
// Test SecureMethod with valid secret
t.Run("SecureMethod", func(t *testing.T) {
data, err := client.SecureMethod()
if err != nil {
t.Fatalf("SecureMethod failed: %v", err)
}
secure, ok := data["secure"].(bool)
if !ok || !secure {
t.Errorf("Expected secure to be true, got: %v", data["secure"])
}
sensitiveData, ok := data["data"].(string)
if !ok || sensitiveData != "sensitive information" {
t.Errorf("Expected data to be 'sensitive information', got: %v", data["data"])
}
})
// Test SecureMethod with invalid secret
t.Run("SecureMethod with invalid secret", func(t *testing.T) {
invalidClient := &MockClient{
BaseClient: BaseClient{
socketPath: socketPath,
secret: "wrong-secret",
},
}
_, err := invalidClient.SecureMethod()
if err == nil {
t.Error("Expected error for invalid secret, but got nil")
}
})
// Test non-existent method
t.Run("Non-existent method", func(t *testing.T) {
_, err := client.Request("non.existent", json.RawMessage("{}"), "")
if err == nil {
t.Error("Expected error for non-existent method, but got nil")
}
})
}

View File

@ -1,113 +0,0 @@
package main
import (
"encoding/json"
"flag"
"fmt"
"log"
"os"
"os/signal"
"syscall"
"github.com/freeflowuniverse/heroagent/pkg/openrpcmanager"
)
func main() {
// Parse command line arguments
socketPath := flag.String("socket", "/tmp/openrpc.sock", "Path to the Unix socket")
secret := flag.String("secret", "test-secret", "Secret for authenticated methods")
flag.Parse()
// Create a simple OpenRPC schema
schema := openrpcmanager.OpenRPCSchema{
OpenRPC: "1.2.6",
Info: openrpcmanager.InfoObject{
Title: "Hero Launcher API",
Version: "1.0.0",
},
Methods: []openrpcmanager.MethodObject{
{
Name: "echo",
Params: []openrpcmanager.ContentDescriptorObject{
{
Name: "message",
Schema: openrpcmanager.SchemaObject{"type": "object"},
},
},
Result: &openrpcmanager.ContentDescriptorObject{
Name: "result",
Schema: openrpcmanager.SchemaObject{"type": "object"},
},
},
{
Name: "ping",
Params: []openrpcmanager.ContentDescriptorObject{},
Result: &openrpcmanager.ContentDescriptorObject{
Name: "result",
Schema: openrpcmanager.SchemaObject{"type": "string"},
},
},
{
Name: "secure.info",
Params: []openrpcmanager.ContentDescriptorObject{},
Result: &openrpcmanager.ContentDescriptorObject{
Name: "result",
Schema: openrpcmanager.SchemaObject{"type": "object"},
},
},
},
}
// Create handlers
handlers := map[string]openrpcmanager.RPCHandler{
"echo": func(params json.RawMessage) (interface{}, error) {
var data interface{}
if err := json.Unmarshal(params, &data); err != nil {
return nil, err
}
return data, nil
},
"ping": func(params json.RawMessage) (interface{}, error) {
return "pong", nil
},
"secure.info": func(params json.RawMessage) (interface{}, error) {
return map[string]interface{}{
"server": "Hero Launcher",
"version": "1.0.0",
"status": "running",
}, nil
},
}
// Create OpenRPC manager
manager, err := openrpcmanager.NewOpenRPCManager(schema, handlers, *secret)
if err != nil {
log.Fatalf("Failed to create OpenRPC manager: %v", err)
}
// Create Unix server
server, err := openrpcmanager.NewUnixServer(manager, *socketPath)
if err != nil {
log.Fatalf("Failed to create Unix server: %v", err)
}
// Start the server
if err := server.Start(); err != nil {
log.Fatalf("Failed to start Unix server: %v", err)
}
defer server.Stop()
fmt.Printf("OpenRPC server started on Unix socket: %s\n", *socketPath)
fmt.Println("Available methods:")
for _, method := range manager.ListMethods() {
fmt.Printf(" - %s\n", method)
}
fmt.Println("\nPress Ctrl+C to stop the server")
// Wait for interrupt signal
sigCh := make(chan os.Signal, 1)
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
<-sigCh
fmt.Println("\nShutting down...")
}

View File

@ -1,112 +0,0 @@
package main
import (
"encoding/json"
"flag"
"fmt"
"net"
"os"
)
// RPCRequest represents an outgoing RPC request
type RPCRequest struct {
Method string `json:"method"`
Params json.RawMessage `json:"params"`
ID interface{} `json:"id,omitempty"`
Secret string `json:"secret,omitempty"`
JSONRPC string `json:"jsonrpc"`
}
// RPCResponse represents an incoming RPC response
type RPCResponse struct {
Result interface{} `json:"result,omitempty"`
Error *RPCError `json:"error,omitempty"`
ID interface{} `json:"id,omitempty"`
JSONRPC string `json:"jsonrpc"`
}
// RPCError represents an RPC error
type RPCError struct {
Code int `json:"code"`
Message string `json:"message"`
Data interface{} `json:"data,omitempty"`
}
func main() {
// Parse command line arguments
socketPath := flag.String("socket", "/tmp/openrpc.sock", "Path to the Unix socket")
method := flag.String("method", "rpc.discover", "RPC method to call")
params := flag.String("params", "{}", "JSON parameters for the method")
secret := flag.String("secret", "", "Secret for authenticated methods")
flag.Parse()
// Connect to the Unix socket
conn, err := net.Dial("unix", *socketPath)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to connect to Unix socket: %v\n", err)
os.Exit(1)
}
defer conn.Close()
// Create the request
var paramsJSON json.RawMessage
if err := json.Unmarshal([]byte(*params), &paramsJSON); err != nil {
fmt.Fprintf(os.Stderr, "Invalid JSON parameters: %v\n", err)
os.Exit(1)
}
request := RPCRequest{
Method: *method,
Params: paramsJSON,
ID: 1,
Secret: *secret,
JSONRPC: "2.0",
}
// Marshal the request
requestData, err := json.Marshal(request)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to marshal request: %v\n", err)
os.Exit(1)
}
// Send the request
_, err = conn.Write(requestData)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to send request: %v\n", err)
os.Exit(1)
}
// Read the response
buf := make([]byte, 4096)
n, err := conn.Read(buf)
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to read response: %v\n", err)
os.Exit(1)
}
// Parse the response
var response RPCResponse
if err := json.Unmarshal(buf[:n], &response); err != nil {
fmt.Fprintf(os.Stderr, "Failed to unmarshal response: %v\n", err)
os.Exit(1)
}
// Check for errors
if response.Error != nil {
fmt.Fprintf(os.Stderr, "Error: %s (code: %d)\n", response.Error.Message, response.Error.Code)
if response.Error.Data != nil {
fmt.Fprintf(os.Stderr, "Error data: %v\n", response.Error.Data)
}
os.Exit(1)
}
// Print the result
resultJSON, err := json.MarshalIndent(response.Result, "", " ")
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to marshal result: %v\n", err)
os.Exit(1)
}
fmt.Println(string(resultJSON))
}

View File

@ -1,416 +0,0 @@
// Package openrpcmanager provides functionality for managing and handling OpenRPC method calls.
package openrpcmanager
import (
"encoding/json"
"fmt"
"sync"
"time"
)
// RPCHandler is a function that handles an OpenRPC method call
type RPCHandler func(params json.RawMessage) (interface{}, error)
// CallLog represents a log entry for an RPC method call
type CallLog struct {
Timestamp time.Time `json:"timestamp"` // When the call was made
Method string `json:"method"` // Method that was called
Params interface{} `json:"params"` // Parameters passed to the method (may be redacted for security)
Duration time.Duration `json:"duration"` // How long the call took to execute
Status string `json:"status"` // Success or error
ErrorMsg string `json:"error,omitempty"` // Error message if status is error
Authenticated bool `json:"authenticated"` // Whether the call was authenticated
}
// OpenRPCManager manages OpenRPC method handlers and processes requests
type OpenRPCManager struct {
handlers map[string]RPCHandler
schema OpenRPCSchema
mutex sync.RWMutex
secret string
// Call logging
callLogs []CallLog
callLogsMutex sync.RWMutex
maxCallLogs int // Maximum number of call logs to keep
}
// NewOpenRPCManager creates a new OpenRPC manager with the given schema and handlers
func NewOpenRPCManager(schema OpenRPCSchema, handlers map[string]RPCHandler, secret string) (*OpenRPCManager, error) {
manager := &OpenRPCManager{
handlers: make(map[string]RPCHandler),
schema: schema,
secret: secret,
callLogs: make([]CallLog, 0, 100),
maxCallLogs: 1000, // Default to keeping the last 1000 calls
}
// Validate that all methods in the schema have corresponding handlers
for _, method := range schema.Methods {
handler, exists := handlers[method.Name]
if !exists {
return nil, fmt.Errorf("missing handler for method '%s' defined in schema", method.Name)
}
manager.handlers[method.Name] = handler
}
// Check for handlers that don't have a corresponding method in the schema
for name := range handlers {
found := false
for _, method := range schema.Methods {
if method.Name == name {
found = true
break
}
}
if !found {
return nil, fmt.Errorf("handler '%s' has no corresponding method in schema", name)
}
}
// Add the discovery method
manager.handlers["rpc.discover"] = manager.handleDiscovery
// Add the introspection method
manager.handlers["rpc.introspect"] = manager.handleIntrospection
return manager, nil
}
// handleDiscovery implements the OpenRPC service discovery method
func (m *OpenRPCManager) handleDiscovery(params json.RawMessage) (interface{}, error) {
return m.schema, nil
}
// handleIntrospection implements the OpenRPC service introspection method
// It returns information about recent RPC calls for monitoring and debugging
func (m *OpenRPCManager) handleIntrospection(params json.RawMessage) (interface{}, error) {
m.callLogsMutex.RLock()
defer m.callLogsMutex.RUnlock()
// Parse parameters to see if we need to filter or limit results
var requestParams struct {
Limit int `json:"limit,omitempty"`
Method string `json:"method,omitempty"`
Status string `json:"status,omitempty"`
}
// Default limit to 100 if not specified
requestParams.Limit = 100
// Try to parse parameters, but don't fail if they're invalid
if len(params) > 0 {
_ = json.Unmarshal(params, &requestParams)
}
// Apply limit
if requestParams.Limit <= 0 || requestParams.Limit > m.maxCallLogs {
requestParams.Limit = 100
}
// Create a copy of the logs to avoid holding the lock while filtering
allLogs := make([]CallLog, len(m.callLogs))
copy(allLogs, m.callLogs)
// Filter logs based on parameters
filteredLogs := []CallLog{}
for i := len(allLogs) - 1; i >= 0 && len(filteredLogs) < requestParams.Limit; i-- {
log := allLogs[i]
// Apply method filter if specified
if requestParams.Method != "" && log.Method != requestParams.Method {
continue
}
// Apply status filter if specified
if requestParams.Status != "" && log.Status != requestParams.Status {
continue
}
filteredLogs = append(filteredLogs, log)
}
// Create response
response := struct {
Logs []CallLog `json:"logs"`
Total int `json:"total"`
Filtered int `json:"filtered"`
}{
Logs: filteredLogs,
Total: len(allLogs),
Filtered: len(filteredLogs),
}
return response, nil
}
// RegisterHandler is deprecated. Use NewOpenRPCManager with a complete set of handlers instead.
// This method is kept for backward compatibility but will return an error for methods not in the schema.
func (m *OpenRPCManager) RegisterHandler(method string, handler RPCHandler) error {
m.mutex.Lock()
defer m.mutex.Unlock()
// Check if handler already exists
if _, exists := m.handlers[method]; exists {
return fmt.Errorf("handler for method '%s' already registered", method)
}
// Check if method exists in schema
found := false
for _, schemaMethod := range m.schema.Methods {
if schemaMethod.Name == method {
found = true
break
}
}
if !found && method != "rpc.discover" {
return fmt.Errorf("method '%s' not defined in schema", method)
}
m.handlers[method] = handler
return nil
}
// UnregisterHandler removes a handler for the specified method
// Note: This will make the service non-compliant with its schema
func (m *OpenRPCManager) UnregisterHandler(method string) error {
m.mutex.Lock()
defer m.mutex.Unlock()
// Check if handler exists
if _, exists := m.handlers[method]; !exists {
return fmt.Errorf("handler for method '%s' not found", method)
}
// Don't allow unregistering the discovery method
if method == "rpc.discover" {
return fmt.Errorf("cannot unregister the discovery method 'rpc.discover'")
}
delete(m.handlers, method)
return nil
}
// HandleRequest processes an RPC request for the specified method
func (m *OpenRPCManager) HandleRequest(method string, params json.RawMessage) (interface{}, error) {
// Start timing the request
startTime := time.Now()
// Create a call log entry
callLog := CallLog{
Timestamp: startTime,
Method: method,
Authenticated: false,
}
// Parse params for logging, but don't fail if we can't
var parsedParams interface{}
if len(params) > 0 {
if err := json.Unmarshal(params, &parsedParams); err == nil {
callLog.Params = parsedParams
} else {
// If we can't parse the params, just store them as a string
callLog.Params = string(params)
}
}
// Find the handler
m.mutex.RLock()
handler, exists := m.handlers[method]
m.mutex.RUnlock()
if !exists {
// Log the error
callLog.Status = "error"
callLog.ErrorMsg = fmt.Sprintf("method '%s' not found", method)
callLog.Duration = time.Since(startTime)
// Add to call logs
m.logCall(callLog)
return nil, fmt.Errorf("method '%s' not found", method)
}
// Execute the handler
result, err := handler(params)
// Complete the call log
callLog.Duration = time.Since(startTime)
if err != nil {
callLog.Status = "error"
callLog.ErrorMsg = err.Error()
} else {
callLog.Status = "success"
}
// Add to call logs
m.logCall(callLog)
return result, err
}
// logCall adds a call log entry to the call logs, maintaining the maximum size
func (m *OpenRPCManager) logCall(log CallLog) {
m.callLogsMutex.Lock()
defer m.callLogsMutex.Unlock()
// Add the log to the call logs
m.callLogs = append(m.callLogs, log)
// Trim the call logs if they exceed the maximum size
if len(m.callLogs) > m.maxCallLogs {
m.callLogs = m.callLogs[len(m.callLogs)-m.maxCallLogs:]
}
}
// HandleRequestWithAuthentication processes an authenticated RPC request
func (m *OpenRPCManager) HandleRequestWithAuthentication(method string, params json.RawMessage, secret string) (interface{}, error) {
// Start timing the request
startTime := time.Now()
// Create a call log entry
callLog := CallLog{
Timestamp: startTime,
Method: method,
Authenticated: true,
}
// Parse params for logging, but don't fail if we can't
var parsedParams interface{}
if len(params) > 0 {
if err := json.Unmarshal(params, &parsedParams); err == nil {
callLog.Params = parsedParams
} else {
// If we can't parse the params, just store them as a string
callLog.Params = string(params)
}
}
// Verify the secret
if secret != m.secret {
// Log the authentication failure
callLog.Status = "error"
callLog.ErrorMsg = "authentication failed"
callLog.Duration = time.Since(startTime)
m.logCall(callLog)
return nil, fmt.Errorf("authentication failed")
}
// Execute the handler
m.mutex.RLock()
handler, exists := m.handlers[method]
m.mutex.RUnlock()
if !exists {
// Log the error
callLog.Status = "error"
callLog.ErrorMsg = fmt.Sprintf("method '%s' not found", method)
callLog.Duration = time.Since(startTime)
m.logCall(callLog)
return nil, fmt.Errorf("method '%s' not found", method)
}
// Execute the handler
result, err := handler(params)
// Complete the call log
callLog.Duration = time.Since(startTime)
if err != nil {
callLog.Status = "error"
callLog.ErrorMsg = err.Error()
} else {
callLog.Status = "success"
}
// Add to call logs
m.logCall(callLog)
return result, err
}
// ListMethods returns a list of all registered method names
func (m *OpenRPCManager) ListMethods() []string {
m.mutex.RLock()
defer m.mutex.RUnlock()
methods := make([]string, 0, len(m.handlers))
for method := range m.handlers {
methods = append(methods, method)
}
return methods
}
// GetSecret returns the authentication secret
func (m *OpenRPCManager) GetSecret() string {
return m.secret
}
// GetSchema returns the OpenRPC schema
func (m *OpenRPCManager) GetSchema() OpenRPCSchema {
return m.schema
}
// NewDefaultOpenRPCManager creates a new OpenRPC manager with a default schema
// This is provided for backward compatibility and testing
func NewDefaultOpenRPCManager(secret string) *OpenRPCManager {
// Create a minimal default schema
defaultSchema := OpenRPCSchema{
OpenRPC: "1.2.6",
Info: InfoObject{
Title: "Default OpenRPC Service",
Version: "1.0.0",
},
Methods: []MethodObject{
{
Name: "rpc.discover",
Description: "Returns the OpenRPC schema for this service",
Params: []ContentDescriptorObject{},
Result: &ContentDescriptorObject{
Name: "schema",
Description: "The OpenRPC schema",
Schema: SchemaObject{"type": "object"},
},
},
{
Name: "rpc.introspect",
Description: "Returns information about recent RPC calls for monitoring and debugging",
Params: []ContentDescriptorObject{
{
Name: "limit",
Description: "Maximum number of call logs to return",
Required: false,
Schema: SchemaObject{"type": "integer", "default": 100},
},
{
Name: "method",
Description: "Filter logs by method name",
Required: false,
Schema: SchemaObject{"type": "string"},
},
{
Name: "status",
Description: "Filter logs by status (success or error)",
Required: false,
Schema: SchemaObject{"type": "string", "enum": []interface{}{"success", "error"}},
},
},
Result: &ContentDescriptorObject{
Name: "introspection",
Description: "Introspection data including call logs",
Schema: SchemaObject{"type": "object"},
},
},
},
}
// Create the manager directly without validation since we're starting with empty methods
return &OpenRPCManager{
handlers: make(map[string]RPCHandler),
schema: defaultSchema,
secret: secret,
}
}

View File

@ -1,446 +0,0 @@
package openrpcmanager
import (
"encoding/json"
"testing"
"time"
"github.com/stretchr/testify/assert"
)
// createTestSchema creates a test OpenRPC schema
func createTestSchema() OpenRPCSchema {
return OpenRPCSchema{
OpenRPC: "1.2.6",
Info: InfoObject{
Title: "Test API",
Version: "1.0.0",
},
Methods: []MethodObject{
{
Name: "echo",
Params: []ContentDescriptorObject{
{
Name: "message",
Schema: SchemaObject{"type": "object"},
},
},
Result: &ContentDescriptorObject{
Name: "result",
Schema: SchemaObject{"type": "object"},
},
},
{
Name: "add",
Params: []ContentDescriptorObject{
{
Name: "numbers",
Schema: SchemaObject{"type": "object"},
},
},
Result: &ContentDescriptorObject{
Name: "result",
Schema: SchemaObject{"type": "number"},
},
},
{
Name: "secure.method",
Params: []ContentDescriptorObject{},
Result: &ContentDescriptorObject{
Name: "result",
Schema: SchemaObject{"type": "string"},
},
},
},
}
}
// createTestHandlers creates test handlers for the schema
func createTestHandlers() map[string]RPCHandler {
return map[string]RPCHandler{
"echo": func(params json.RawMessage) (interface{}, error) {
var data interface{}
if err := json.Unmarshal(params, &data); err != nil {
return nil, err
}
return data, nil
},
"add": func(params json.RawMessage) (interface{}, error) {
var numbers struct {
A float64 `json:"a"`
B float64 `json:"b"`
}
if err := json.Unmarshal(params, &numbers); err != nil {
return nil, err
}
return numbers.A + numbers.B, nil
},
"secure.method": func(params json.RawMessage) (interface{}, error) {
return "secure data", nil
},
}
}
// TestNewOpenRPCManager tests the creation of a new OpenRPC manager
func TestNewOpenRPCManager(t *testing.T) {
secret := "test-secret"
schema := createTestSchema()
handlers := createTestHandlers()
manager, err := NewOpenRPCManager(schema, handlers, secret)
if err != nil {
t.Fatalf("Failed to create OpenRPCManager: %v", err)
}
if manager == nil {
t.Fatal("Manager is nil")
}
if manager.GetSecret() != secret {
t.Errorf("Secret mismatch. Expected: %s, Got: %s", secret, manager.GetSecret())
}
if manager.handlers == nil {
t.Error("handlers map not initialized")
}
// Test the default manager for backward compatibility
defaultManager := NewDefaultOpenRPCManager(secret)
if defaultManager == nil {
t.Fatal("Default manager is nil")
}
if defaultManager.GetSecret() != secret {
t.Errorf("Secret mismatch in default manager. Expected: %s, Got: %s", secret, defaultManager.GetSecret())
}
}
// TestRegisterHandler tests registering a handler to the OpenRPC manager
func TestRegisterHandler(t *testing.T) {
manager := NewDefaultOpenRPCManager("test-secret")
// Define a mock handler
mockHandler := func(params json.RawMessage) (interface{}, error) {
return "mock response", nil
}
// Add a method to the schema
manager.schema.Methods = append(manager.schema.Methods, MethodObject{
Name: "test.method",
Params: []ContentDescriptorObject{},
Result: &ContentDescriptorObject{
Name: "result",
Schema: SchemaObject{"type": "string"},
},
})
// Register the handler
err := manager.RegisterHandler("test.method", mockHandler)
if err != nil {
t.Fatalf("Failed to register handler: %v", err)
}
// Check if handler was registered
if _, exists := manager.handlers["test.method"]; !exists {
t.Error("Handler was not registered")
}
// Try to register the same handler again, should fail
err = manager.RegisterHandler("test.method", mockHandler)
if err == nil {
t.Error("Expected error when registering duplicate handler, but got nil")
}
// Try to register a handler for a method not in the schema
err = manager.RegisterHandler("not.in.schema", mockHandler)
if err == nil {
t.Error("Expected error when registering handler for method not in schema, but got nil")
}
}
// TestHandleRequest tests handling an RPC request
func TestHandleRequest(t *testing.T) {
schema := createTestSchema()
handlers := createTestHandlers()
manager, err := NewOpenRPCManager(schema, handlers, "test-secret")
if err != nil {
t.Fatalf("Failed to create OpenRPCManager: %v", err)
}
// Test the echo handler
testParams := json.RawMessage(`{"message":"hello world"}`)
result, err := manager.HandleRequest("echo", testParams)
if err != nil {
t.Fatalf("Failed to handle request: %v", err)
}
// Convert result to map for comparison
resultMap, ok := result.(map[string]interface{})
if !ok {
t.Fatalf("Expected map result, got: %T", result)
}
if resultMap["message"] != "hello world" {
t.Errorf("Expected 'hello world', got: %v", resultMap["message"])
}
// Test the add handler
addParams := json.RawMessage(`{"a":5,"b":7}`)
addResult, err := manager.HandleRequest("add", addParams)
if err != nil {
t.Fatalf("Failed to handle add request: %v", err)
}
// Check the result type and value
resultValue, ok := addResult.(float64)
if !ok {
t.Fatalf("Expected result type float64, got: %T", addResult)
}
if resultValue != float64(12) {
t.Errorf("Expected 12, got: %v", resultValue)
}
// Test with non-existent method
_, err = manager.HandleRequest("nonexistent", testParams)
if err == nil {
t.Error("Expected error for non-existent method, but got nil")
}
// Test the discovery method
discoveryResult, err := manager.HandleRequest("rpc.discover", json.RawMessage(`{}`))
if err != nil {
t.Fatalf("Failed to handle discovery request: %v", err)
}
// Verify the discovery result is the schema
discoverySchema, ok := discoveryResult.(OpenRPCSchema)
if !ok {
t.Fatalf("Expected OpenRPCSchema result, got: %T", discoveryResult)
}
if discoverySchema.OpenRPC != schema.OpenRPC {
t.Errorf("Expected OpenRPC version %s, got: %s", schema.OpenRPC, discoverySchema.OpenRPC)
}
if len(discoverySchema.Methods) != len(schema.Methods) {
t.Errorf("Expected %d methods, got: %d", len(schema.Methods), len(discoverySchema.Methods))
}
}
// TestHandleRequestWithAuthentication tests handling a request with authentication
func TestHandleRequestWithAuthentication(t *testing.T) {
secret := "test-secret"
schema := createTestSchema()
handlers := createTestHandlers()
manager, err := NewOpenRPCManager(schema, handlers, secret)
if err != nil {
t.Fatalf("Failed to create OpenRPCManager: %v", err)
}
// Test with correct secret
result, err := manager.HandleRequestWithAuthentication("secure.method", json.RawMessage(`{}`), secret)
if err != nil {
t.Fatalf("Failed to handle authenticated request: %v", err)
}
if result != "secure data" {
t.Errorf("Expected 'secure data', got: %v", result)
}
// Test with incorrect secret
_, err = manager.HandleRequestWithAuthentication("secure.method", json.RawMessage(`{}`), "wrong-secret")
if err == nil {
t.Error("Expected authentication error, but got nil")
}
}
// TestUnregisterHandler tests removing a handler from the OpenRPC manager
func TestUnregisterHandler(t *testing.T) {
manager := NewDefaultOpenRPCManager("test-secret")
// Define a mock handler
mockHandler := func(params json.RawMessage) (interface{}, error) {
return "mock response", nil
}
// Add a method to the schema
manager.schema.Methods = append(manager.schema.Methods, MethodObject{
Name: "test.method",
Params: []ContentDescriptorObject{},
Result: &ContentDescriptorObject{
Name: "result",
Schema: SchemaObject{"type": "string"},
},
})
// Register the handler
manager.RegisterHandler("test.method", mockHandler)
// Unregister the handler
err := manager.UnregisterHandler("test.method")
if err != nil {
t.Fatalf("Failed to unregister handler: %v", err)
}
// Check if handler was unregistered
if _, exists := manager.handlers["test.method"]; exists {
t.Error("Handler was not unregistered")
}
// Try to unregister non-existent handler
err = manager.UnregisterHandler("nonexistent")
if err == nil {
t.Error("Expected error when unregistering non-existent handler, but got nil")
}
// Try to unregister the discovery method
err = manager.UnregisterHandler("rpc.discover")
if err == nil {
t.Error("Expected error when unregistering discovery method, but got nil")
}
}
// TestIntrospection tests the introspection functionality
func TestIntrospection(t *testing.T) {
// Create a test manager
schema := createTestSchema()
handlers := createTestHandlers()
manager, err := NewOpenRPCManager(schema, handlers, "test-secret")
assert.NoError(t, err)
// The introspection handler is already registered in NewOpenRPCManager
// Make some test calls to generate logs
_, err = manager.HandleRequest("echo", json.RawMessage(`{"message":"hello"}`))
assert.NoError(t, err)
_, err = manager.HandleRequestWithAuthentication("echo", json.RawMessage(`{"message":"authenticated"}`), "test-secret")
assert.NoError(t, err)
_, err = manager.HandleRequestWithAuthentication("echo", json.RawMessage(`{"message":"auth-fail"}`), "wrong-secret")
assert.Error(t, err)
// Wait a moment to ensure timestamps are different
time.Sleep(10 * time.Millisecond)
// Call the introspection handler
result, err := manager.handleIntrospection(json.RawMessage(`{"limit":10}`))
assert.NoError(t, err)
// Verify the result
response, ok := result.(struct {
Logs []CallLog `json:"logs"`
Total int `json:"total"`
Filtered int `json:"filtered"`
})
assert.True(t, ok)
// Should have 3 logs (2 successful calls, 1 auth failure)
assert.Equal(t, 3, response.Total)
assert.Equal(t, 3, response.Filtered)
assert.Len(t, response.Logs, 3)
// Test filtering by method
result, err = manager.handleIntrospection(json.RawMessage(`{"method":"echo"}`))
assert.NoError(t, err)
response, ok = result.(struct {
Logs []CallLog `json:"logs"`
Total int `json:"total"`
Filtered int `json:"filtered"`
})
assert.True(t, ok)
assert.Equal(t, 3, response.Total) // Total is still 3
assert.Equal(t, 3, response.Filtered) // All 3 match the method filter
// Test filtering by status
result, err = manager.handleIntrospection(json.RawMessage(`{"status":"error"}`))
assert.NoError(t, err)
response, ok = result.(struct {
Logs []CallLog `json:"logs"`
Total int `json:"total"`
Filtered int `json:"filtered"`
})
assert.True(t, ok)
assert.Equal(t, 3, response.Total) // Total is still 3
assert.Equal(t, 1, response.Filtered) // Only 1 error
assert.Len(t, response.Logs, 1)
assert.Equal(t, "error", response.Logs[0].Status)
}
// TestListMethods tests listing all registered methods
func TestListMethods(t *testing.T) {
schema := createTestSchema()
handlers := createTestHandlers()
manager, err := NewOpenRPCManager(schema, handlers, "test-secret")
if err != nil {
t.Fatalf("Failed to create OpenRPCManager: %v", err)
}
// List all methods
registeredMethods := manager.ListMethods()
// Check if all methods plus discovery and introspection methods are listed
expectedCount := len(schema.Methods) + 2 // +2 for rpc.discover and rpc.introspect
if len(registeredMethods) != expectedCount {
t.Errorf("Expected %d methods, got %d", expectedCount, len(registeredMethods))
}
// Check if all schema methods are in the list
for _, methodObj := range schema.Methods {
found := false
for _, registeredMethod := range registeredMethods {
if registeredMethod == methodObj.Name {
found = true
break
}
}
if !found {
t.Errorf("Method %s not found in list", methodObj.Name)
}
}
// Check if discovery method is in the list
found := false
for _, registeredMethod := range registeredMethods {
if registeredMethod == "rpc.discover" {
found = true
break
}
}
if !found {
t.Error("Discovery method 'rpc.discover' not found in list")
}
}
// TestSchemaValidation tests that the schema validation works correctly
func TestSchemaValidation(t *testing.T) {
secret := "test-secret"
schema := createTestSchema()
// Test with missing handler
incompleteHandlers := map[string]RPCHandler{
"echo": func(params json.RawMessage) (interface{}, error) {
return nil, nil
},
// Missing "add" handler
"secure.method": func(params json.RawMessage) (interface{}, error) {
return nil, nil
},
}
_, err := NewOpenRPCManager(schema, incompleteHandlers, secret)
if err == nil {
t.Error("Expected error when missing handler for schema method, but got nil")
}
// Test with extra handler not in schema
extraHandlers := createTestHandlers()
extraHandlers["not.in.schema"] = func(params json.RawMessage) (interface{}, error) {
return nil, nil
}
_, err = NewOpenRPCManager(schema, extraHandlers, secret)
if err == nil {
t.Error("Expected error when handler has no corresponding method in schema, but got nil")
}
}

View File

@ -1,117 +0,0 @@
package openrpcmanager
// OpenRPCSchema represents the OpenRPC specification document
// Based on OpenRPC Specification 1.2.6: https://spec.open-rpc.org/
type OpenRPCSchema struct {
OpenRPC string `json:"openrpc"` // Required: Version of the OpenRPC specification
Info InfoObject `json:"info"` // Required: Information about the API
Methods []MethodObject `json:"methods"` // Required: List of method objects
ExternalDocs *ExternalDocsObject `json:"externalDocs,omitempty"` // Optional: External documentation
Servers []ServerObject `json:"servers,omitempty"` // Optional: List of servers
Components *ComponentsObject `json:"components,omitempty"` // Optional: Reusable components
}
// InfoObject provides metadata about the API
type InfoObject struct {
Title string `json:"title"` // Required: Title of the API
Description string `json:"description,omitempty"` // Optional: Description of the API
Version string `json:"version"` // Required: Version of the API
TermsOfService string `json:"termsOfService,omitempty"` // Optional: Terms of service URL
Contact *ContactObject `json:"contact,omitempty"` // Optional: Contact information
License *LicenseObject `json:"license,omitempty"` // Optional: License information
}
// ContactObject provides contact information for the API
type ContactObject struct {
Name string `json:"name,omitempty"` // Optional: Name of the contact
URL string `json:"url,omitempty"` // Optional: URL of the contact
Email string `json:"email,omitempty"` // Optional: Email of the contact
}
// LicenseObject provides license information for the API
type LicenseObject struct {
Name string `json:"name"` // Required: Name of the license
URL string `json:"url,omitempty"` // Optional: URL of the license
}
// ExternalDocsObject provides a URL to external documentation
type ExternalDocsObject struct {
Description string `json:"description,omitempty"` // Optional: Description of the external docs
URL string `json:"url"` // Required: URL of the external docs
}
// ServerObject provides connection information to a server
type ServerObject struct {
Name string `json:"name,omitempty"` // Optional: Name of the server
Description string `json:"description,omitempty"` // Optional: Description of the server
URL string `json:"url"` // Required: URL of the server
Variables map[string]ServerVariable `json:"variables,omitempty"` // Optional: Server variables
}
// ServerVariable is a variable for server URL template substitution
type ServerVariable struct {
Default string `json:"default"` // Required: Default value of the variable
Description string `json:"description,omitempty"` // Optional: Description of the variable
Enum []string `json:"enum,omitempty"` // Optional: Enumeration of possible values
}
// MethodObject describes an RPC method
type MethodObject struct {
Name string `json:"name"` // Required: Name of the method
Description string `json:"description,omitempty"` // Optional: Description of the method
Summary string `json:"summary,omitempty"` // Optional: Summary of the method
Params []ContentDescriptorObject `json:"params"` // Required: List of parameters
Result *ContentDescriptorObject `json:"result"` // Required: Description of the result
Deprecated bool `json:"deprecated,omitempty"` // Optional: Whether the method is deprecated
Errors []ErrorObject `json:"errors,omitempty"` // Optional: List of possible errors
Tags []TagObject `json:"tags,omitempty"` // Optional: List of tags
ExternalDocs *ExternalDocsObject `json:"externalDocs,omitempty"` // Optional: External documentation
ParamStructure string `json:"paramStructure,omitempty"` // Optional: Structure of the parameters
}
// ContentDescriptorObject describes the content of a parameter or result
type ContentDescriptorObject struct {
Name string `json:"name"` // Required: Name of the parameter
Description string `json:"description,omitempty"` // Optional: Description of the parameter
Summary string `json:"summary,omitempty"` // Optional: Summary of the parameter
Required bool `json:"required,omitempty"` // Optional: Whether the parameter is required
Deprecated bool `json:"deprecated,omitempty"` // Optional: Whether the parameter is deprecated
Schema SchemaObject `json:"schema"` // Required: JSON Schema of the parameter
}
// SchemaObject is a JSON Schema definition
// This is a simplified version, in a real implementation you would use a full JSON Schema library
type SchemaObject map[string]interface{}
// ErrorObject describes an error that may be returned
type ErrorObject struct {
Code int `json:"code"` // Required: Error code
Message string `json:"message"` // Required: Error message
Data interface{} `json:"data,omitempty"` // Optional: Additional error data
}
// TagObject describes a tag for documentation purposes
type TagObject struct {
Name string `json:"name"` // Required: Name of the tag
Description string `json:"description,omitempty"` // Optional: Description of the tag
ExternalDocs *ExternalDocsObject `json:"externalDocs,omitempty"` // Optional: External documentation
}
// ComponentsObject holds reusable objects for different aspects of the OpenRPC spec
type ComponentsObject struct {
Schemas map[string]SchemaObject `json:"schemas,omitempty"` // Optional: Reusable schemas
ContentDescriptors map[string]ContentDescriptorObject `json:"contentDescriptors,omitempty"` // Optional: Reusable content descriptors
Examples map[string]interface{} `json:"examples,omitempty"` // Optional: Reusable examples
Links map[string]LinkObject `json:"links,omitempty"` // Optional: Reusable links
Errors map[string]ErrorObject `json:"errors,omitempty"` // Optional: Reusable errors
}
// LinkObject describes a link between operations
type LinkObject struct {
Name string `json:"name,omitempty"` // Optional: Name of the link
Description string `json:"description,omitempty"` // Optional: Description of the link
Summary string `json:"summary,omitempty"` // Optional: Summary of the link
Method string `json:"method"` // Required: Method name
Params map[string]interface{} `json:"params,omitempty"` // Optional: Parameters for the method
Server *ServerObject `json:"server,omitempty"` // Optional: Server for the method
}

View File

@ -1,241 +0,0 @@
package openrpcmanager
import (
"encoding/json"
"fmt"
"io"
"net"
"os"
"path/filepath"
"sync"
)
// RPCRequest represents an incoming RPC request
type RPCRequest struct {
Method string `json:"method"`
Params json.RawMessage `json:"params"`
ID interface{} `json:"id,omitempty"`
Secret string `json:"secret,omitempty"`
JSONRPC string `json:"jsonrpc"`
}
// RPCResponse represents an outgoing RPC response
type RPCResponse struct {
Result interface{} `json:"result,omitempty"`
Error *RPCError `json:"error,omitempty"`
ID interface{} `json:"id,omitempty"`
JSONRPC string `json:"jsonrpc"`
}
// RPCError represents an RPC error
type RPCError struct {
Code int `json:"code"`
Message string `json:"message"`
Data interface{} `json:"data,omitempty"`
}
// UnixServer represents a Unix socket server for the OpenRPC manager
type UnixServer struct {
manager *OpenRPCManager
socketPath string
listener net.Listener
connections map[net.Conn]bool
mutex sync.Mutex
wg sync.WaitGroup
done chan struct{}
}
// NewUnixServer creates a new Unix socket server for the OpenRPC manager
func NewUnixServer(manager *OpenRPCManager, socketPath string) (*UnixServer, error) {
// Create directory if it doesn't exist
dir := filepath.Dir(socketPath)
if err := os.MkdirAll(dir, 0755); err != nil {
return nil, fmt.Errorf("failed to create socket directory: %w", err)
}
// Remove socket if it already exists
if _, err := os.Stat(socketPath); err == nil {
if err := os.Remove(socketPath); err != nil {
return nil, fmt.Errorf("failed to remove existing socket: %w", err)
}
}
return &UnixServer{
manager: manager,
socketPath: socketPath,
connections: make(map[net.Conn]bool),
done: make(chan struct{}),
}, nil
}
// Start starts the Unix socket server
func (s *UnixServer) Start() error {
listener, err := net.Listen("unix", s.socketPath)
if err != nil {
return fmt.Errorf("failed to listen on unix socket: %w", err)
}
s.listener = listener
// Set socket permissions
if err := os.Chmod(s.socketPath, 0660); err != nil {
s.listener.Close()
return fmt.Errorf("failed to set socket permissions: %w", err)
}
s.wg.Add(1)
go s.acceptConnections()
return nil
}
// Stop stops the Unix socket server
func (s *UnixServer) Stop() error {
close(s.done)
// Close the listener
if s.listener != nil {
s.listener.Close()
}
// Close all connections
s.mutex.Lock()
for conn := range s.connections {
conn.Close()
}
s.mutex.Unlock()
// Wait for all goroutines to finish
s.wg.Wait()
// Remove the socket file
os.Remove(s.socketPath)
return nil
}
// acceptConnections accepts incoming connections
func (s *UnixServer) acceptConnections() {
defer s.wg.Done()
for {
select {
case <-s.done:
return
default:
conn, err := s.listener.Accept()
if err != nil {
select {
case <-s.done:
return
default:
fmt.Printf("Error accepting connection: %v\n", err)
continue
}
}
s.mutex.Lock()
s.connections[conn] = true
s.mutex.Unlock()
s.wg.Add(1)
go s.handleConnection(conn)
}
}
}
// handleConnection handles a client connection
func (s *UnixServer) handleConnection(conn net.Conn) {
defer func() {
s.mutex.Lock()
delete(s.connections, conn)
s.mutex.Unlock()
conn.Close()
s.wg.Done()
}()
buf := make([]byte, 4096)
for {
select {
case <-s.done:
return
default:
n, err := conn.Read(buf)
if err != nil {
if err != io.EOF {
fmt.Printf("Error reading from connection: %v\n", err)
}
return
}
if n > 0 {
go s.handleRequest(conn, buf[:n])
}
}
}
}
// handleRequest processes an RPC request
func (s *UnixServer) handleRequest(conn net.Conn, data []byte) {
var req RPCRequest
if err := json.Unmarshal(data, &req); err != nil {
s.sendErrorResponse(conn, nil, -32700, "Parse error", err)
return
}
// Validate JSON-RPC version
if req.JSONRPC != "2.0" {
s.sendErrorResponse(conn, req.ID, -32600, "Invalid Request", "Invalid JSON-RPC version")
return
}
var result interface{}
var err error
// Check if authentication is required
if req.Secret != "" {
result, err = s.manager.HandleRequestWithAuthentication(req.Method, req.Params, req.Secret)
} else {
result, err = s.manager.HandleRequest(req.Method, req.Params)
}
if err != nil {
s.sendErrorResponse(conn, req.ID, -32603, "Internal error", err.Error())
return
}
// Send success response
response := RPCResponse{
Result: result,
ID: req.ID,
JSONRPC: "2.0",
}
responseData, err := json.Marshal(response)
if err != nil {
s.sendErrorResponse(conn, req.ID, -32603, "Internal error", err.Error())
return
}
conn.Write(responseData)
}
// sendErrorResponse sends an error response
func (s *UnixServer) sendErrorResponse(conn net.Conn, id interface{}, code int, message string, data interface{}) {
response := RPCResponse{
Error: &RPCError{
Code: code,
Message: message,
Data: data,
},
ID: id,
JSONRPC: "2.0",
}
responseData, err := json.Marshal(response)
if err != nil {
fmt.Printf("Error marshaling error response: %v\n", err)
return
}
conn.Write(responseData)
}

View File

@ -1,362 +0,0 @@
package openrpcmanager
import (
"encoding/json"
"fmt"
"net"
"os"
"path/filepath"
"testing"
"time"
)
func TestUnixServer(t *testing.T) {
// Create a temporary socket path
tempDir, err := os.MkdirTemp("", "openrpc-test")
if err != nil {
t.Fatalf("Failed to create temp directory: %v", err)
}
defer os.RemoveAll(tempDir)
socketPath := filepath.Join(tempDir, "openrpc.sock")
// Create OpenRPC manager
schema := createTestSchema()
handlers := createTestHandlers()
manager, err := NewOpenRPCManager(schema, handlers, "test-secret")
if err != nil {
t.Fatalf("Failed to create OpenRPCManager: %v", err)
}
// Create and start Unix server
server, err := NewUnixServer(manager, socketPath)
if err != nil {
t.Fatalf("Failed to create UnixServer: %v", err)
}
if err := server.Start(); err != nil {
t.Fatalf("Failed to start UnixServer: %v", err)
}
defer server.Stop()
// Wait for server to start
time.Sleep(100 * time.Millisecond)
// Test connection
conn, err := net.Dial("unix", socketPath)
if err != nil {
t.Fatalf("Failed to connect to Unix socket: %v", err)
}
defer conn.Close()
// Test echo method
t.Run("Echo method", func(t *testing.T) {
request := RPCRequest{
Method: "echo",
Params: json.RawMessage(`{"message":"hello world"}`),
ID: 1,
JSONRPC: "2.0",
}
requestData, err := json.Marshal(request)
if err != nil {
t.Fatalf("Failed to marshal request: %v", err)
}
_, err = conn.Write(requestData)
if err != nil {
t.Fatalf("Failed to send request: %v", err)
}
// Read response
buf := make([]byte, 4096)
n, err := conn.Read(buf)
if err != nil {
t.Fatalf("Failed to read response: %v", err)
}
var response RPCResponse
if err := json.Unmarshal(buf[:n], &response); err != nil {
t.Fatalf("Failed to unmarshal response: %v", err)
}
// Check response
if response.Error != nil {
t.Fatalf("Received error response: %v", response.Error)
}
// Note: JSON unmarshaling may convert numbers to float64, so we need to check the value not exact type
if fmt.Sprintf("%v", response.ID) != fmt.Sprintf("%v", request.ID) {
t.Errorf("Response ID mismatch. Expected: %v, Got: %v", request.ID, response.ID)
}
// Check result
resultMap, ok := response.Result.(map[string]interface{})
if !ok {
t.Fatalf("Expected map result, got: %T", response.Result)
}
if resultMap["message"] != "hello world" {
t.Errorf("Expected 'hello world', got: %v", resultMap["message"])
}
})
// Test add method
t.Run("Add method", func(t *testing.T) {
request := RPCRequest{
Method: "add",
Params: json.RawMessage(`{"a":5,"b":7}`),
ID: 2,
JSONRPC: "2.0",
}
requestData, err := json.Marshal(request)
if err != nil {
t.Fatalf("Failed to marshal request: %v", err)
}
_, err = conn.Write(requestData)
if err != nil {
t.Fatalf("Failed to send request: %v", err)
}
// Read response
buf := make([]byte, 4096)
n, err := conn.Read(buf)
if err != nil {
t.Fatalf("Failed to read response: %v", err)
}
var response RPCResponse
if err := json.Unmarshal(buf[:n], &response); err != nil {
t.Fatalf("Failed to unmarshal response: %v", err)
}
// Check response
if response.Error != nil {
t.Fatalf("Received error response: %v", response.Error)
}
// Note: JSON unmarshaling may convert numbers to float64, so we need to check the value not exact type
if fmt.Sprintf("%v", response.ID) != fmt.Sprintf("%v", request.ID) {
t.Errorf("Response ID mismatch. Expected: %v, Got: %v", request.ID, response.ID)
}
// Check result
resultValue, ok := response.Result.(float64)
if !ok {
t.Fatalf("Expected float64 result, got: %T", response.Result)
}
if resultValue != float64(12) {
t.Errorf("Expected 12, got: %v", resultValue)
}
})
// Test authenticated method
t.Run("Authenticated method", func(t *testing.T) {
request := RPCRequest{
Method: "secure.method",
Params: json.RawMessage(`{}`),
ID: 3,
Secret: "test-secret",
JSONRPC: "2.0",
}
requestData, err := json.Marshal(request)
if err != nil {
t.Fatalf("Failed to marshal request: %v", err)
}
_, err = conn.Write(requestData)
if err != nil {
t.Fatalf("Failed to send request: %v", err)
}
// Read response
buf := make([]byte, 4096)
n, err := conn.Read(buf)
if err != nil {
t.Fatalf("Failed to read response: %v", err)
}
var response RPCResponse
if err := json.Unmarshal(buf[:n], &response); err != nil {
t.Fatalf("Failed to unmarshal response: %v", err)
}
// Check response
if response.Error != nil {
t.Fatalf("Received error response: %v", response.Error)
}
// Note: JSON unmarshaling may convert numbers to float64, so we need to check the value not exact type
if fmt.Sprintf("%v", response.ID) != fmt.Sprintf("%v", request.ID) {
t.Errorf("Response ID mismatch. Expected: %v, Got: %v", request.ID, response.ID)
}
// Check result
resultValue, ok := response.Result.(string)
if !ok {
t.Fatalf("Expected string result, got: %T", response.Result)
}
if resultValue != "secure data" {
t.Errorf("Expected 'secure data', got: %v", resultValue)
}
})
// Test authentication failure
t.Run("Authentication failure", func(t *testing.T) {
request := RPCRequest{
Method: "secure.method",
Params: json.RawMessage(`{}`),
ID: 4,
Secret: "wrong-secret",
JSONRPC: "2.0",
}
requestData, err := json.Marshal(request)
if err != nil {
t.Fatalf("Failed to marshal request: %v", err)
}
_, err = conn.Write(requestData)
if err != nil {
t.Fatalf("Failed to send request: %v", err)
}
// Read response
buf := make([]byte, 4096)
n, err := conn.Read(buf)
if err != nil {
t.Fatalf("Failed to read response: %v", err)
}
var response RPCResponse
if err := json.Unmarshal(buf[:n], &response); err != nil {
t.Fatalf("Failed to unmarshal response: %v", err)
}
// Check response
if response.Error == nil {
t.Fatal("Expected error response, but got nil")
}
// Note: JSON unmarshaling may convert numbers to float64, so we need to check the value not exact type
if fmt.Sprintf("%v", response.ID) != fmt.Sprintf("%v", request.ID) {
t.Errorf("Response ID mismatch. Expected: %v, Got: %v", request.ID, response.ID)
}
if response.Error.Code != -32603 {
t.Errorf("Expected error code -32603, got: %v", response.Error.Code)
}
})
// Test non-existent method
t.Run("Non-existent method", func(t *testing.T) {
request := RPCRequest{
Method: "nonexistent",
Params: json.RawMessage(`{}`),
ID: 5,
JSONRPC: "2.0",
}
requestData, err := json.Marshal(request)
if err != nil {
t.Fatalf("Failed to marshal request: %v", err)
}
_, err = conn.Write(requestData)
if err != nil {
t.Fatalf("Failed to send request: %v", err)
}
// Read response
buf := make([]byte, 4096)
n, err := conn.Read(buf)
if err != nil {
t.Fatalf("Failed to read response: %v", err)
}
var response RPCResponse
if err := json.Unmarshal(buf[:n], &response); err != nil {
t.Fatalf("Failed to unmarshal response: %v", err)
}
// Check response
if response.Error == nil {
t.Fatal("Expected error response, but got nil")
}
// Note: JSON unmarshaling may convert numbers to float64, so we need to check the value not exact type
if fmt.Sprintf("%v", response.ID) != fmt.Sprintf("%v", request.ID) {
t.Errorf("Response ID mismatch. Expected: %v, Got: %v", request.ID, response.ID)
}
if response.Error.Code != -32603 {
t.Errorf("Expected error code -32603, got: %v", response.Error.Code)
}
})
// Test discovery method
t.Run("Discovery method", func(t *testing.T) {
request := RPCRequest{
Method: "rpc.discover",
Params: json.RawMessage(`{}`),
ID: 6,
JSONRPC: "2.0",
}
requestData, err := json.Marshal(request)
if err != nil {
t.Fatalf("Failed to marshal request: %v", err)
}
_, err = conn.Write(requestData)
if err != nil {
t.Fatalf("Failed to send request: %v", err)
}
// Read response
buf := make([]byte, 4096)
n, err := conn.Read(buf)
if err != nil {
t.Fatalf("Failed to read response: %v", err)
}
var response RPCResponse
if err := json.Unmarshal(buf[:n], &response); err != nil {
t.Fatalf("Failed to unmarshal response: %v", err)
}
// Check response
if response.Error != nil {
t.Fatalf("Received error response: %v", response.Error)
}
// Note: JSON unmarshaling may convert numbers to float64, so we need to check the value not exact type
if fmt.Sprintf("%v", response.ID) != fmt.Sprintf("%v", request.ID) {
t.Errorf("Response ID mismatch. Expected: %v, Got: %v", request.ID, response.ID)
}
// Check that we got a valid schema
resultMap, ok := response.Result.(map[string]interface{})
if !ok {
t.Fatalf("Expected map result, got: %T", response.Result)
}
if resultMap["openrpc"] != "1.2.6" {
t.Errorf("Expected OpenRPC version 1.2.6, got: %v", resultMap["openrpc"])
}
methods, ok := resultMap["methods"].([]interface{})
if !ok {
t.Fatalf("Expected methods array, got: %T", resultMap["methods"])
}
if len(methods) < 3 {
t.Errorf("Expected at least 3 methods, got: %d", len(methods))
}
})
}

View File

@ -5,8 +5,8 @@ import (
"log"
"time"
"github.com/freeflowuniverse/heroagent/pkg/processmanager/interfaces"
"github.com/freeflowuniverse/heroagent/pkg/processmanager/interfaces/openrpc"
"git.ourworld.tf/herocode/heroagent/pkg/processmanager/interfaces"
"git.ourworld.tf/herocode/heroagent/pkg/processmanager/interfaces/openrpc"
)
// RunClientExample runs a complete example of using the process manager OpenRPC client

View File

@ -7,7 +7,7 @@ import (
"syscall"
"time"
"github.com/freeflowuniverse/heroagent/pkg/processmanager/interfaces/openrpc"
"git.ourworld.tf/herocode/heroagent/pkg/processmanager/interfaces/openrpc"
)
func main() {

View File

@ -6,8 +6,8 @@ import (
"sync"
"time"
"github.com/freeflowuniverse/heroagent/pkg/processmanager"
"github.com/freeflowuniverse/heroagent/pkg/processmanager/interfaces"
"git.ourworld.tf/herocode/heroagent/pkg/processmanager"
"git.ourworld.tf/herocode/heroagent/pkg/processmanager/interfaces"
)
// MockProcessManager implements the interfaces.ProcessManagerInterface for testing purposes

View File

@ -4,8 +4,8 @@ import (
"encoding/json"
"fmt"
"github.com/freeflowuniverse/heroagent/pkg/openrpcmanager/client"
"github.com/freeflowuniverse/heroagent/pkg/processmanager/interfaces"
"git.ourworld.tf/herocode/heroagent/pkg/openrpcmanager/client"
"git.ourworld.tf/herocode/heroagent/pkg/processmanager/interfaces"
)
// Client provides a client for interacting with process manager operations via RPC

View File

@ -4,9 +4,9 @@ import (
"encoding/json"
"fmt"
"github.com/freeflowuniverse/heroagent/pkg/openrpcmanager"
"github.com/freeflowuniverse/heroagent/pkg/processmanager"
"github.com/freeflowuniverse/heroagent/pkg/processmanager/interfaces"
"git.ourworld.tf/herocode/heroagent/pkg/openrpcmanager"
"git.ourworld.tf/herocode/heroagent/pkg/processmanager"
"git.ourworld.tf/herocode/heroagent/pkg/processmanager/interfaces"
)
// Handler implements the OpenRPC handlers for process manager operations

View File

@ -6,8 +6,8 @@ import (
"testing"
"time"
"github.com/freeflowuniverse/heroagent/pkg/processmanager"
"github.com/freeflowuniverse/heroagent/pkg/processmanager/interfaces"
"git.ourworld.tf/herocode/heroagent/pkg/processmanager"
"git.ourworld.tf/herocode/heroagent/pkg/processmanager/interfaces"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

View File

@ -7,7 +7,7 @@ import (
"path/filepath"
"runtime"
"github.com/freeflowuniverse/heroagent/pkg/openrpcmanager"
"git.ourworld.tf/herocode/heroagent/pkg/openrpcmanager"
)
// LoadSchema loads the OpenRPC schema from the embedded JSON file

View File

@ -6,8 +6,8 @@ import (
"os"
"path/filepath"
"github.com/freeflowuniverse/heroagent/pkg/openrpcmanager"
"github.com/freeflowuniverse/heroagent/pkg/processmanager/interfaces"
"git.ourworld.tf/herocode/heroagent/pkg/openrpcmanager"
"git.ourworld.tf/herocode/heroagent/pkg/processmanager/interfaces"
)
// Server represents the Process Manager OpenRPC server

View File

@ -3,7 +3,7 @@ package interfaces
import (
"time"
"github.com/freeflowuniverse/heroagent/pkg/processmanager"
"git.ourworld.tf/herocode/heroagent/pkg/processmanager"
)
// ProcessManagerInterface defines the interface for process management operations

View File

@ -14,7 +14,7 @@ import (
"time"
"unicode"
"github.com/freeflowuniverse/heroagent/pkg/logger"
"git.ourworld.tf/herocode/heroagent/pkg/logger"
"github.com/shirou/gopsutil/v3/process"
)

View File

@ -24,7 +24,7 @@ The server implements the following Redis commands:
### Basic Usage
```go
import "github.com/freeflowuniverse/heroagent/pkg/redisserver"
import "git.ourworld.tf/herocode/heroagent/pkg/redisserver"
// Create a new server with default configuration
server := redisserver.NewServer(redisserver.ServerConfig{

View File

@ -10,7 +10,7 @@ import (
"sync"
"time"
"github.com/freeflowuniverse/heroagent/pkg/servers/redisserver"
"git.ourworld.tf/herocode/heroagent/pkg/servers/redisserver"
"github.com/redis/go-redis/v9"
)

View File

@ -10,7 +10,7 @@ import (
"sync"
"time"
"github.com/freeflowuniverse/heroagent/pkg/servers/redisserver"
"git.ourworld.tf/herocode/heroagent/pkg/servers/redisserver"
"github.com/redis/go-redis/v9"
)

View File

@ -5,7 +5,7 @@ import (
"fmt"
"os"
"github.com/freeflowuniverse/heroagent/pkg/system/builders/hetznerinstall"
"git.ourworld.tf/herocode/heroagent/pkg/system/builders/hetznerinstall"
)
func main() {

View File

@ -6,10 +6,10 @@ import (
"os/exec"
"path/filepath"
"github.com/freeflowuniverse/heroagent/pkg/system/builders/postgresql/dependencies"
"github.com/freeflowuniverse/heroagent/pkg/system/builders/postgresql/gosp"
"github.com/freeflowuniverse/heroagent/pkg/system/builders/postgresql/postgres"
"github.com/freeflowuniverse/heroagent/pkg/system/builders/postgresql/verification"
"git.ourworld.tf/herocode/heroagent/pkg/system/builders/postgresql/dependencies"
"git.ourworld.tf/herocode/heroagent/pkg/system/builders/postgresql/gosp"
"git.ourworld.tf/herocode/heroagent/pkg/system/builders/postgresql/postgres"
"git.ourworld.tf/herocode/heroagent/pkg/system/builders/postgresql/verification"
)
// Constants for PostgreSQL installation

View File

@ -4,7 +4,7 @@ import (
"fmt"
"os"
"github.com/freeflowuniverse/heroagent/pkg/system/builders/postgresql"
"git.ourworld.tf/herocode/heroagent/pkg/system/builders/postgresql"
)
func main() {

View File

@ -6,7 +6,7 @@ import (
"os/exec"
"path/filepath"
"github.com/freeflowuniverse/heroagent/pkg/system/builders/postgresql/postgres"
"git.ourworld.tf/herocode/heroagent/pkg/system/builders/postgresql/postgres"
)
// Constants for Go stored procedure
@ -49,7 +49,7 @@ func (b *GoSPBuilder) run(cmd string, args ...string) error {
c.Env = append(os.Environ(),
"GOROOT=/usr/local/go",
"GOPATH=/root/go",
"PATH=/usr/local/go/bin:" + os.Getenv("PATH"))
"PATH=/usr/local/go/bin:"+os.Getenv("PATH"))
c.Stdout = os.Stdout
c.Stderr = os.Stderr
return c.Run()

View File

@ -8,7 +8,7 @@ import (
"runtime"
"strings"
"github.com/mholt/archiver/v3"
"github.com/mholt/archiver/v4"
)
const (

View File

@ -8,7 +8,7 @@ import (
"syscall"
"time"
"github.com/freeflowuniverse/heroagent/pkg/system/stats"
"git.ourworld.tf/herocode/heroagent/pkg/system/stats"
)
func main() {
@ -18,11 +18,11 @@ func main() {
// Create a new stats manager with Redis connection
// Create a custom configuration
config := &stats.Config{
RedisAddr: "localhost:6379",
RedisPassword: "",
RedisDB: 0,
Debug: false,
QueueSize: 100,
RedisAddr: "localhost:6379",
RedisPassword: "",
RedisDB: 0,
Debug: false,
QueueSize: 100,
DefaultTimeout: 5 * time.Second,
ExpirationTimes: map[string]time.Duration{
"system": 60 * time.Second, // System info expires after 60 seconds

View File

@ -11,27 +11,27 @@ import (
"syscall"
"time"
"github.com/freeflowuniverse/heroagent/pkg/system/stats"
"git.ourworld.tf/herocode/heroagent/pkg/system/stats"
"github.com/shirou/gopsutil/v3/cpu"
"github.com/shirou/gopsutil/v3/process"
)
// TestResult stores the results of a single test run
type TestResult struct {
StartTime time.Time
EndTime time.Time
SystemInfoTime time.Duration
DiskStatsTime time.Duration
ProcessTime time.Duration
NetworkTime time.Duration
HardwareTime time.Duration
TotalTime time.Duration
UserCPU float64
SystemCPU float64
TotalCPU float64
OverallCPU float64
MemoryUsageMB float32
NumGoroutines int
StartTime time.Time
EndTime time.Time
SystemInfoTime time.Duration
DiskStatsTime time.Duration
ProcessTime time.Duration
NetworkTime time.Duration
HardwareTime time.Duration
TotalTime time.Duration
UserCPU float64
SystemCPU float64
TotalCPU float64
OverallCPU float64
MemoryUsageMB float32
NumGoroutines int
}
func main() {
@ -66,11 +66,11 @@ func main() {
// Create a new stats manager with Redis connection
config := &stats.Config{
RedisAddr: "localhost:6379",
RedisPassword: "",
RedisDB: 0,
Debug: false,
QueueSize: 100,
RedisAddr: "localhost:6379",
RedisPassword: "",
RedisDB: 0,
Debug: false,
QueueSize: 100,
DefaultTimeout: 5 * time.Second,
ExpirationTimes: map[string]time.Duration{
"system": 60 * time.Second, // System info expires after 60 seconds

View File

@ -6,7 +6,7 @@ import (
"os"
"time"
"github.com/freeflowuniverse/heroagent/pkg/system/stats"
"git.ourworld.tf/herocode/heroagent/pkg/system/stats"
"github.com/redis/go-redis/v9"
)

View File

@ -6,7 +6,7 @@ import (
"os"
"time"
"github.com/freeflowuniverse/heroagent/pkg/system/stats"
"git.ourworld.tf/herocode/heroagent/pkg/system/stats"
)
func main() {
@ -15,18 +15,18 @@ func main() {
// Create a new stats manager with Redis connection
config := &stats.Config{
RedisAddr: "localhost:6379",
RedisPassword: "",
RedisDB: 0,
Debug: false,
QueueSize: 100,
RedisAddr: "localhost:6379",
RedisPassword: "",
RedisDB: 0,
Debug: false,
QueueSize: 100,
DefaultTimeout: 5 * time.Second,
ExpirationTimes: map[string]time.Duration{
"system": 30 * time.Second, // System info expires after 30 seconds
"disk": 60 * time.Second, // Disk info expires after 1 minute
"process": 15 * time.Second, // Process info expires after 15 seconds
"network": 20 * time.Second, // Network info expires after 20 seconds
"hardware": 60 * time.Second, // Hardware stats expire after 1 minute
"system": 30 * time.Second, // System info expires after 30 seconds
"disk": 60 * time.Second, // Disk info expires after 1 minute
"process": 15 * time.Second, // Process info expires after 15 seconds
"network": 20 * time.Second, // Network info expires after 20 seconds
"hardware": 60 * time.Second, // Hardware stats expire after 1 minute
},
}