generated from nhcarrigan/template
Compare commits
No commits in common. "main" and "v1.0.0" have entirely different histories.
@ -1,34 +0,0 @@
|
||||
name: Code Analysis
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
sonar:
|
||||
name: SonarQube
|
||||
|
||||
steps:
|
||||
- name: Checkout Source Files
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: SonarCube Scan
|
||||
uses: SonarSource/sonarqube-scan-action@v4
|
||||
timeout-minutes: 10
|
||||
env:
|
||||
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
||||
SONAR_HOST_URL: "https://quality.nhcarrigan.com"
|
||||
with:
|
||||
args: >
|
||||
-Dsonar.sources=.
|
||||
-Dsonar.projectKey=cordelia-taryne
|
||||
|
||||
- name: SonarQube Quality Gate check
|
||||
uses: sonarsource/sonarqube-quality-gate-action@v1
|
||||
with:
|
||||
pollingTimeoutSec: 600
|
||||
env:
|
||||
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
|
||||
SONAR_HOST_URL: "https://quality.nhcarrigan.com"
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "cordelia-taryne",
|
||||
"version": "1.1.0",
|
||||
"version": "1.0.0",
|
||||
"description": "An AI-powered multi-purpose assistant for Discord.",
|
||||
"main": "index.js",
|
||||
"type": "module",
|
||||
@ -22,8 +22,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@anthropic-ai/sdk": "0.36.3",
|
||||
"@nhcarrigan/logger": "1.0.0",
|
||||
"discord.js": "14.18.0",
|
||||
"fastify": "5.2.1"
|
||||
"fastify": "5.2.1",
|
||||
"winston": "3.17.0"
|
||||
}
|
||||
}
|
||||
|
206
pnpm-lock.yaml
generated
206
pnpm-lock.yaml
generated
@ -11,15 +11,15 @@ importers:
|
||||
'@anthropic-ai/sdk':
|
||||
specifier: 0.36.3
|
||||
version: 0.36.3
|
||||
'@nhcarrigan/logger':
|
||||
specifier: 1.0.0
|
||||
version: 1.0.0
|
||||
discord.js:
|
||||
specifier: 14.18.0
|
||||
version: 14.18.0
|
||||
fastify:
|
||||
specifier: 5.2.1
|
||||
version: 5.2.1
|
||||
winston:
|
||||
specifier: 3.17.0
|
||||
version: 3.17.0
|
||||
devDependencies:
|
||||
'@nhcarrigan/eslint-config':
|
||||
specifier: 5.1.0
|
||||
@ -50,6 +50,13 @@ packages:
|
||||
resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==}
|
||||
engines: {node: '>=6.9.0'}
|
||||
|
||||
'@colors/colors@1.6.0':
|
||||
resolution: {integrity: sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==}
|
||||
engines: {node: '>=0.1.90'}
|
||||
|
||||
'@dabh/diagnostics@2.0.3':
|
||||
resolution: {integrity: sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==}
|
||||
|
||||
'@discordjs/builders@1.10.1':
|
||||
resolution: {integrity: sha512-OWo1fY4ztL1/M/DUyRPShB4d/EzVfuUvPTRRHRIt/YxBrUYSz0a+JicD5F5zHFoNs2oTuWavxCOVFV1UljHTng==}
|
||||
engines: {node: '>=16.11.0'}
|
||||
@ -340,9 +347,6 @@ packages:
|
||||
typescript: '>=5'
|
||||
vitest: '>=2'
|
||||
|
||||
'@nhcarrigan/logger@1.0.0':
|
||||
resolution: {integrity: sha512-2e19Bie+ZKb6yKPKjhawqsENkhHatYkvBAmFZx9eToOXdOca+CYi51tldRMtejg6e0+4hOOf2bo5zdBQKmH0dw==}
|
||||
|
||||
'@nhcarrigan/typescript-config@4.0.0':
|
||||
resolution: {integrity: sha512-969HVha7A/Sg77fuMwOm6p14a+7C5iE6g55OD71srqwKIgksQl+Ex/hAI/pyzTQFDQ/FBJbpnHlR4Ov25QV/rw==}
|
||||
engines: {node: '20', pnpm: '9'}
|
||||
@ -502,6 +506,9 @@ packages:
|
||||
'@types/normalize-package-data@2.4.4':
|
||||
resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==}
|
||||
|
||||
'@types/triple-beam@1.3.5':
|
||||
resolution: {integrity: sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==}
|
||||
|
||||
'@types/ws@8.5.14':
|
||||
resolution: {integrity: sha512-bd/YFLW+URhBzMXurx7lWByOu+xzU9+kb3RboOteXYDfW+tr+JZa99OyNmPINEGB/ahzKrEuc8rcv4gnpJmxTw==}
|
||||
|
||||
@ -745,6 +752,9 @@ packages:
|
||||
resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
async@3.2.6:
|
||||
resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==}
|
||||
|
||||
asynckit@0.4.0:
|
||||
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
|
||||
|
||||
@ -824,13 +834,28 @@ packages:
|
||||
resolution: {integrity: sha512-GfisEZEJvzKrmGWkvfhgzcz/BllN1USeqD2V6tg14OAOgaCD2Z/PUEuxnAZ/nPvmaHRG7a8y77p1T/IRQ4D1Hw==}
|
||||
engines: {node: '>=4'}
|
||||
|
||||
color-convert@1.9.3:
|
||||
resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
|
||||
|
||||
color-convert@2.0.1:
|
||||
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
|
||||
engines: {node: '>=7.0.0'}
|
||||
|
||||
color-name@1.1.3:
|
||||
resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==}
|
||||
|
||||
color-name@1.1.4:
|
||||
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
|
||||
|
||||
color-string@1.9.1:
|
||||
resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==}
|
||||
|
||||
color@3.2.1:
|
||||
resolution: {integrity: sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==}
|
||||
|
||||
colorspace@1.1.4:
|
||||
resolution: {integrity: sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==}
|
||||
|
||||
combined-stream@1.0.8:
|
||||
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
|
||||
engines: {node: '>= 0.8'}
|
||||
@ -927,6 +952,9 @@ packages:
|
||||
electron-to-chromium@1.5.97:
|
||||
resolution: {integrity: sha512-HKLtaH02augM7ZOdYRuO19rWDeY+QSJ1VxnXFa/XDFLf07HvM90pALIJFgrO+UVaajI3+aJMMpojoUTLZyQ7JQ==}
|
||||
|
||||
enabled@2.0.0:
|
||||
resolution: {integrity: sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==}
|
||||
|
||||
error-ex@1.3.2:
|
||||
resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==}
|
||||
|
||||
@ -1145,6 +1173,9 @@ packages:
|
||||
fastq@1.19.0:
|
||||
resolution: {integrity: sha512-7SFSRCNjBQIZH/xZR3iy5iQYR8aGBE0h3VG6/cwlbrpdciNYBMotQav8c1XI3HjHH+NikUpP53nPdlZSdWmFzA==}
|
||||
|
||||
fecha@4.2.3:
|
||||
resolution: {integrity: sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==}
|
||||
|
||||
file-entry-cache@8.0.0:
|
||||
resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==}
|
||||
engines: {node: '>=16.0.0'}
|
||||
@ -1172,6 +1203,9 @@ packages:
|
||||
flatted@3.3.2:
|
||||
resolution: {integrity: sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==}
|
||||
|
||||
fn.name@1.1.0:
|
||||
resolution: {integrity: sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==}
|
||||
|
||||
for-each@0.3.4:
|
||||
resolution: {integrity: sha512-kKaIINnFpzW6ffJNDjjyjrk21BkDx38c0xa/klsT8VzLCaMEefv4ZTacrcVR4DmgTeBra++jMDAfS/tS799YDw==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@ -1303,6 +1337,9 @@ packages:
|
||||
resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
inherits@2.0.4:
|
||||
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
|
||||
|
||||
internal-slot@1.1.0:
|
||||
resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@ -1318,6 +1355,9 @@ packages:
|
||||
is-arrayish@0.2.1:
|
||||
resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==}
|
||||
|
||||
is-arrayish@0.3.2:
|
||||
resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==}
|
||||
|
||||
is-async-function@2.1.1:
|
||||
resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@ -1390,6 +1430,10 @@ packages:
|
||||
resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
is-stream@2.0.1:
|
||||
resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
is-string@1.1.1:
|
||||
resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@ -1473,6 +1517,9 @@ packages:
|
||||
keyv@4.5.4:
|
||||
resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
|
||||
|
||||
kuler@2.0.0:
|
||||
resolution: {integrity: sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==}
|
||||
|
||||
levn@0.4.1:
|
||||
resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
|
||||
engines: {node: '>= 0.8.0'}
|
||||
@ -1500,6 +1547,10 @@ packages:
|
||||
lodash@4.17.21:
|
||||
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
|
||||
|
||||
logform@2.7.0:
|
||||
resolution: {integrity: sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
|
||||
loose-envify@1.4.0:
|
||||
resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
|
||||
hasBin: true
|
||||
@ -1613,6 +1664,9 @@ packages:
|
||||
resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
|
||||
one-time@1.0.0:
|
||||
resolution: {integrity: sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==}
|
||||
|
||||
optionator@0.9.4:
|
||||
resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==}
|
||||
engines: {node: '>= 0.8.0'}
|
||||
@ -1753,6 +1807,10 @@ packages:
|
||||
resolution: {integrity: sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
readable-stream@3.6.2:
|
||||
resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==}
|
||||
engines: {node: '>= 6'}
|
||||
|
||||
real-require@0.2.0:
|
||||
resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==}
|
||||
engines: {node: '>= 12.13.0'}
|
||||
@ -1817,6 +1875,9 @@ packages:
|
||||
resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==}
|
||||
engines: {node: '>=0.4'}
|
||||
|
||||
safe-buffer@5.2.1:
|
||||
resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
|
||||
|
||||
safe-push-apply@1.0.0:
|
||||
resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@ -1890,6 +1951,9 @@ packages:
|
||||
siginfo@2.0.0:
|
||||
resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==}
|
||||
|
||||
simple-swizzle@0.2.2:
|
||||
resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==}
|
||||
|
||||
slash@3.0.0:
|
||||
resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
|
||||
engines: {node: '>=8'}
|
||||
@ -1923,6 +1987,9 @@ packages:
|
||||
resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==}
|
||||
engines: {node: '>= 10.x'}
|
||||
|
||||
stack-trace@0.0.10:
|
||||
resolution: {integrity: sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==}
|
||||
|
||||
stackback@0.0.2:
|
||||
resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==}
|
||||
|
||||
@ -1948,6 +2015,9 @@ packages:
|
||||
resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
string_decoder@1.3.0:
|
||||
resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==}
|
||||
|
||||
strip-bom@3.0.0:
|
||||
resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==}
|
||||
engines: {node: '>=4'}
|
||||
@ -1972,6 +2042,9 @@ packages:
|
||||
resolution: {integrity: sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw==}
|
||||
engines: {node: ^14.18.0 || >=16.0.0}
|
||||
|
||||
text-hex@1.0.0:
|
||||
resolution: {integrity: sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==}
|
||||
|
||||
thread-stream@3.1.0:
|
||||
resolution: {integrity: sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==}
|
||||
|
||||
@ -2004,6 +2077,10 @@ packages:
|
||||
tr46@0.0.3:
|
||||
resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==}
|
||||
|
||||
triple-beam@1.4.1:
|
||||
resolution: {integrity: sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==}
|
||||
engines: {node: '>= 14.0.0'}
|
||||
|
||||
ts-api-utils@1.4.3:
|
||||
resolution: {integrity: sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==}
|
||||
engines: {node: '>=16'}
|
||||
@ -2085,6 +2162,9 @@ packages:
|
||||
uri-js@4.4.1:
|
||||
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
|
||||
|
||||
util-deprecate@1.0.2:
|
||||
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
|
||||
|
||||
validate-npm-package-license@3.0.4:
|
||||
resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==}
|
||||
|
||||
@ -2197,6 +2277,14 @@ packages:
|
||||
engines: {node: '>=8'}
|
||||
hasBin: true
|
||||
|
||||
winston-transport@4.9.0:
|
||||
resolution: {integrity: sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
|
||||
winston@3.17.0:
|
||||
resolution: {integrity: sha512-DLiFIXYC5fMPxaRg832S6F5mJYvePtmO5G9v9IgUFPhXm9/GkXarH/TUrBAVzhTCzAj9anE/+GjrgXp/54nOgw==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
|
||||
word-wrap@1.2.5:
|
||||
resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@ -2239,6 +2327,14 @@ snapshots:
|
||||
|
||||
'@babel/helper-validator-identifier@7.25.9': {}
|
||||
|
||||
'@colors/colors@1.6.0': {}
|
||||
|
||||
'@dabh/diagnostics@2.0.3':
|
||||
dependencies:
|
||||
colorspace: 1.1.4
|
||||
enabled: 2.0.0
|
||||
kuler: 2.0.0
|
||||
|
||||
'@discordjs/builders@1.10.1':
|
||||
dependencies:
|
||||
'@discordjs/formatters': 0.6.0
|
||||
@ -2492,8 +2588,6 @@ snapshots:
|
||||
- eslint-import-resolver-webpack
|
||||
- supports-color
|
||||
|
||||
'@nhcarrigan/logger@1.0.0': {}
|
||||
|
||||
'@nhcarrigan/typescript-config@4.0.0(typescript@5.7.3)':
|
||||
dependencies:
|
||||
typescript: 5.7.3
|
||||
@ -2613,6 +2707,8 @@ snapshots:
|
||||
|
||||
'@types/normalize-package-data@2.4.4': {}
|
||||
|
||||
'@types/triple-beam@1.3.5': {}
|
||||
|
||||
'@types/ws@8.5.14':
|
||||
dependencies:
|
||||
'@types/node': 22.13.1
|
||||
@ -2937,6 +3033,8 @@ snapshots:
|
||||
|
||||
async-function@1.0.0: {}
|
||||
|
||||
async@3.2.6: {}
|
||||
|
||||
asynckit@0.4.0: {}
|
||||
|
||||
atomic-sleep@1.0.0: {}
|
||||
@ -3018,12 +3116,33 @@ snapshots:
|
||||
dependencies:
|
||||
escape-string-regexp: 1.0.5
|
||||
|
||||
color-convert@1.9.3:
|
||||
dependencies:
|
||||
color-name: 1.1.3
|
||||
|
||||
color-convert@2.0.1:
|
||||
dependencies:
|
||||
color-name: 1.1.4
|
||||
|
||||
color-name@1.1.3: {}
|
||||
|
||||
color-name@1.1.4: {}
|
||||
|
||||
color-string@1.9.1:
|
||||
dependencies:
|
||||
color-name: 1.1.4
|
||||
simple-swizzle: 0.2.2
|
||||
|
||||
color@3.2.1:
|
||||
dependencies:
|
||||
color-convert: 1.9.3
|
||||
color-string: 1.9.1
|
||||
|
||||
colorspace@1.1.4:
|
||||
dependencies:
|
||||
color: 3.2.1
|
||||
text-hex: 1.0.0
|
||||
|
||||
combined-stream@1.0.8:
|
||||
dependencies:
|
||||
delayed-stream: 1.0.0
|
||||
@ -3126,6 +3245,8 @@ snapshots:
|
||||
|
||||
electron-to-chromium@1.5.97: {}
|
||||
|
||||
enabled@2.0.0: {}
|
||||
|
||||
error-ex@1.3.2:
|
||||
dependencies:
|
||||
is-arrayish: 0.2.1
|
||||
@ -3529,6 +3650,8 @@ snapshots:
|
||||
dependencies:
|
||||
reusify: 1.0.4
|
||||
|
||||
fecha@4.2.3: {}
|
||||
|
||||
file-entry-cache@8.0.0:
|
||||
dependencies:
|
||||
flat-cache: 4.0.1
|
||||
@ -3560,6 +3683,8 @@ snapshots:
|
||||
|
||||
flatted@3.3.2: {}
|
||||
|
||||
fn.name@1.1.0: {}
|
||||
|
||||
for-each@0.3.4:
|
||||
dependencies:
|
||||
is-callable: 1.2.7
|
||||
@ -3693,6 +3818,8 @@ snapshots:
|
||||
|
||||
indent-string@4.0.0: {}
|
||||
|
||||
inherits@2.0.4: {}
|
||||
|
||||
internal-slot@1.1.0:
|
||||
dependencies:
|
||||
es-errors: 1.3.0
|
||||
@ -3709,6 +3836,8 @@ snapshots:
|
||||
|
||||
is-arrayish@0.2.1: {}
|
||||
|
||||
is-arrayish@0.3.2: {}
|
||||
|
||||
is-async-function@2.1.1:
|
||||
dependencies:
|
||||
async-function: 1.0.0
|
||||
@ -3786,6 +3915,8 @@ snapshots:
|
||||
dependencies:
|
||||
call-bound: 1.0.3
|
||||
|
||||
is-stream@2.0.1: {}
|
||||
|
||||
is-string@1.1.1:
|
||||
dependencies:
|
||||
call-bound: 1.0.3
|
||||
@ -3866,6 +3997,8 @@ snapshots:
|
||||
dependencies:
|
||||
json-buffer: 3.0.1
|
||||
|
||||
kuler@2.0.0: {}
|
||||
|
||||
levn@0.4.1:
|
||||
dependencies:
|
||||
prelude-ls: 1.2.1
|
||||
@ -3893,6 +4026,15 @@ snapshots:
|
||||
|
||||
lodash@4.17.21: {}
|
||||
|
||||
logform@2.7.0:
|
||||
dependencies:
|
||||
'@colors/colors': 1.6.0
|
||||
'@types/triple-beam': 1.3.5
|
||||
fecha: 4.2.3
|
||||
ms: 2.1.3
|
||||
safe-stable-stringify: 2.5.0
|
||||
triple-beam: 1.4.1
|
||||
|
||||
loose-envify@1.4.0:
|
||||
dependencies:
|
||||
js-tokens: 4.0.0
|
||||
@ -3996,6 +4138,10 @@ snapshots:
|
||||
|
||||
on-exit-leak-free@2.1.2: {}
|
||||
|
||||
one-time@1.0.0:
|
||||
dependencies:
|
||||
fn.name: 1.1.0
|
||||
|
||||
optionator@0.9.4:
|
||||
dependencies:
|
||||
deep-is: 0.1.4
|
||||
@ -4134,6 +4280,12 @@ snapshots:
|
||||
parse-json: 5.2.0
|
||||
type-fest: 0.6.0
|
||||
|
||||
readable-stream@3.6.2:
|
||||
dependencies:
|
||||
inherits: 2.0.4
|
||||
string_decoder: 1.3.0
|
||||
util-deprecate: 1.0.2
|
||||
|
||||
real-require@0.2.0: {}
|
||||
|
||||
reflect.getprototypeof@1.0.10:
|
||||
@ -4223,6 +4375,8 @@ snapshots:
|
||||
has-symbols: 1.1.0
|
||||
isarray: 2.0.5
|
||||
|
||||
safe-buffer@5.2.1: {}
|
||||
|
||||
safe-push-apply@1.0.0:
|
||||
dependencies:
|
||||
es-errors: 1.3.0
|
||||
@ -4308,6 +4462,10 @@ snapshots:
|
||||
|
||||
siginfo@2.0.0: {}
|
||||
|
||||
simple-swizzle@0.2.2:
|
||||
dependencies:
|
||||
is-arrayish: 0.3.2
|
||||
|
||||
slash@3.0.0: {}
|
||||
|
||||
slashes@3.0.12: {}
|
||||
@ -4339,6 +4497,8 @@ snapshots:
|
||||
|
||||
split2@4.2.0: {}
|
||||
|
||||
stack-trace@0.0.10: {}
|
||||
|
||||
stackback@0.0.2: {}
|
||||
|
||||
std-env@3.8.0: {}
|
||||
@ -4387,6 +4547,10 @@ snapshots:
|
||||
define-properties: 1.2.1
|
||||
es-object-atoms: 1.1.1
|
||||
|
||||
string_decoder@1.3.0:
|
||||
dependencies:
|
||||
safe-buffer: 5.2.1
|
||||
|
||||
strip-bom@3.0.0: {}
|
||||
|
||||
strip-indent@3.0.0:
|
||||
@ -4406,6 +4570,8 @@ snapshots:
|
||||
'@pkgr/core': 0.1.1
|
||||
tslib: 2.8.1
|
||||
|
||||
text-hex@1.0.0: {}
|
||||
|
||||
thread-stream@3.1.0:
|
||||
dependencies:
|
||||
real-require: 0.2.0
|
||||
@ -4428,6 +4594,8 @@ snapshots:
|
||||
|
||||
tr46@0.0.3: {}
|
||||
|
||||
triple-beam@1.4.1: {}
|
||||
|
||||
ts-api-utils@1.4.3(typescript@5.7.3):
|
||||
dependencies:
|
||||
typescript: 5.7.3
|
||||
@ -4515,6 +4683,8 @@ snapshots:
|
||||
dependencies:
|
||||
punycode: 2.3.1
|
||||
|
||||
util-deprecate@1.0.2: {}
|
||||
|
||||
validate-npm-package-license@3.0.4:
|
||||
dependencies:
|
||||
spdx-correct: 3.2.0
|
||||
@ -4646,6 +4816,26 @@ snapshots:
|
||||
siginfo: 2.0.0
|
||||
stackback: 0.0.2
|
||||
|
||||
winston-transport@4.9.0:
|
||||
dependencies:
|
||||
logform: 2.7.0
|
||||
readable-stream: 3.6.2
|
||||
triple-beam: 1.4.1
|
||||
|
||||
winston@3.17.0:
|
||||
dependencies:
|
||||
'@colors/colors': 1.6.0
|
||||
'@dabh/diagnostics': 2.0.3
|
||||
async: 3.2.6
|
||||
is-stream: 2.0.1
|
||||
logform: 2.7.0
|
||||
one-time: 1.0.0
|
||||
readable-stream: 3.6.2
|
||||
safe-stable-stringify: 2.5.0
|
||||
stack-trace: 0.0.10
|
||||
triple-beam: 1.4.1
|
||||
winston-transport: 4.9.0
|
||||
|
||||
word-wrap@1.2.5: {}
|
||||
|
||||
ws@8.18.0: {}
|
||||
|
1
prod.env
1
prod.env
@ -1,3 +1,2 @@
|
||||
DISCORD_TOKEN="op://Environment Variables - Naomi/Cordelia Taryne/discord_token"
|
||||
AI_TOKEN="op://Environment Variables - Naomi/Cordelia Taryne/ai_token"
|
||||
LOG_TOKEN="op://Environment Variables - Naomi/Alert Server/api_auth"
|
||||
|
28
src/index.ts
28
src/index.ts
@ -12,7 +12,7 @@ import { proofread } from "./modules/proofread.js";
|
||||
import { query } from "./modules/query.js";
|
||||
import { summarise } from "./modules/summarise.js";
|
||||
import { instantiateServer } from "./server/serve.js";
|
||||
import { logger } from "./utils/logger.js";
|
||||
import { logHandler } from "./utils/logHandler.js";
|
||||
|
||||
const commands: Record<
|
||||
string,
|
||||
@ -28,22 +28,6 @@ const commands: Record<
|
||||
"summarise": summarise,
|
||||
};
|
||||
|
||||
process.on("unhandledRejection", (error) => {
|
||||
if (error instanceof Error) {
|
||||
void logger.error("Unhandled Rejection", error);
|
||||
return;
|
||||
}
|
||||
void logger.error("unhandled rejection", new Error(String(error)));
|
||||
});
|
||||
|
||||
process.on("uncaughtException", (error) => {
|
||||
if (error instanceof Error) {
|
||||
void logger.error("Uncaught Exception", error);
|
||||
return;
|
||||
}
|
||||
void logger.error("uncaught exception", new Error(String(error)));
|
||||
});
|
||||
|
||||
const client = new Client({
|
||||
intents: [],
|
||||
});
|
||||
@ -57,16 +41,8 @@ client.on(Events.InteractionCreate, (interaction) => {
|
||||
}
|
||||
});
|
||||
|
||||
client.on(Events.EntitlementCreate, (entitlement) => {
|
||||
void logger.log("info", `User ${entitlement.userId} has subscribed!`);
|
||||
});
|
||||
|
||||
client.on(Events.EntitlementDelete, (entitlement) => {
|
||||
void logger.log("info", `User ${entitlement.userId} has unsubscribed... :c`);
|
||||
});
|
||||
|
||||
client.on(Events.ClientReady, () => {
|
||||
void logger.log("debug", "Bot is ready.");
|
||||
logHandler.info("Bot is ready.");
|
||||
});
|
||||
|
||||
instantiateServer();
|
||||
|
@ -13,66 +13,56 @@ import {
|
||||
MessageFlags,
|
||||
type ChatInputCommandInteraction,
|
||||
} from "discord.js";
|
||||
import { logger } from "../utils/logger.js";
|
||||
import { replyToError } from "../utils/replyToError.js";
|
||||
|
||||
/**
|
||||
* Responds with information about the bot.
|
||||
* @param interaction -- The interaction payload from Discord.
|
||||
*/
|
||||
// eslint-disable-next-line max-lines-per-function -- Refactor at a later time.
|
||||
export const about = async(
|
||||
interaction: ChatInputCommandInteraction,
|
||||
): Promise<void> => {
|
||||
try {
|
||||
await interaction.deferReply({ flags: [ MessageFlags.Ephemeral ] });
|
||||
await interaction.deferReply({ flags: [ MessageFlags.Ephemeral ] });
|
||||
|
||||
const version = process.env.npm_package_version ?? "Unknown";
|
||||
const commit = execSync("git rev-parse --short HEAD").toString().
|
||||
trim();
|
||||
const version = process.env.npm_package_version ?? "Unknown";
|
||||
const commit = execSync("git rev-parse --short HEAD").toString().
|
||||
trim();
|
||||
|
||||
const embed = new EmbedBuilder();
|
||||
embed.setTitle("About Cordelia Taryne");
|
||||
embed.setDescription(
|
||||
const embed = new EmbedBuilder();
|
||||
embed.setTitle("About Cordelia Taryne");
|
||||
embed.setDescription(
|
||||
// eslint-disable-next-line stylistic/max-len -- It's a long string.
|
||||
"Cordelia Taryne is a Discord bot that uses Anthropic to provide assistive features. She is developed by NHCarrigan. To use the bot, type `/` and select one of her commands!",
|
||||
);
|
||||
embed.addFields(
|
||||
{
|
||||
name: "Running Version",
|
||||
value: version,
|
||||
},
|
||||
{
|
||||
name: "Current Commit",
|
||||
value: commit,
|
||||
},
|
||||
);
|
||||
"Cordelia Taryne is a Discord bot that uses Anthropic to provide assistive features. She is developed by NHCarrigan. To use the bot, type `/` and select one of her commands!",
|
||||
);
|
||||
embed.addFields(
|
||||
{
|
||||
name: "Running Version",
|
||||
value: version,
|
||||
},
|
||||
{
|
||||
name: "Current Commit",
|
||||
value: commit,
|
||||
},
|
||||
);
|
||||
|
||||
const supportButton = new ButtonBuilder().
|
||||
setLabel("Need help?").
|
||||
setStyle(ButtonStyle.Link).
|
||||
setURL("https://chat.nhcarrigan.com");
|
||||
const sourceButton = new ButtonBuilder().
|
||||
setLabel("Source Code").
|
||||
setStyle(ButtonStyle.Link).
|
||||
setURL("https://git.nhcarrigan.com/nhcarrigan/aria-iuvo");
|
||||
const subscribeButton = new ButtonBuilder().
|
||||
setStyle(ButtonStyle.Premium).
|
||||
setSKUId("1338672773261951026");
|
||||
const row = new ActionRowBuilder<ButtonBuilder>().addComponents(
|
||||
supportButton,
|
||||
sourceButton,
|
||||
subscribeButton,
|
||||
);
|
||||
const supportButton = new ButtonBuilder().
|
||||
setLabel("Need help?").
|
||||
setStyle(ButtonStyle.Link).
|
||||
setURL("https://chat.nhcarrigan.com");
|
||||
const sourceButton = new ButtonBuilder().
|
||||
setLabel("Source Code").
|
||||
setStyle(ButtonStyle.Link).
|
||||
setURL("https://git.nhcarrigan.com/nhcarrigan/aria-iuvo");
|
||||
const subscribeButton = new ButtonBuilder().
|
||||
setStyle(ButtonStyle.Premium).
|
||||
setSKUId("1338672773261951026");
|
||||
const row = new ActionRowBuilder<ButtonBuilder>().addComponents(
|
||||
supportButton,
|
||||
sourceButton,
|
||||
subscribeButton,
|
||||
);
|
||||
|
||||
await interaction.editReply({
|
||||
components: [ row ],
|
||||
embeds: [ embed ],
|
||||
});
|
||||
} catch (error) {
|
||||
await replyToError(interaction);
|
||||
if (error instanceof Error) {
|
||||
await logger.error("about command", error);
|
||||
}
|
||||
}
|
||||
await interaction.editReply({
|
||||
components: [ row ],
|
||||
embeds: [ embed ],
|
||||
});
|
||||
};
|
||||
|
@ -6,10 +6,7 @@
|
||||
import { MessageFlags, type ChatInputCommandInteraction } from "discord.js";
|
||||
import { personality } from "../config/personality.js";
|
||||
import { ai } from "../utils/ai.js";
|
||||
import { calculateCost } from "../utils/calculateCost.js";
|
||||
import { isSubscribed } from "../utils/isSubscribed.js";
|
||||
import { logger } from "../utils/logger.js";
|
||||
import { replyToError } from "../utils/replyToError.js";
|
||||
import type { ImageBlockParam } from "@anthropic-ai/sdk/resources/index.js";
|
||||
|
||||
const isValidContentType = (
|
||||
@ -33,93 +30,83 @@ const isValidContentType = (
|
||||
export const alt = async(
|
||||
interaction: ChatInputCommandInteraction,
|
||||
): Promise<void> => {
|
||||
try {
|
||||
await interaction.deferReply({ flags: [ MessageFlags.Ephemeral ] });
|
||||
const sub = await isSubscribed(interaction);
|
||||
if (!sub) {
|
||||
return;
|
||||
}
|
||||
await interaction.deferReply({ flags: [ MessageFlags.Ephemeral ] });
|
||||
const sub = await isSubscribed(interaction);
|
||||
if (!sub) {
|
||||
return;
|
||||
}
|
||||
|
||||
const image = interaction.options.getAttachment("image", true);
|
||||
const { contentType, height, width, size, url } = image;
|
||||
const image = interaction.options.getAttachment("image", true);
|
||||
const { contentType, height, width, size, url } = image;
|
||||
|
||||
// Claude supports JPG, PNG, GIF, WEBP
|
||||
if (
|
||||
contentType === null
|
||||
// Claude supports JPG, PNG, GIF, WEBP
|
||||
if (
|
||||
contentType === null
|
||||
|| !isValidContentType(contentType)
|
||||
|| height === null
|
||||
|| width === null
|
||||
) {
|
||||
await interaction.editReply({
|
||||
content: "That does not appear to be a valid image.",
|
||||
});
|
||||
return;
|
||||
}
|
||||
) {
|
||||
await interaction.editReply({
|
||||
content: "That does not appear to be a valid image.",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Max file size is 5MB
|
||||
if (size > 5 * 1024 * 1024) {
|
||||
await interaction.editReply({
|
||||
content:
|
||||
// Max file size is 5MB
|
||||
if (size > 5 * 1024 * 1024) {
|
||||
await interaction.editReply({
|
||||
content:
|
||||
// eslint-disable-next-line stylistic/max-len -- It's a long string.
|
||||
"That image is too large. Please provide an image that is less than 5MB.",
|
||||
});
|
||||
return;
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Max dimensions are 8000px
|
||||
if (height > 8000 || width > 8000) {
|
||||
await interaction.editReply({
|
||||
content:
|
||||
// Max dimensions are 8000px
|
||||
if (height > 8000 || width > 8000) {
|
||||
await interaction.editReply({
|
||||
content:
|
||||
// eslint-disable-next-line stylistic/max-len -- It's a long string.
|
||||
"That image is too large. Please provide an image that is less than 8000 pixels high or wide.",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const downloadRequest = await fetch(url);
|
||||
|
||||
const blob = await downloadRequest.arrayBuffer();
|
||||
const base64 = Buffer.from(blob).toString("base64");
|
||||
|
||||
const messages = await ai.messages.create({
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention -- Required key format for SDK.
|
||||
max_tokens: 2000,
|
||||
messages: [
|
||||
{
|
||||
content: [
|
||||
{
|
||||
source: {
|
||||
data: base64,
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention -- Required property syntax for SDK.
|
||||
media_type: contentType,
|
||||
type: "base64",
|
||||
},
|
||||
type: "image",
|
||||
},
|
||||
],
|
||||
role: "user",
|
||||
},
|
||||
],
|
||||
model: "claude-3-5-sonnet-latest",
|
||||
system: `${personality} Your role in this conversation is to generate descriptive and accessible alt-text for the user's image. Be as descriptive as possible. Do not include ANYTHING in your response EXCEPT the actual alt-text. Wrap the text in a multi-line code block for easy copying.`,
|
||||
temperature: 1,
|
||||
});
|
||||
|
||||
const response = messages.content.find((message) => {
|
||||
return message.type === "text";
|
||||
});
|
||||
|
||||
await interaction.editReply(
|
||||
response?.text
|
||||
?? "I'm sorry, I don't have an answer for that. Please try again later.",
|
||||
);
|
||||
|
||||
const { usage } = messages;
|
||||
await calculateCost(usage, interaction.user.username, "alt-text");
|
||||
} catch (error) {
|
||||
await replyToError(interaction);
|
||||
if (error instanceof Error) {
|
||||
await logger.error("alt-text command", error);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const downloadRequest = await fetch(url);
|
||||
|
||||
const blob = await downloadRequest.arrayBuffer();
|
||||
const base64 = Buffer.from(blob).toString("base64");
|
||||
|
||||
const messages = await ai.messages.create({
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention -- Required key format for SDK.
|
||||
max_tokens: 2000,
|
||||
messages: [
|
||||
{
|
||||
content: [
|
||||
{
|
||||
source: {
|
||||
data: base64,
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention -- Required property syntax for SDK.
|
||||
media_type: contentType,
|
||||
type: "base64",
|
||||
},
|
||||
type: "image",
|
||||
},
|
||||
],
|
||||
role: "user",
|
||||
},
|
||||
],
|
||||
model: "claude-3-5-sonnet-latest",
|
||||
system: `${personality} Your role in this conversation is to generate descriptive and accessible alt-text for the user's image. Be as descriptive as possible. Do not include ANYTHING in your response EXCEPT the actual alt-text. Wrap the text in a multi-line code block for easy copying.`,
|
||||
temperature: 1,
|
||||
});
|
||||
|
||||
const response = messages.content.find((message) => {
|
||||
return message.type === "text";
|
||||
});
|
||||
|
||||
await interaction.editReply(
|
||||
response?.text
|
||||
?? "I'm sorry, I don't have an answer for that. Please try again later.",
|
||||
);
|
||||
};
|
||||
|
@ -6,10 +6,7 @@
|
||||
import { MessageFlags, type ChatInputCommandInteraction } from "discord.js";
|
||||
import { personality } from "../config/personality.js";
|
||||
import { ai } from "../utils/ai.js";
|
||||
import { calculateCost } from "../utils/calculateCost.js";
|
||||
import { isSubscribed } from "../utils/isSubscribed.js";
|
||||
import { logger } from "../utils/logger.js";
|
||||
import { replyToError } from "../utils/replyToError.js";
|
||||
|
||||
/**
|
||||
* Accepts an arbitrary code snippet from the user, then sends
|
||||
@ -19,38 +16,28 @@ import { replyToError } from "../utils/replyToError.js";
|
||||
export const evaluate = async(
|
||||
interaction: ChatInputCommandInteraction,
|
||||
): Promise<void> => {
|
||||
try {
|
||||
await interaction.deferReply({ flags: [ MessageFlags.Ephemeral ] });
|
||||
const sub = await isSubscribed(interaction);
|
||||
if (!sub) {
|
||||
return;
|
||||
}
|
||||
|
||||
const code = interaction.options.getString("code", true);
|
||||
const messages = await ai.messages.create({
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention -- Required key format for SDK.
|
||||
max_tokens: 2000,
|
||||
messages: [ { content: code, role: "user" } ],
|
||||
model: "claude-3-5-sonnet-latest",
|
||||
system: `${personality} Your role in this conversation is to evaluate the user's code and provide the result. Wrap ONLY THE CODE RESULT in a multi-line code block for easy copying.`,
|
||||
temperature: 1,
|
||||
});
|
||||
|
||||
const response = messages.content.find((message) => {
|
||||
return message.type === "text";
|
||||
});
|
||||
|
||||
await interaction.editReply(
|
||||
response?.text
|
||||
?? "I'm sorry, I don't have an answer for that. Please try again later.",
|
||||
);
|
||||
|
||||
const { usage } = messages;
|
||||
await calculateCost(usage, interaction.user.username, "evaluate");
|
||||
} catch (error) {
|
||||
await replyToError(interaction);
|
||||
if (error instanceof Error) {
|
||||
await logger.error("evaluate command", error);
|
||||
}
|
||||
await interaction.deferReply({ flags: [ MessageFlags.Ephemeral ] });
|
||||
const sub = await isSubscribed(interaction);
|
||||
if (!sub) {
|
||||
return;
|
||||
}
|
||||
|
||||
const code = interaction.options.getString("code", true);
|
||||
const messages = await ai.messages.create({
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention -- Required key format for SDK.
|
||||
max_tokens: 2000,
|
||||
messages: [ { content: code, role: "user" } ],
|
||||
model: "claude-3-5-sonnet-latest",
|
||||
system: `${personality} Your role in this conversation is to evaluate the user's code and provide the result. Wrap ONLY THE CODE RESULT in a multi-line code block for easy copying.`,
|
||||
temperature: 1,
|
||||
});
|
||||
|
||||
const response = messages.content.find((message) => {
|
||||
return message.type === "text";
|
||||
});
|
||||
|
||||
await interaction.editReply(
|
||||
response?.text
|
||||
?? "I'm sorry, I don't have an answer for that. Please try again later.",
|
||||
);
|
||||
};
|
||||
|
@ -6,10 +6,7 @@
|
||||
import { MessageFlags, type ChatInputCommandInteraction } from "discord.js";
|
||||
import { personality } from "../config/personality.js";
|
||||
import { ai } from "../utils/ai.js";
|
||||
import { calculateCost } from "../utils/calculateCost.js";
|
||||
import { isSubscribed } from "../utils/isSubscribed.js";
|
||||
import { logger } from "../utils/logger.js";
|
||||
import { replyToError } from "../utils/replyToError.js";
|
||||
|
||||
/**
|
||||
* Accepts a text snippet from the user. Submits it to Anthropic
|
||||
@ -19,39 +16,29 @@ import { replyToError } from "../utils/replyToError.js";
|
||||
export const mood = async(
|
||||
interaction: ChatInputCommandInteraction,
|
||||
): Promise<void> => {
|
||||
try {
|
||||
await interaction.deferReply({ flags: [ MessageFlags.Ephemeral ] });
|
||||
const sub = await isSubscribed(interaction);
|
||||
if (!sub) {
|
||||
return;
|
||||
}
|
||||
|
||||
const prompt = interaction.options.getString("text", true);
|
||||
|
||||
const messages = await ai.messages.create({
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention -- Required key format for SDK.
|
||||
max_tokens: 2000,
|
||||
messages: [ { content: prompt, role: "user" } ],
|
||||
model: "claude-3-5-sonnet-latest",
|
||||
system: `${personality} Your role in this conversation is to analyse the text the user provides for the overall sentiment and mood of the author.`,
|
||||
temperature: 1,
|
||||
});
|
||||
|
||||
const response = messages.content.find((message) => {
|
||||
return message.type === "text";
|
||||
});
|
||||
|
||||
await interaction.editReply(
|
||||
response?.text
|
||||
?? "I'm sorry, I don't have an answer for that. Please try again later.",
|
||||
);
|
||||
|
||||
const { usage } = messages;
|
||||
await calculateCost(usage, interaction.user.username, "mood");
|
||||
} catch (error) {
|
||||
await replyToError(interaction);
|
||||
if (error instanceof Error) {
|
||||
await logger.error("mood command", error);
|
||||
}
|
||||
await interaction.deferReply({ flags: [ MessageFlags.Ephemeral ] });
|
||||
const sub = await isSubscribed(interaction);
|
||||
if (!sub) {
|
||||
return;
|
||||
}
|
||||
|
||||
const prompt = interaction.options.getString("text", true);
|
||||
|
||||
const messages = await ai.messages.create({
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention -- Required key format for SDK.
|
||||
max_tokens: 2000,
|
||||
messages: [ { content: prompt, role: "user" } ],
|
||||
model: "claude-3-5-sonnet-latest",
|
||||
system: `${personality} Your role in this conversation is to analyse the text the user provides for the overall sentiment and mood of the author.`,
|
||||
temperature: 1,
|
||||
});
|
||||
|
||||
const response = messages.content.find((message) => {
|
||||
return message.type === "text";
|
||||
});
|
||||
|
||||
await interaction.editReply(
|
||||
response?.text
|
||||
?? "I'm sorry, I don't have an answer for that. Please try again later.",
|
||||
);
|
||||
};
|
||||
|
@ -6,10 +6,7 @@
|
||||
import { MessageFlags, type ChatInputCommandInteraction } from "discord.js";
|
||||
import { personality } from "../config/personality.js";
|
||||
import { ai } from "../utils/ai.js";
|
||||
import { calculateCost } from "../utils/calculateCost.js";
|
||||
import { isSubscribed } from "../utils/isSubscribed.js";
|
||||
import { logger } from "../utils/logger.js";
|
||||
import { replyToError } from "../utils/replyToError.js";
|
||||
|
||||
/**
|
||||
* Accepts a text snippet from the user. Submits it to Anthropic
|
||||
@ -19,39 +16,29 @@ import { replyToError } from "../utils/replyToError.js";
|
||||
export const proofread = async(
|
||||
interaction: ChatInputCommandInteraction,
|
||||
): Promise<void> => {
|
||||
try {
|
||||
await interaction.deferReply({ flags: [ MessageFlags.Ephemeral ] });
|
||||
const sub = await isSubscribed(interaction);
|
||||
if (!sub) {
|
||||
return;
|
||||
}
|
||||
|
||||
const prompt = interaction.options.getString("text", true);
|
||||
|
||||
const messages = await ai.messages.create({
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention -- Required key format for SDK.
|
||||
max_tokens: 2000,
|
||||
messages: [ { content: prompt, role: "user" } ],
|
||||
model: "claude-3-5-sonnet-latest",
|
||||
system: `${personality} Your role in this conversation is to proofread the text the user has provided. You should identify spelling and grammatical errors using British English.`,
|
||||
temperature: 1,
|
||||
});
|
||||
|
||||
const response = messages.content.find((message) => {
|
||||
return message.type === "text";
|
||||
});
|
||||
|
||||
await interaction.editReply(
|
||||
response?.text
|
||||
?? "I'm sorry, I don't have an answer for that. Please try again later.",
|
||||
);
|
||||
|
||||
const { usage } = messages;
|
||||
await calculateCost(usage, interaction.user.username, "proofread");
|
||||
} catch (error) {
|
||||
await replyToError(interaction);
|
||||
if (error instanceof Error) {
|
||||
await logger.error("proofread command", error);
|
||||
}
|
||||
await interaction.deferReply({ flags: [ MessageFlags.Ephemeral ] });
|
||||
const sub = await isSubscribed(interaction);
|
||||
if (!sub) {
|
||||
return;
|
||||
}
|
||||
|
||||
const prompt = interaction.options.getString("text", true);
|
||||
|
||||
const messages = await ai.messages.create({
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention -- Required key format for SDK.
|
||||
max_tokens: 2000,
|
||||
messages: [ { content: prompt, role: "user" } ],
|
||||
model: "claude-3-5-sonnet-latest",
|
||||
system: `${personality} Your role in this conversation is to proofread the text the user has provided. You should identify spelling and grammatical errors using British English.`,
|
||||
temperature: 1,
|
||||
});
|
||||
|
||||
const response = messages.content.find((message) => {
|
||||
return message.type === "text";
|
||||
});
|
||||
|
||||
await interaction.editReply(
|
||||
response?.text
|
||||
?? "I'm sorry, I don't have an answer for that. Please try again later.",
|
||||
);
|
||||
};
|
||||
|
@ -6,10 +6,7 @@
|
||||
import { MessageFlags, type ChatInputCommandInteraction } from "discord.js";
|
||||
import { personality } from "../config/personality.js";
|
||||
import { ai } from "../utils/ai.js";
|
||||
import { calculateCost } from "../utils/calculateCost.js";
|
||||
import { isSubscribed } from "../utils/isSubscribed.js";
|
||||
import { logger } from "../utils/logger.js";
|
||||
import { replyToError } from "../utils/replyToError.js";
|
||||
|
||||
/**
|
||||
* Accepts an arbitrary question from the user, then sends it to Anthropic
|
||||
@ -19,39 +16,29 @@ import { replyToError } from "../utils/replyToError.js";
|
||||
export const query = async(
|
||||
interaction: ChatInputCommandInteraction,
|
||||
): Promise<void> => {
|
||||
try {
|
||||
await interaction.deferReply({ flags: [ MessageFlags.Ephemeral ] });
|
||||
const sub = await isSubscribed(interaction);
|
||||
if (!sub) {
|
||||
return;
|
||||
}
|
||||
|
||||
const prompt = interaction.options.getString("prompt", true);
|
||||
|
||||
const messages = await ai.messages.create({
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention -- Required key format for SDK.
|
||||
max_tokens: 2000,
|
||||
messages: [ { content: prompt, role: "user" } ],
|
||||
model: "claude-3-5-sonnet-latest",
|
||||
system: `${personality} Your role in this conversation is to answer the user's question to the best of your abilities. When possible, include links to relevant sources.`,
|
||||
temperature: 1,
|
||||
});
|
||||
|
||||
const response = messages.content.find((message) => {
|
||||
return message.type === "text";
|
||||
});
|
||||
|
||||
await interaction.editReply(
|
||||
response?.text
|
||||
?? "I'm sorry, I don't have an answer for that. Please try again later.",
|
||||
);
|
||||
|
||||
const { usage } = messages;
|
||||
await calculateCost(usage, interaction.user.username, "query");
|
||||
} catch (error) {
|
||||
await replyToError(interaction);
|
||||
if (error instanceof Error) {
|
||||
await logger.error("query command", error);
|
||||
}
|
||||
await interaction.deferReply({ flags: [ MessageFlags.Ephemeral ] });
|
||||
const sub = await isSubscribed(interaction);
|
||||
if (!sub) {
|
||||
return;
|
||||
}
|
||||
|
||||
const prompt = interaction.options.getString("prompt", true);
|
||||
|
||||
const messages = await ai.messages.create({
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention -- Required key format for SDK.
|
||||
max_tokens: 2000,
|
||||
messages: [ { content: prompt, role: "user" } ],
|
||||
model: "claude-3-5-sonnet-latest",
|
||||
system: `${personality} Your role in this conversation is to answer the user's question to the best of your abilities. When possible, include links to relevant sources.`,
|
||||
temperature: 1,
|
||||
});
|
||||
|
||||
const response = messages.content.find((message) => {
|
||||
return message.type === "text";
|
||||
});
|
||||
|
||||
await interaction.editReply(
|
||||
response?.text
|
||||
?? "I'm sorry, I don't have an answer for that. Please try again later.",
|
||||
);
|
||||
};
|
||||
|
@ -6,10 +6,7 @@
|
||||
import { MessageFlags, type ChatInputCommandInteraction } from "discord.js";
|
||||
import { personality } from "../config/personality.js";
|
||||
import { ai } from "../utils/ai.js";
|
||||
import { calculateCost } from "../utils/calculateCost.js";
|
||||
import { isSubscribed } from "../utils/isSubscribed.js";
|
||||
import { logger } from "../utils/logger.js";
|
||||
import { replyToError } from "../utils/replyToError.js";
|
||||
|
||||
/**
|
||||
* Accepts a text snippet from the user. Submits it to Anthropic
|
||||
@ -19,39 +16,29 @@ import { replyToError } from "../utils/replyToError.js";
|
||||
export const summarise = async(
|
||||
interaction: ChatInputCommandInteraction,
|
||||
): Promise<void> => {
|
||||
try {
|
||||
await interaction.deferReply({ flags: [ MessageFlags.Ephemeral ] });
|
||||
const sub = await isSubscribed(interaction);
|
||||
if (!sub) {
|
||||
return;
|
||||
}
|
||||
|
||||
const prompt = interaction.options.getString("text", true);
|
||||
|
||||
const messages = await ai.messages.create({
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention -- Required key format for SDK.
|
||||
max_tokens: 2000,
|
||||
messages: [ { content: prompt, role: "user" } ],
|
||||
model: "claude-3-5-sonnet-latest",
|
||||
system: `${personality} Your role in this conversation is to summarise the text the user has provided. Your goal is to reach 250 words or less. Wrap ONLY THE SUMMARY in multi-line code block so it is easy to copy.`,
|
||||
temperature: 1,
|
||||
});
|
||||
|
||||
const response = messages.content.find((message) => {
|
||||
return message.type === "text";
|
||||
});
|
||||
|
||||
await interaction.editReply(
|
||||
response?.text
|
||||
?? "I'm sorry, I don't have an answer for that. Please try again later.",
|
||||
);
|
||||
|
||||
const { usage } = messages;
|
||||
await calculateCost(usage, interaction.user.username, "summarise");
|
||||
} catch (error) {
|
||||
await replyToError(interaction);
|
||||
if (error instanceof Error) {
|
||||
await logger.error("summarise command", error);
|
||||
}
|
||||
await interaction.deferReply({ flags: [ MessageFlags.Ephemeral ] });
|
||||
const sub = await isSubscribed(interaction);
|
||||
if (!sub) {
|
||||
return;
|
||||
}
|
||||
|
||||
const prompt = interaction.options.getString("text", true);
|
||||
|
||||
const messages = await ai.messages.create({
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention -- Required key format for SDK.
|
||||
max_tokens: 2000,
|
||||
messages: [ { content: prompt, role: "user" } ],
|
||||
model: "claude-3-5-sonnet-latest",
|
||||
system: `${personality} Your role in this conversation is to summarise the text the user has provided. Your goal is to reach 250 words or less. Wrap ONLY THE SUMMARY in multi-line code block so it is easy to copy.`,
|
||||
temperature: 1,
|
||||
});
|
||||
|
||||
const response = messages.content.find((message) => {
|
||||
return message.type === "text";
|
||||
});
|
||||
|
||||
await interaction.editReply(
|
||||
response?.text
|
||||
?? "I'm sorry, I don't have an answer for that. Please try again later.",
|
||||
);
|
||||
};
|
||||
|
@ -5,27 +5,27 @@
|
||||
*/
|
||||
|
||||
import fastify from "fastify";
|
||||
import { logger } from "../utils/logger.js";
|
||||
import { logHandler } from "../utils/logHandler.js";
|
||||
|
||||
const html = `<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Cordelia Taryne</title>
|
||||
<title>Aria Iuvo</title>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="description" content="AI-powered multi-purpose assistant for Discord!" />
|
||||
<meta name="description" content="Bot to translate your messages on Discord!" />
|
||||
<script src="https://cdn.nhcarrigan.com/headers/index.js" async defer></script>
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<h1>Cordelia Taryne</h1>
|
||||
<h1>Aria Iuvo</h1>
|
||||
<section>
|
||||
<p>AI-powered multi-purpose assistant for Discord!</p>
|
||||
<p>Bot to translate your messages on Discord!</p>
|
||||
</section>
|
||||
<section>
|
||||
<h2>Links</h2>
|
||||
<p>
|
||||
<a href="https://git.nhcarrigan.com/nhcarrigan/cordelia-taryne">
|
||||
<a href="https://git.nhcarrigan.com/nhcarrigan/aria-iuvo">
|
||||
<i class="fa-solid fa-code"></i> Source Code
|
||||
</a>
|
||||
</p>
|
||||
@ -60,16 +60,12 @@ export const instantiateServer = (): void => {
|
||||
|
||||
server.listen({ port: 5002 }, (error) => {
|
||||
if (error) {
|
||||
void logger.error("instantiate server", error);
|
||||
logHandler.error(error);
|
||||
return;
|
||||
}
|
||||
void logger.log("debug", "Server listening on port 5002.");
|
||||
logHandler.info("Server listening on port 5002.");
|
||||
});
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
void logger.error("instantiate server", error);
|
||||
return;
|
||||
}
|
||||
void logger.error("instantiate server", new Error("Unknown error"));
|
||||
logHandler.error(error);
|
||||
}
|
||||
};
|
||||
|
@ -1,30 +0,0 @@
|
||||
/**
|
||||
* @copyright nhcarrigan
|
||||
* @license Naomi's Public License
|
||||
* @author Naomi Carrigan
|
||||
*/
|
||||
import { logger } from "./logger.js";
|
||||
import type { Usage } from "@anthropic-ai/sdk/resources/index.js";
|
||||
|
||||
/**
|
||||
* Calculates the cost of a command run by a user, and sends to
|
||||
* our logging service.
|
||||
* @param usage -- The usage payload from Anthropic.
|
||||
* @param uuid -- The Discord ID of the user who ran the command.
|
||||
* @param command -- The command that was run.
|
||||
*/
|
||||
export const calculateCost = async(
|
||||
usage: Usage,
|
||||
uuid: string,
|
||||
command: string,
|
||||
): Promise<void> => {
|
||||
const inputCost = usage.input_tokens * (3 / 1_000_000);
|
||||
const outputCost = usage.output_tokens * (15 / 1_000_000);
|
||||
const totalCost = inputCost + outputCost;
|
||||
await logger.log(
|
||||
"info",
|
||||
`User ${uuid} ran \`${command}\` which accepted ${usage.input_tokens.toString()} and generated ${usage.output_tokens.toString()}.
|
||||
|
||||
Total cost: ${totalCost.toLocaleString("en-GB", { currency: "USD", style: "currency" })}`,
|
||||
);
|
||||
};
|
31
src/utils/logHandler.ts
Normal file
31
src/utils/logHandler.ts
Normal file
@ -0,0 +1,31 @@
|
||||
/**
|
||||
* @copyright nhcarrigan
|
||||
* @license Naomi's Public License
|
||||
* @author Naomi Carrigan
|
||||
*/
|
||||
import { createLogger, format, transports, config } from "winston";
|
||||
|
||||
const { combine, timestamp, colorize, printf } = format;
|
||||
|
||||
/**
|
||||
* Standard log handler, using winston to wrap and format
|
||||
* messages. Call with `logHandler.log(level, message)`.
|
||||
* @param {string} level - The log level to use.
|
||||
* @param {string} message - The message to log.
|
||||
*/
|
||||
export const logHandler = createLogger({
|
||||
exitOnError: false,
|
||||
format: combine(
|
||||
timestamp({
|
||||
format: "YYYY-MM-DD HH:mm:ss",
|
||||
}),
|
||||
colorize(),
|
||||
printf((info) => {
|
||||
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions -- Winston properties...
|
||||
return `${info.level}: ${info.timestamp}: ${info.message}`;
|
||||
}),
|
||||
),
|
||||
level: "silly",
|
||||
levels: config.npm.levels,
|
||||
transports: [ new transports.Console() ],
|
||||
});
|
@ -1,12 +0,0 @@
|
||||
/**
|
||||
* @copyright nhcarrigan
|
||||
* @license Naomi's Public License
|
||||
* @author Naomi Carrigan
|
||||
*/
|
||||
|
||||
import { Logger } from "@nhcarrigan/logger";
|
||||
|
||||
export const logger = new Logger(
|
||||
"Cordelia Taryne",
|
||||
process.env.LOG_TOKEN ?? "",
|
||||
);
|
@ -1,38 +0,0 @@
|
||||
/**
|
||||
* @copyright nhcarrigan
|
||||
* @license Naomi's Public License
|
||||
* @author Naomi Carrigan
|
||||
*/
|
||||
import {
|
||||
ActionRowBuilder,
|
||||
ButtonBuilder,
|
||||
ButtonStyle,
|
||||
type ChatInputCommandInteraction,
|
||||
type MessageContextMenuCommandInteraction,
|
||||
} from "discord.js";
|
||||
|
||||
/**
|
||||
* Responds to an interaction with a generic error message.
|
||||
* @param interaction -- The interaction payload from Discord.
|
||||
*/
|
||||
export const replyToError = async(
|
||||
interaction:
|
||||
| ChatInputCommandInteraction
|
||||
| MessageContextMenuCommandInteraction,
|
||||
): Promise<void> => {
|
||||
const button = new ButtonBuilder().setLabel("Need help?").
|
||||
setStyle(ButtonStyle.Link).
|
||||
setURL("https://chat.nhcarrigan.com");
|
||||
const row = new ActionRowBuilder<ButtonBuilder>().addComponents(button);
|
||||
if (interaction.deferred || interaction.replied) {
|
||||
await interaction.editReply({
|
||||
components: [ row ],
|
||||
content: "An error occurred while running this command.",
|
||||
});
|
||||
return;
|
||||
}
|
||||
await interaction.reply({
|
||||
components: [ row ],
|
||||
content: "An error occurred while running this command.",
|
||||
});
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user