repos / pico

pico services mono repo
git clone https://github.com/picosh/pico.git

commit
cf7db11
parent
ff4632d
author
Antonio Mika
date
2025-03-07 13:59:33 -0500 EST
Switch to senpai upstream
7 files changed,  +77, -48
M go.mod
M go.sum
M go.mod
+10, -12
 1@@ -22,10 +22,8 @@ toolchain go1.24.0
 2 
 3 // replace github.com/charmbracelet/wish => ../../wish
 4 
 5-replace git.sr.ht/~delthas/senpai => github.com/antoniomika/senpai v0.0.0-20250222151844-ab59937d60cc
 6-
 7 require (
 8-	git.sr.ht/~delthas/senpai v0.3.1-0.20240425235039-206be659439e
 9+	git.sr.ht/~delthas/senpai v0.3.1-0.20250307120855-1e7e8219bd23
10 	github.com/alecthomas/chroma/v2 v2.14.0
11 	github.com/antoniomika/syncmap v1.0.0
12 	github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de
13@@ -70,7 +68,7 @@ require (
14 	go.abhg.dev/goldmark/anchor v0.1.1
15 	go.abhg.dev/goldmark/hashtag v0.3.1
16 	go.abhg.dev/goldmark/toc v0.10.0
17-	golang.org/x/crypto v0.35.0
18+	golang.org/x/crypto v0.36.0
19 	google.golang.org/protobuf v1.36.5
20 	gopkg.in/yaml.v2 v2.4.0
21 )
22@@ -79,7 +77,7 @@ require (
23 	codeberg.org/emersion/go-scfg v0.1.0 // indirect
24 	dario.cat/mergo v1.0.0 // indirect
25 	filippo.io/edwards25519 v1.1.0 // indirect
26-	git.sr.ht/~rockorager/vaxis v0.12.1-0.20250218200016-0e88f197413a // indirect
27+	git.sr.ht/~rockorager/vaxis v0.12.1-0.20250303214113-6cc9a0be8874 // indirect
28 	github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 // indirect
29 	github.com/Masterminds/goutils v1.1.1 // indirect
30 	github.com/Masterminds/semver/v3 v3.2.0 // indirect
31@@ -329,14 +327,14 @@ require (
32 	go.uber.org/zap/exp v0.2.0 // indirect
33 	golang.org/x/crypto/x509roots/fallback v0.0.0-20240507223354-67b13616a595 // indirect
34 	golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa // indirect
35-	golang.org/x/image v0.24.0 // indirect
36+	golang.org/x/image v0.25.0 // indirect
37 	golang.org/x/mod v0.23.0 // indirect
38-	golang.org/x/net v0.35.0 // indirect
39-	golang.org/x/sync v0.11.0 // indirect
40-	golang.org/x/sys v0.30.0 // indirect
41-	golang.org/x/term v0.29.0 // indirect
42-	golang.org/x/text v0.22.0 // indirect
43-	golang.org/x/time v0.10.0 // indirect
44+	golang.org/x/net v0.37.0 // indirect
45+	golang.org/x/sync v0.12.0 // indirect
46+	golang.org/x/sys v0.31.0 // indirect
47+	golang.org/x/term v0.30.0 // indirect
48+	golang.org/x/text v0.23.0 // indirect
49+	golang.org/x/time v0.11.0 // indirect
50 	golang.org/x/tools v0.30.0 // indirect
51 	google.golang.org/genproto/googleapis/api v0.0.0-20250115164207-1a7da9e5054f // indirect
52 	google.golang.org/genproto/googleapis/rpc v0.0.0-20250115164207-1a7da9e5054f // indirect
M go.sum
+20, -20
  1@@ -18,8 +18,10 @@ dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk=
  2 dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
  3 filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
  4 filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
  5-git.sr.ht/~rockorager/vaxis v0.12.1-0.20250218200016-0e88f197413a h1:duJRKIJCDSWNUx1A7GmlGK2HcRxbVFrFiXSqAW2EBHE=
  6-git.sr.ht/~rockorager/vaxis v0.12.1-0.20250218200016-0e88f197413a/go.mod h1:h94aKek3frIV1hJbdXjqnBqaLkbWXvV+UxAsQHg9bns=
  7+git.sr.ht/~delthas/senpai v0.3.1-0.20250307120855-1e7e8219bd23 h1:i4U3UUb9dxHIuvdJQdbY/Cj4S6RPmitq8ahV0jt+CP0=
  8+git.sr.ht/~delthas/senpai v0.3.1-0.20250307120855-1e7e8219bd23/go.mod h1:RzVz1R7QRHGcRDnJTcr7AN/cD3rj9scdgvupkXTJLYk=
  9+git.sr.ht/~rockorager/vaxis v0.12.1-0.20250303214113-6cc9a0be8874 h1:J582m7egrvWSJGay9GUAASHnM8zqzRbCaU8P64/B7/U=
 10+git.sr.ht/~rockorager/vaxis v0.12.1-0.20250303214113-6cc9a0be8874/go.mod h1:RSNtZnMeIwpyQzgIEYo9EHJb8Wcl/RhFSxypLpD/ajg=
 11 github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 h1:cTp8I5+VIoKjsnZuH8vjyaysT/ses3EvZeaV/1UkF2M=
 12 github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
 13 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 14@@ -64,8 +66,6 @@ github.com/antlabs/timer v0.0.11 h1:z75oGFLeTqJHMOcWzUPBKsBbQAz4Ske3AfqJ7bsdcwU=
 15 github.com/antlabs/timer v0.0.11/go.mod h1:JNV8J3yGvMKhCavGXgj9HXrVZkfdQyKCcqXBT8RdyuU=
 16 github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI=
 17 github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g=
 18-github.com/antoniomika/senpai v0.0.0-20250222151844-ab59937d60cc h1:GwAKg5l25HphCYFcvEV50+q4FXY0aGhNWSXbazkRJ5E=
 19-github.com/antoniomika/senpai v0.0.0-20250222151844-ab59937d60cc/go.mod h1:RzVz1R7QRHGcRDnJTcr7AN/cD3rj9scdgvupkXTJLYk=
 20 github.com/antoniomika/syncmap v1.0.0 h1:iFSfbQFQOvHZILFZF+hqWosO0no+W9+uF4y2VEyMKWU=
 21 github.com/antoniomika/syncmap v1.0.0/go.mod h1:fK2829foEYnO4riNfyUn0SHQZt4ue3DStYjGU+sJj38=
 22 github.com/araddon/dateparse v0.0.0-20210429162001-6b43995a97de h1:FxWPpzIjnTlhPwqqXc4/vE0f7GvRjuAsbW+HOIe8KnA=
 23@@ -1023,16 +1023,16 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
 24 golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
 25 golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
 26 golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
 27-golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs=
 28-golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ=
 29+golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
 30+golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
 31 golang.org/x/crypto/x509roots/fallback v0.0.0-20240507223354-67b13616a595 h1:TgSqweA595vD0Zt86JzLv3Pb/syKg8gd5KMGGbJPYFw=
 32 golang.org/x/crypto/x509roots/fallback v0.0.0-20240507223354-67b13616a595/go.mod h1:kNa9WdvYnzFwC79zRpLRMJbdEFlhyM5RPFBBZp/wWH8=
 33 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 34 golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa h1:t2QcU6V556bFjYgu4L6C+6VrCPyJZ+eyRsABUPs1mz4=
 35 golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa/go.mod h1:BHOTPb3L19zxehTsLoJXVaTktb06DFgmdW6Wb9s8jqk=
 36 golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
 37-golang.org/x/image v0.24.0 h1:AN7zRgVsbvmTfNyqIbbOraYL8mSwcKncEj8ofjgzcMQ=
 38-golang.org/x/image v0.24.0/go.mod h1:4b/ITuLfqYq1hqZcjofwctIhi7sZh2WaCjvsBNjjya8=
 39+golang.org/x/image v0.25.0 h1:Y6uW6rH1y5y/LK1J8BPWZtr6yZ7hrsy6hFrXjgsc2fQ=
 40+golang.org/x/image v0.25.0/go.mod h1:tCAmOEGthTtkalusGp1g3xa2gke8J6c2N565dTyl9Rs=
 41 golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
 42 golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
 43 golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
 44@@ -1075,8 +1075,8 @@ golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
 45 golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
 46 golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
 47 golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
 48-golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
 49-golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
 50+golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c=
 51+golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
 52 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 53 golang.org/x/oauth2 v0.25.0 h1:CY4y7XT9v0cRI9oupztF8AgiIu99L/ksR/Xp/6jrZ70=
 54 golang.org/x/oauth2 v0.25.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
 55@@ -1090,8 +1090,8 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ
 56 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 57 golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 58 golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 59-golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
 60-golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
 61+golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
 62+golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
 63 golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 64 golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 65 golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 66@@ -1147,8 +1147,8 @@ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 67 golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 68 golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 69 golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 70-golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
 71-golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 72+golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
 73+golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
 74 golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
 75 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 76 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 77@@ -1158,8 +1158,8 @@ golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
 78 golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
 79 golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
 80 golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
 81-golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU=
 82-golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s=
 83+golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y=
 84+golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g=
 85 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 86 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
 87 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 88@@ -1170,10 +1170,10 @@ golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
 89 golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
 90 golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
 91 golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
 92-golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
 93-golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
 94-golang.org/x/time v0.10.0 h1:3usCWA8tQn0L8+hFJQNgzpWbd89begxN66o1Ojdn5L4=
 95-golang.org/x/time v0.10.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
 96+golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
 97+golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
 98+golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
 99+golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
100 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
101 golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
102 golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
M pico/cli.go
+16, -0
 1@@ -133,6 +133,22 @@ func WishMiddleware(handler *CliHandler) wish.Middleware {
 2 					return
 3 				}
 4 
 5+				ff, err := dbpool.FindFeatureForUser(user.ID, "plus")
 6+				if err != nil {
 7+					handler.Logger.Error("Unable to find plus feature flag", "err", err, "user", user, "command", args)
 8+					ff, err = dbpool.FindFeatureForUser(user.ID, "bouncer")
 9+					if err != nil {
10+						handler.Logger.Error("Unable to find bouncer feature flag", "err", err, "user", user, "command", args)
11+						wish.Fatalln(sesh, "Unable to find plus or bouncer feature flag")
12+						return
13+					}
14+				}
15+
16+				if ff == nil {
17+					wish.Fatalln(sesh, "Unable to find plus or bouncer feature flag")
18+					return
19+				}
20+
21 				pass, err := dbpool.UpsertToken(user.ID, "pico-chat")
22 				if err != nil {
23 					wish.Fatalln(sesh, err)
M tui/chat/chat.go
+10, -4
 1@@ -21,10 +21,16 @@ type Model struct {
 2 }
 3 
 4 func NewModel(shrd *common.SharedModel) Model {
 5-	return Model{
 6+	m := Model{
 7 		shared: shrd,
 8 		focus:  focusChat,
 9 	}
10+
11+	if m.shared.PlusFeatureFlag == nil && m.shared.BouncerFeatureFlag == nil {
12+		m.focus = focusNone
13+	}
14+
15+	return m
16 }
17 
18 func (m Model) Init() tea.Cmd {
19@@ -38,7 +44,7 @@ func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
20 		case "q", "esc":
21 			return m, pages.Navigate(pages.MenuPage)
22 		case "tab":
23-			if m.focus == focusNone {
24+			if m.focus == focusNone && (m.shared.PlusFeatureFlag != nil || m.shared.BouncerFeatureFlag != nil) {
25 				m.focus = focusChat
26 			} else {
27 				m.focus = focusNone
28@@ -69,11 +75,11 @@ If you want to quickly chat with us on IRC without pico+, go to the web chat:
29 
30 	str := ""
31 	hasPlus := m.shared.PlusFeatureFlag != nil
32-	if hasPlus {
33+	if hasPlus || m.shared.BouncerFeatureFlag != nil {
34 		hasFocus := m.focus == focusChat
35 		str += banner + "\n\nLet's Chat!  " + common.OKButtonView(m.shared.Styles, hasFocus, true)
36 	} else {
37-		str += banner + "\n\n" + m.shared.Styles.Error.SetString("Our IRC Bouncer is only available to pico+ users.").String()
38+		str += banner + "\n\n" + m.shared.Styles.Error.SetString("Our IRC Bouncer is only available to pico+ users.\n\nHit Esc or q to return.").String()
39 	}
40 
41 	return m.shared.Styles.RoundedBorder.Width(maxWidth).SetString(str).String()
M tui/common/model.go
+12, -11
 1@@ -9,15 +9,16 @@ import (
 2 )
 3 
 4 type SharedModel struct {
 5-	Logger          *slog.Logger
 6-	Session         ssh.Session
 7-	Cfg             *shared.ConfigSite
 8-	Dbpool          db.DB
 9-	User            *db.User
10-	PlusFeatureFlag *db.FeatureFlag
11-	Width           int
12-	Height          int
13-	HeaderHeight    int
14-	Styles          Styles
15-	Impersonated    bool
16+	Logger             *slog.Logger
17+	Session            ssh.Session
18+	Cfg                *shared.ConfigSite
19+	Dbpool             db.DB
20+	User               *db.User
21+	PlusFeatureFlag    *db.FeatureFlag
22+	BouncerFeatureFlag *db.FeatureFlag
23+	Width              int
24+	Height             int
25+	HeaderHeight       int
26+	Styles             Styles
27+	Impersonated       bool
28 }
M tui/ui.go
+4, -0
 1@@ -64,9 +64,13 @@ func (m *UI) setupUser() error {
 2 	}
 3 
 4 	m.shared.User = user
 5+
 6 	ff, _ := findPlusFeatureFlag(m.shared)
 7 	m.shared.PlusFeatureFlag = ff
 8 
 9+	bff, _ := findFeatureFlag(m.shared, "bouncer")
10+	m.shared.BouncerFeatureFlag = bff
11+
12 	return nil
13 }
14 
M tui/util.go
+5, -1
 1@@ -51,11 +51,15 @@ func findUser(shrd *common.SharedModel) (*db.User, error) {
 2 }
 3 
 4 func findPlusFeatureFlag(shrd *common.SharedModel) (*db.FeatureFlag, error) {
 5+	return findFeatureFlag(shrd, "plus")
 6+}
 7+
 8+func findFeatureFlag(shrd *common.SharedModel, feature string) (*db.FeatureFlag, error) {
 9 	if shrd.User == nil {
10 		return nil, nil
11 	}
12 
13-	ff, err := shrd.Dbpool.FindFeatureForUser(shrd.User.ID, "plus")
14+	ff, err := shrd.Dbpool.FindFeatureForUser(shrd.User.ID, feature)
15 	if err != nil {
16 		return nil, err
17 	}