Farhan Beg commited on
Commit
be5c4d4
·
1 Parent(s): bc1794a

fix(docker): restore proper Dockerfile and add venv chown for hermes user

Browse files
Files changed (1) hide show
  1. Dockerfile +193 -1
Dockerfile CHANGED
@@ -1 +1,193 @@
1
- IyBIdWdnaW5nTWVzICsgSGVybWVzIFdlYlVJIOKAlCBtZXJnZWQgZGVwbG95bWVudCBmb3IgSHVnZ2luZyBGYWNlIFNwYWNlcwojIEJhc2U6IE5vdXNSZXNlYXJjaCBIZXJtZXMgQWdlbnQgKHNoaXBzIEhlcm1lcyBDTEksIGdhdGV3YXksIGRhc2hib2FyZCwgUHl0aG9uIHZlbnYpCgpBUkcgSEVSTUVTX0FHRU5UX1ZFUlNJT049bGF0ZXN0CkZST00gbm91c3Jlc2VhcmNoL2hlcm1lcy1hZ2VudDoke0hFUk1FU19BR0VOVF9WRVJTSU9OfQoKUkcgV0VCVUlfUkVGPW1hc3RlcgoKVVNFUiByb290CgojIFN5c3RlbSBkZXBzIChtaXJyb3JzIEh1Z2dpbmdNZXMpICsgZ2l0L25vZGVqcyBmb3IgV2ViVUkgY2hlY2tvdXQgKyByb3V0ZXIKUlVOIGFwdC1nZXQgdXBkYXRlICYmIGFwdC1nZXQgaW5zdGFsbCAteSAtLW5vLWluc3RhbGwtcmVjb21tZW5kcwogICAgY2EtY2VydGlmaWNhdGVzIFwKICAgIGN1cmwgXAogICAganEgXAogICAgZ2l0IFwKICAgIHB5dGhvbjMgXAogICAgbm9kZWpzIFwKICAgIG5wbSBcCiAgICBjaHJvbWl1bSBcCiAgICBsaWJudHMzIFwKICAgIGxpYmF0azEuMC0wIFwKICAgIGxpYmF0ay1icmlkZ2UyLjAtMCBcCiAgICBsaWJkcm0yIFwKICAgIGxpYmdibTEgXAogICAgbGlieGNvbXBvc2l0ZTEgXAogICAgbGlieGRhbWFnZTEgXAogICAgbGlieHJhbmRyMiBcCiAgICBsaWJ4a2Jjb21tb24wIFwKICAgIGxpYngxMS02IFwKICAgIGxpYng2IFwKICAgIGxpYnhmaXhlczMgXAogICAgbGliYXNvdW5kMiBcCiAgICBmb250cy1kZWphdnUtY29yZSBcCiAgICBmb250cy1saWJlcmF0aW9uIFwKICAgIGZvbnRzLW5vdG8tY29sb3ItZW1vamkgXAogICAgJiYgcm0gLXJmIC92YXIvbGliL2FwdC9saXN0cy8qIFwKICAgICYmIHV2IHBpcCBpbnN0YWxsIC0tcHl0aG9uIC9vcHQvaGVybWVzLy52ZW52L2Jpbi9weXRob24gLS1uby1jYWNoZS1kaXIgXAogICAgICAgIGh1Z2dpbmdmYWNlX2h1YiBoZl90cmFuc2ZlciBweXlhbWwKCiMgQ2xvbmUgbmVzcXVlbmEvaGVybWVzLXdlYnVpIChpbnN0YWxsIGRlcHMgaW50byB0aGUgYWdlbnQgdmVudiBzbyBpbXBvcnRzIHJlc29sdmUpClJVTiBnaXQgY2xvbmUgLS1kZXB0aCAxIC0tYnJhbmNoICR7V0VCVUlfUkVGfQogICAgICAgIGh0dHBzOi8vZ2l0aHViLmNvbS9uZXNxdWVuYS9oZXJtZXMtd2VidWkuZ2l0IC9vcHQvaGVybWVzLXdlYnVpIFwKICYmICggWyAtZiAvb3B0L2hlcm1lcy13ZWJ1aS9yZXF1aXJlbWVudHMudHh0IF0KICAgICAgJiYgL29wdC9oZXJtZXMvLnZlbnYvYmluL3BpcCBpbnN0YWxsIC0tbm8tY2FjaGUtZGlyIC1yIC9vcHQvaGVybWVzLXdlYnVpL3JlcXVpcmVtZW50cy50eHQgXAogICAgICB8fCB0cnVlICkgXAogICYmIGNob3duIC1SIGhlcm1lczpoZXJtZXMgL29wdC9oZXJtZXMtd2VidWkKCiMgSHVnZ2luZ01lcy1zdHlsZSBpbnRlZ3JhdGlvbiBzY3JpcHRzICh2ZW5kb3JlZCBmcm9tIHNvbXJhdHByby9IdWdnaW5nTWVzKQpDT1BZIC0tY2hvd249aGVybWVzOmhlcm1lcyBzdGFydC5zaCAgICAgICAgICAgICAgICAgICAgICAgICAgIC9vcHQvaHVnZ2luZ21lcy9zdGFydC5zaApDT1BZIC0tY2hvd249aGVybWVzOmhlcm1lcyBoZWFsdGgtc2VydmVyLmpzICAgICAgICAgICAgICAgICAgICAvb3B0L2h1Z2dpbmdtZXMvaGVhbHRoLXNlcnZlci5qcwpDT1BZIC0tY2hvd249aGVybWVzOmhlcm1lcyBoZXJtZXMtc3luYy5weSAgICAgICAgICAgICAgICAgICAgIC9vcHQvaHVnZ2luZ21lcy9oZXJtZXMtc3luYy5weQpDT1BZIC0tY2hvd249aGVybWVzOmhlcm1lcyBjbG91ZGZsYXJlLXByb3h5LXNldHVwLnB5ICAgICAgL29wdC9odWdnaW5nbWVzL2Nsb3VkZmxhcmUtcHJveHktc2V0dXAucHkKQ09QWSAtLWNob3duPWhlcm1lczpoZXJtZXMgY2xvdWRmbGFyZS1rZWVwYWxpdmUtc2V0dXAucHkgIC9vcHQvaHVnZ2luZ21lcy9jbG91ZGZsYXJlLWtlZXBhbGl2ZS1zZXR1cC5weQoKUlVOIGNobW9kICt4IFwKICAgIC9vcHQvaHVnZ2luZ21lcy9zdGFydC5zaCBcCiAgICAvb3B0L2h1Z2dpbmdtZXMvaGVybWVzLXN5bmMucHkgXAogICAgL29wdC9odWdnaW5nbWVzL2Nsb3VkZmxhcmUtcHJveHktc2V0dXAucHkgXAogICAgL29wdC9odWdnaW5nbWVzL2Nsb3VkZmxhcmUta2VlcGFsaXZlLXNldHVwLnB5CgojIElkZW1wb3RlbnQga2FuYmFuIG1pZ3JhdGlvbiBwYXRjaCAoc2FtZSB3b3JrYXJvdW5kIEh1Z2dpbmdNZXMgc2hpcHMpClJVTiBweXRob24zIC0gPDwnUFknCmZyb20gcGF0aGxpYiBpbXBvcnQgUGF0aAppbXBvcnQgc3lzCnAgPSBQYXRoKCIvb3B0L2hlcm1lcy9oZXJtZXNfY2xpL2thbmJhbl9kYi5weSIpCmlmIG5vdCBwLmV4aXN0cygpOgogICAgc3lzLmV4aXQoMCkKc3JjID0gcC5yZWFkX3RleHQoZW5jb2Rpbmc9InV0Zi04IikKc2VudGluZWwgPSAiIyBodWdnaW5nbWVzLXdlYnVpOiBpZGVtcG90ZW50LWFsdGVyIgppZiBzZW50aW5lbCBpbiBzcmM6CiAgICBzeXMuZXhpdCgwKQpvbGQgPSAoCiAgICAnICAgIGNvbm4uZXhlY3V0ZShcbicKICAgICcgICAgICAgICJBTFRFUiBUQUJMRSB0YXNrcyBBREQgQ09MVU1OIGNvbnNlY3V0aXZlX2ZhaWx1cmVzICInCiAgICAnICAgICAgICAiSU5URUdFUiBOT1QgTlVMTCBERUZBVUxUIDAiJwogICAgJyAgICApJwopCm5ldyA9ICgKICAgIGYnICAgIHRyeTogIHtzZW50aW5lbH1cbicKICAgICcgICAgICAgIGNvbm4uZXhlY3V0ZShcbicKICAgICcgICAgICAgICAgICAiQUxURVIgVEFCTEUgdGFza3MgQUREIENPTFVNTiBjb25zZWN1dGl2ZV9mYWlsdXJlcyAiJwogICAgJyAgICAgICAgICAgICJJTlRFR0VSIE5PVCBOVUxMIERFRkFVTFQgMCInCiAgICAnICAgICAgICApXG4nCiAgICAnICAgIGV4Y2VwdCBFeGNlcHRpb246XG4nCiAgICAnICAgICAgICBwYXNzJwppZiBvbGQgaW4gc3JjOgogICAgcC53cml0ZV90ZXh0KHNyYy5yZXBsYWNlKG9sZCwgbmV3KSwgZW5jb2Rpbmc9InV0Zi04IikKICAgIHByaW50KCJrYW5iYW4gcGF0Y2g6IGFwcGxpZWQiKwpQWQoKIyBRdWlldCBoZXJtZXMtd2VidWkncyBwZXItcmVxdWVzdCBhY2Nlc3MgbG9nIG5vaXNlLgojIEJ5IGRlZmF1bHQgaXQgcHJpbnRzIGBbd2VidWldIHsidHMiOi4uLiJtZXRob2QiOi4uLn1gIGZvciBFVkVSWSByZXF1ZXN0LAojIHdoaWNoIGRyb3ducyB0aGUgSEYgTG9ncyB0YWIgb25jZSBhbnkgYnJvd3NlciB0YWIgaXMgb3BlbiBwb2xsaW5nCiMgL2FwaS9kYXNoYm9hcmQvc3RhdHVzLCAvYXBpL2hlYWx0aC9hZ2VudCwgL2FwaS9zZXNzaW9ucywgL3N3LmpzLCBldGMuCiMgUGF0Y2ggbG9nX3JlcXVlc3QoKSB0byBkcm9wIDJ4eCByZXNwb25zZXMgZm9yIGhpZ2gtZnJlcXVlbmN5IHBvbGwgcGF0aHMuCiMgRXJyb3JzIGFuZCBjaGF0L3N0cmVhbWluZyBwYXRocyBzdGlsbCBsb2cgbm9ybWFsbHkuClJVTiBweXRob24zIC0gPDwnUFknCmZyb20gcGF0aGxpYiBpbXBvcnQgUGF0aAppbXBvcnQgcmUKaW1wb3J0IHN5cwoKcCA9IFBhdGgoIi9vcHQvaGVybWVzLXdlYnVpL3NlcnZlci5weSIpCmlmIG5vdCBwLmV4aXN0cygpOgogICAgc3lzLmV4aXQoMCkKc3JjID0gcC5yZWFkX3RleHQoZW5jb2Rpbmc9InV0Zi04IikKc2VudGluZWwgPSAiIyBodWdnaW5nbWVzLXdlYnVpOiBxdWlldC1wb2xsLXBhdGhzIgppZiBzZW50aW5lbCBpbiBzcmM6CiAgICBzeXMuZXhpdCgwKQoKb2xkID0gKAogICAgIiAgICBkZWYgbG9nX3JlcXVlc3Qoc2VsZiwgY29kZTogc3RyPSctJywgc2l6ZTogc3RyPSctJykgLT4gTm9uZzpcbiIKICAgICIgICAgICAgIFwiXCJcIlN0cnVjdHVyZWQgSlNPTiBsb2dzIGZvciBlYWNoIHJlcXVlc3QuXCJcIlwiXG4iCiAgICAiICAgICAgICBpbXBvcnQganNvbiBhcyBfanNvblxuIgogICAgIiAgICAgICAgZHVyYXRpb25fbXMgPSByb3VuZCgodGltZS50aW1lKCkgLSBnZXRhdHRyKHNlbGYsICdfcmVxX3QwJywgdGltZS50aW1lKCkpKSAqIDEwMDAsIDEpXG4iCiAgICAiICAgICAgICByZWNvcmQgPSBfanNvbi5kdW1wcyh7XG4iCiAgICAiICAgICAgICAgICAgJ3RzJzogdGltZS5zdHJmdGltZSgnJVktJW0tJWRUJUglbTolJVN6JywgdGltZS5nbXRpbWUoKSksXG4iCiAgICAiICAgICAgICAgICAgJ21ldGhvZCc6IHNlbGYuY29tbWFuZCBvciAnLScsXG4iCiAgICAiICAgICAgICAgICAgJ3BhdGgnOiBzZWxmLnBhdGggb3IgJy0nLFxuIgogICAgIiAgICAgICAgICAgICdzdGF0dXMnOiBpbnQoY29kZSkgaWYgc3RyKGNvZGUpLmlzZGlnaXQoKSBlbHNlIGNvZGUsXG4iCiAgICAiICAgICAgICAgICAgJ21zJzogZHVyYXRpb25fbXMsXG4iCiAgICAiICAgICAgICB9KVxuIgogICAgIiAgICAgICAgcHJpbnQoZidbd2VidWldIHtyZWNvcmR9JywgZmx1c2g9VHJ1ZSkiCQoKbmV3ID0gKAogICAgIiAgICBfUVVJRVRfUE9MTF9QQVRIUyA9ICggICIgKyBzZW50aW5lbCArICJcbiIKICAgICIgICAgICAgICcvYXBpL2hlYWx0aC9hZ2VudCcsICcvYXBpL2Rhc2hib2FyZC9zdGF0dXMnLFxuIgogICAgIiAgICAgICAgJy9hcGkvZGFzaGJvYXJkL2NvbmZpZycsICcvYXBpL3Nlc3Npb25zJywgJy9hcGkvcHJvZmlsZXMnLFxuIgogICAgIiAgICAgICAgJy9hcGkvcHJvZmlsZS9hY3RpdmUnLCAnL2FwaS9vbmJvYXJkaW5nL3N0YXR1cycsXG4iCiAgICAiICAgICAgICAnL2FwaS9pbnNpZ2h0cycsICcvYXBpL3N5c3RlbS9oZWFsdGgnLFxuIgogICAgIiAgICAgICAgJy9hcGkvc2V0dGluZ3MnLCAnL2FwaS9wcm9qZWN0cycsICcvYXBpL3JlYXNvbmluZycsXG4iCiAgICAiICAgICAgICAnL2FwaS9tb2RlbHMnLCAnL2FwaS9jaGF0L3N0cmVhbS9zdGF0dXMnLFxuIgogICAgIiAgICAgICAgJy9hcGkvZ2l0LWluZm8nLCAnL3N3LmpzJywgJy9oZWFsdGgnLFxuIgogICAgIiAgICApXG4iCiAgICAiICAgIF9RVUlFVF9QUkVGSVhFUyA9ICgnL3N0YXRpYy8nLCAnL3Nlc3Npb24vc3RhdGljLycsICcvYXNzZXRzLycpXG4iCiAgICAiXG4iCiAgICAiICAgIGRlZiBsb2dfcmVxdWVzdChzZWxmLCBjb2RlOiBzdHI9Jy0nLCBzaXplOiBzdHI9Jy0nKSAtPiBOb25lOlxuIgogICAgIiAgICAgICAgXCJcIlwiU3RydWN0dXJlZCBKU09OIGxvZ3MgZm9yIGVhY2ggcmVxdWVzdCwgc2tpcHBpbmcgbm9pc3kgcG9sbHMuXCJcIlwiXG4iCiAgICAiICAgICAgICAjIEFsd2F5cyBsb2cgbm9uLTJ4eCBzbyA0MDEvNDA0LzV4eCByZW1haW4gdmlzaWJsZS5cbiIKICAgICIgICAgICAgIHRyeTpcbiIKICAgICIgICAgICAgICAgICBzdGF0dXNfaW50ID0gaW50KGNvZGUpIGlmIHN0cihjb2RlKS5pc2RpZ2l0KCkgZWxzZSAwXG4iCiAgICAiICAgICAgICBleGNlcHQgRXhjZXB0aW9uOlxuIgogICAgIiAgICAgICAgICAgIHN0YXR1c19pbnQgPSAwXG4iCiAgICAiICAgICAgICBwYXRoID0gKHNlbGYucGF0aCBvciAnJykuc3BsaXQoJz8nLCAxKVswXVxuIgogICAgIiAgICAgICAgaWYgMjAwIDw9IHN0YXR1c19pbnQgPCA0MDA6XG4iCiAgICAiICAgICAgICAgICAgaWYgcGF0aCBpbiBzZWxmLl9RVUlFVF9QT0xMX1BBVEhTOlxuIgogICAgIiAgICAgICAgICAgICAgICByZXR1cm5cbiIKICAgICIgICAgICAgICAgICBmb3IgcHJlZiBpbiBzZWxmLl9RVUlFVF9QUkVGSVhFUzpcbiIKICAgICIgICAgICAgICAgICAgICAgaWYgcGF0aC5zdGFydHN3aXRoKHByZWYpOlxuIgogICAgIiAgICAgICAgICAgICAgICAgICAgcmV0dXJuXG4iCiAgICAiICAgICAgICBpbXBvcnQganNvbiBhcyBfanNvblxuIgogICAgIiAgICAgICAgZHVyYXRpb25fbXMgPSByb3VuZCgodGltZS50aW1lKCkgLSBnZXRhdHRyKHNlbGYsICdfcmVxX3QwJywgdGltZS50aW1lKCkpKSAqIDEwMDAsIDEpXG4iCiAgICAiICAgICAgICByZWNvcmQgPSBfanNvbi5kdW1wcyh7XG4iCiAgICAiICAgICAgICAgICAgJ3RzJzogdGltZS5zdHJmdGltZSgnJVktJW0tJWRUJUglbTolJVN6JywgdGltZS5nbXRpbWUoKSksXG4iCiAgICAiICAgICAgICAgICAgJ21ldGhvZCc6IHNlbGYuY29tbWFuZCBvciAnLScsXG4iCiAgICAiICAgICAgICAgICAgJ3BhdGgnOiBzZWxmLnBhdGggb3IgJy0nLFxuIgogICAgIiAgICAgICAgICAgICdzdGF0dXMnOiBpbnQoY29kZSkgaWYgc3RyKGNvZGUpLmlzZGlnaXQoKSBlbHNlIGNvZGUsXG4iCiAgICAiICAgICAgICAgICAgJ21zJzogZHVyYXRpb25fbXMsXG4iCiAgICAiICAgICAgICB9KVxuIgogICAgIiAgICAgICAgcHJpbnQoZidbd2VidWldIHtyZWNvcmR9JywgZmx1c2g9VHJ1ZSkiCQoKaWYgb2xkIGluIHNyYzoKICAgIHAud3JpdGVfdGV4dChzcmMucmVwbGFjZShvbGQsIG5ldyksIGVuY29kaW5nPSJ1dGYtOCIpCiAgICBwcmludCgid2VidWkgbG9nLXF1aWV0IHBhdGNoOiBhcHBsaWVkIikKZWxzZToKICAgIHByaW50KCJ3ZWJ1aSBsb2ctcXVpZXQgcGF0Y2g6IHBhdHRlcm4gbm90IGZvdW5kLCBza2lwcGluZyIpClBZCgojIEZpeCBwZXJtaXNzaW9ucyBzbyBoZXJtZXMgdXNlciBjYW4gc2VsZi11cGRhdGUgcGFja2FnZXMKUlVOIGNob3duIC1SIGhlcm1lczpoZXJtZXMgL29wdC9oZXJtZXMvLnZlbnYKCiMgS2VlcCBoZXJtZXMgQ0xJIG9uIFBBVEggZm9yIGFsbCBzaGVsbCB0eXBlcyAobG9naW4vaW50ZXJhY3RpdmUvbm9uLWludGVyYWN0aXZlKQpSVU4gZWNobyAnZXhwb3J0IFBBVEg9Ii9vcHQvaGVybWVzLy52ZW52L2Jpbjovb3B0L2RhdGEvLmxvY2FsL2JpbjokUEFUSCInIFwKICAgID4gL2V0Yy9wcm9maWxlLmQvaGVybWVzLXZlbnYuc2gKCiMgQ3JlYXRlIGRpcmVjdG9yeSBmb3Igc2tpbiBzeW5jaW5nIApSVU4gbWtkaXIgLXAgJHtIRVJNRVNfSE9NRX0vc2tpbnMKClJVTiBjaG93biAtUiBoZXJtZXM6aGVybWVzICR7SEVSTUVTX0hPTUV9L3NraW5zCgpFTlYgSEVSTUVTX0hPTUU9L29wdC9kYXRhIFwKICAgIEhVR0dJTkdNRVNfQVBQX0RJUj0vb3B0L2h1Z2dpbmdtZXMgXAogICAgSEVSTUVTX1dFQlVJX1JFUE89L29wdC9oZXJtZXMtd2VidWkgXAogICAgSEVSTUVTX0FHRU5UX1ZFUlNJT049JHtIRVJNRVNfQUdFTlRfVkVSU0lPTn0gXAogICAgUFlUSE9OVU5CVUZGRVJFVD0xIFwKICAgIEhGX0hVQl9FTkFCTEVfSEZfVFJBTlNGRVI9MSBcCiAgICBQTEFZV1JJR0hUX0NIUk9NSVVNX0VYRUNVVEFCTEVfUEFUSD0vdXNyL2Jpbi9jaHJvbWl1bQpFWFBPU0UgNzg2MQpIRUFMVEhDSEVDSyAtLWludGVydmFsPTM0cyAtLXRpbWVvdXQ9NXMgLS1zdGFydC1wZXJpb2Q9MTI2cyBcClJVTiBjdXJsIC1mc1MgaHR0cDovL2xvY2FsaG9zdDo3ODYxL2hlYWx0aCB8fCBleGl0IDEKCiMgQ3JlYXRlIGRpcmVjdG9yeSBmb3Igc2tpbiBzeW5jaW5nIFUKUlVOIG1rZGlyIC1wICR7SEVSTUVTX0hPTUV9L3NraW5zIApSVU4gY2hvd24gLVIgaGVybWVzOmhlcm1lcyAke0hFUk1FU19IT01FfS9za2lucyA=
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # HuggingMes + Hermes WebUI — merged deployment for Hugging Face Spaces
2
+ # Base: NousResearch Hermes Agent (ships Hermes CLI, gateway, dashboard, Python venv)
3
+
4
+ ARG HERMES_AGENT_VERSION=latest
5
+ FROM nousresearch/hermes-agent:${HERMES_AGENT_VERSION}
6
+
7
+ ARG WEBUI_REF=master
8
+
9
+ USER root
10
+
11
+ # System deps (mirrors HuggingMes) + git/nodejs for WebUI checkout + router
12
+ RUN apt-get update && apt-get install -y --no-install-recommends \
13
+ ca-certificates \
14
+ curl \
15
+ jq \
16
+ git \
17
+ python3 \
18
+ nodejs \
19
+ npm \
20
+ chromium \
21
+ libnss3 \
22
+ libatk1.0-0 \
23
+ libatk-bridge2.0-0 \
24
+ libdrm2 \
25
+ libgbm1 \
26
+ libxcomposite1 \
27
+ libxdamage1 \
28
+ libxrandr2 \
29
+ libxkbcommon0 \
30
+ libx11-6 \
31
+ libxext6 \
32
+ libxfixes3 \
33
+ libasound2 \
34
+ fonts-dejavu-core \
35
+ fonts-liberation \
36
+ fonts-noto-color-emoji \
37
+ && rm -rf /var/lib/apt/lists/* \
38
+ && uv pip install --python /opt/hermes/.venv/bin/python --no-cache-dir \
39
+ huggingface_hub hf_transfer pyyaml
40
+
41
+ # Clone nesquena/hermes-webui (install deps into the agent venv so imports resolve)
42
+ RUN git clone --depth 1 --branch ${WEBUI_REF} \
43
+ https://github.com/nesquena/hermes-webui.git /opt/hermes-webui \
44
+ && ( [ -f /opt/hermes-webui/requirements.txt ] \
45
+ && /opt/hermes/.venv/bin/pip install --no-cache-dir -r /opt/hermes-webui/requirements.txt \
46
+ || true ) \
47
+ && chown -R hermes:hermes /opt/hermes-webui
48
+
49
+ # HuggingMes-style integration scripts (vendored from somratpro/HuggingMes)
50
+ COPY --chown=hermes:hermes start.sh /opt/huggingmes/start.sh
51
+ COPY --chown=hermes:hermes health-server.js /opt/huggingmes/health-server.js
52
+ COPY --chown=hermes:hermes hermes-sync.py /opt/huggingmes/hermes-sync.py
53
+ COPY --chown=hermes:hermes cloudflare-proxy-setup.py /opt/huggingmes/cloudflare-proxy-setup.py
54
+ COPY --chown=hermes:hermes cloudflare-keepalive-setup.py /opt/huggingmes/cloudflare-keepalive-setup.py
55
+
56
+ RUN chmod +x \
57
+ /opt/huggingmes/start.sh \
58
+ /opt/huggingmes/hermes-sync.py \
59
+ /opt/huggingmes/cloudflare-proxy-setup.py \
60
+ /opt/huggingmes/cloudflare-keepalive-setup.py
61
+
62
+ # Idempotent kanban migration patch (same workaround HuggingMes ships)
63
+ RUN python3 - <<'PY'
64
+ from pathlib import Path
65
+ import sys
66
+ p = Path("/opt/hermes/hermes_cli/kanban_db.py")
67
+ if not p.exists():
68
+ sys.exit(0)
69
+ src = p.read_text(encoding="utf-8")
70
+ sentinel = "# huggingmes-webui: idempotent-alter"
71
+ if sentinel in src:
72
+ sys.exit(0)
73
+ old = (
74
+ ' conn.execute(\n'
75
+ ' "ALTER TABLE tasks ADD COLUMN consecutive_failures "\n'
76
+ ' "INTEGER NOT NULL DEFAULT 0"\n'
77
+ ' )'
78
+ )
79
+ new = (
80
+ f' try: {sentinel}\n'
81
+ ' conn.execute(\n'
82
+ ' "ALTER TABLE tasks ADD COLUMN consecutive_failures "\n'
83
+ ' "INTEGER NOT NULL DEFAULT 0"\n'
84
+ ' )\n'
85
+ ' except Exception:\n'
86
+ ' pass'
87
+ )
88
+ if old in src:
89
+ p.write_text(src.replace(old, new), encoding="utf-8")
90
+ print("kanban patch: applied")
91
+ PY
92
+
93
+ # Quiet hermes-webui's per-request access log noise.
94
+ # By default it prints \[webui] {"ts":...,"method":...}\ for EVERY request,
95
+ # which drowns the HF Logs tab once any browser tab is open polling
96
+ # /api/dashboard/status, /api/health/agent, /api/sessions, /sw.js, etc.
97
+ # Patch log_request() to drop 2xx responses for high-frequency poll paths.
98
+ # Errors and chat/streaming paths still log normally.
99
+ RUN python3 - <<'PY'
100
+ from pathlib import Path
101
+ import re
102
+ import sys
103
+
104
+ p = Path("/opt/hermes-webui/server.py")
105
+ if not p.exists():
106
+ sys.exit(0)
107
+ src = p.read_text(encoding="utf-8")
108
+ sentinel = "# huggingmes-webui: quiet-poll-paths"
109
+ if sentinel in src:
110
+ sys.exit(0)
111
+
112
+ old = (
113
+ " def log_request(self, code: str='-', size: str='-') -> None:\n"
114
+ " \"\"\"Structured JSON logs for each request.\"\"\"\n"
115
+ " import json as _json\n"
116
+ " duration_ms = round((time.time() - getattr(self, '_req_t0', time.time())) * 1000, 1)\n"
117
+ " record = _json.dumps({\n"
118
+ " 'ts': time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime()),\n"
119
+ " 'method': self.command or '-',\n"
120
+ " 'path': self.path or '-',\n"
121
+ " 'status': int(code) if str(code).isdigit() else code,\n"
122
+ " 'ms': duration_ms,\n"
123
+ " })\n"
124
+ " print(f'[webui] {record}', flush=True)"
125
+ )
126
+
127
+ new = (
128
+ " _QUIET_POLL_PATHS = ( " + sentinel + "\n"
129
+ " '/api/health/agent', '/api/dashboard/status',\n"
130
+ " '/api/dashboard/config', '/api/sessions', '/api/profiles',\n"
131
+ " '/api/profile/active', '/api/onboarding/status',\n"
132
+ " '/api/insights', '/api/system/health',\n"
133
+ " '/api/settings', '/api/projects', '/api/reasoning',\n"
134
+ " '/api/models', '/api/chat/stream/status',\n"
135
+ " '/api/git-info', '/sw.js', '/health',\n"
136
+ " )\n"
137
+ " _QUIET_PREFIXES = ('/static/', '/session/static/', '/assets/')\n"
138
+ "\n"
139
+ " def log_request(self, code: str='-', size: str='-') -> None:\n"
140
+ " \"\"\"Structured JSON logs for each request, skipping noisy polls.\"\"\"\n"
141
+ " # Always log non-2xx so 401/404/5xx remain visible.\n"
142
+ " try:\n"
143
+ " status_int = int(code) if str(code).isdigit() else 0\n"
144
+ " except Exception:\n"
145
+ " status_int = 0\n"
146
+ " path = (self.path or '').split('?', 1)[0]\n"
147
+ " if 200 <= status_int < 400:\n"
148
+ " if path in self._QUIET_POLL_PATHS:\n"
149
+ " return\n"
150
+ " for pref in self._QUIET_PREFIXES:\n"
151
+ " if path.startswith(pref):\n"
152
+ " return\n"
153
+ " import json as _json\n"
154
+ " duration_ms = round((time.time() - getattr(self, '_req_t0', time.time())) * 1000, 1)\n"
155
+ " record = _json.dumps({\n"
156
+ " 'ts': time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime()),\n"
157
+ " 'method': self.command or '-',\n"
158
+ " 'path': self.path or '-',\n"
159
+ " 'status': int(code) if str(code).isdigit() else code,\n"
160
+ " 'ms': duration_ms,\n"
161
+ " })\n"
162
+ " print(f'[webui] {record}', flush=True)"
163
+ )
164
+
165
+ if old in src:
166
+ p.write_text(src.replace(old, new), encoding="utf-8")
167
+ print("webui log-quiet patch: applied")
168
+ else:
169
+ print("webui log-quiet patch: pattern not found, skipping")
170
+ PY
171
+
172
+ # Fix permissions so hermes user can self-update packages
173
+ RUN chown -R hermes:hermes /opt/hermes/.venv
174
+
175
+ # Keep hermes CLI on PATH for all shell types (login/interactive/non-interactive)
176
+ RUN echo 'export PATH="/opt/hermes/.venv/bin:/opt/data/.local/bin:$PATH"' \
177
+ > /etc/profile.d/hermes-venv.sh
178
+
179
+ ENV HERMES_HOME=/opt/data \
180
+ HUGGINGMES_APP_DIR=/opt/huggingmes \
181
+ HERMES_WEBUI_REPO=/opt/hermes-webui \
182
+ HERMES_AGENT_VERSION=${HERMES_AGENT_VERSION} \
183
+ PYTHONUNBUFFERED=1 \
184
+ HF_HUB_ENABLE_HF_TRANSFER=1 \
185
+ PLAYWRIGHT_CHROMIUM_EXECUTABLE_PATH=/usr/bin/chromium
186
+
187
+ EXPOSE 7861
188
+
189
+ HEALTHCHECK --interval=30s --timeout=5s --start-period=120s \
190
+ CMD curl -fsS http://localhost:7861/health || exit 1
191
+
192
+ USER hermes
193
+ ENTRYPOINT ["/opt/huggingmes/start.sh"]