feat(#170): Implement mosaic-bridge module for Discord
Created the mosaic-bridge module to enable Discord integration for chat-based control of Mosaic Stack. This module provides the foundation for receiving commands via Discord and forwarding them to the stitcher for job orchestration. Key Features: - Discord bot connection and authentication - Command parsing (@mosaic fix, status, cancel, verbose, quiet, help) - Thread management for job updates - Chat provider interface for future platform extensibility - Noise management (low/medium/high verbosity levels) Implementation Details: - Created IChatProvider interface for platform abstraction - Implemented DiscordService with Discord.js - Basic command parsing (detailed parsing in #171) - Thread creation for job-specific updates - Configuration via environment variables Commands Supported: - @mosaic fix <issue> - Start job for issue - @mosaic status <job> - Get job status (placeholder) - @mosaic cancel <job> - Cancel running job (placeholder) - @mosaic verbose <job> - Stream full logs (placeholder) - @mosaic quiet - Reduce notifications (placeholder) - @mosaic help - Show available commands Testing: - 23/23 tests passing (TDD approach) - Unit tests for Discord service - Module integration tests - 100% coverage of critical paths Quality Gates: - Typecheck: PASSED - Lint: PASSED - Build: PASSED - Tests: PASSED (23/23) Environment Variables: - DISCORD_BOT_TOKEN - Bot authentication token - DISCORD_GUILD_ID - Server/Guild ID (optional) - DISCORD_CONTROL_CHANNEL_ID - Channel for commands Files Created: - apps/api/src/bridge/bridge.module.ts - apps/api/src/bridge/discord/discord.service.ts - apps/api/src/bridge/interfaces/chat-provider.interface.ts - apps/api/src/bridge/index.ts - Full test coverage Dependencies Added: - discord.js@latest Next Steps: - Issue #171: Implement detailed command parsing - Issue #172: Add Herald integration for job updates - Future: Add Slack, Matrix support via IChatProvider Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
163
pnpm-lock.yaml
generated
163
pnpm-lock.yaml
generated
@@ -129,6 +129,9 @@ importers:
|
||||
class-validator:
|
||||
specifier: ^0.14.3
|
||||
version: 0.14.3
|
||||
discord.js:
|
||||
specifier: ^14.25.1
|
||||
version: 14.25.1
|
||||
gray-matter:
|
||||
specifier: ^4.0.3
|
||||
version: 4.0.3
|
||||
@@ -729,6 +732,34 @@ packages:
|
||||
resolution: {integrity: sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
'@discordjs/builders@1.13.1':
|
||||
resolution: {integrity: sha512-cOU0UDHc3lp/5nKByDxkmRiNZBpdp0kx55aarbiAfakfKJHlxv/yFW1zmIqCAmwH5CRlrH9iMFKJMpvW4DPB+w==}
|
||||
engines: {node: '>=16.11.0'}
|
||||
|
||||
'@discordjs/collection@1.5.3':
|
||||
resolution: {integrity: sha512-SVb428OMd3WO1paV3rm6tSjM4wC+Kecaa1EUGX7vc6/fddvw/6lg90z4QtCqm21zvVe92vMMDt9+DkIvjXImQQ==}
|
||||
engines: {node: '>=16.11.0'}
|
||||
|
||||
'@discordjs/collection@2.1.1':
|
||||
resolution: {integrity: sha512-LiSusze9Tc7qF03sLCujF5iZp7K+vRNEDBZ86FT9aQAv3vxMLihUvKvpsCWiQ2DJq1tVckopKm1rxomgNUc9hg==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
'@discordjs/formatters@0.6.2':
|
||||
resolution: {integrity: sha512-y4UPwWhH6vChKRkGdMB4odasUbHOUwy7KL+OVwF86PvT6QVOwElx+TiI1/6kcmcEe+g5YRXJFiXSXUdabqZOvQ==}
|
||||
engines: {node: '>=16.11.0'}
|
||||
|
||||
'@discordjs/rest@2.6.0':
|
||||
resolution: {integrity: sha512-RDYrhmpB7mTvmCKcpj+pc5k7POKszS4E2O9TYc+U+Y4iaCP+r910QdO43qmpOja8LRr1RJ0b3U+CqVsnPqzf4w==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
'@discordjs/util@1.2.0':
|
||||
resolution: {integrity: sha512-3LKP7F2+atl9vJFhaBjn4nOaSWahZ/yWjOvA4e5pnXkt2qyXRCHLxoBQy81GFtLGCq7K9lPm9R517M1U+/90Qg==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
'@discordjs/ws@1.2.3':
|
||||
resolution: {integrity: sha512-wPlQDxEmlDg5IxhJPuxXr3Vy9AjYq5xCvFWGJyD7w7Np8ZGu+Mc+97LCoEc/+AYCo2IDpKioiH0/c/mj5ZR9Uw==}
|
||||
engines: {node: '>=16.11.0'}
|
||||
|
||||
'@dnd-kit/accessibility@3.1.1':
|
||||
resolution: {integrity: sha512-2P+YgaXF+gRsIihwwY1gCsQSYnu9Zyj2py8kY5fFvUM1qm2WA2u639R6YNVfU4GWr+ZM5mqEsfHZZLoRONbemw==}
|
||||
peerDependencies:
|
||||
@@ -2318,6 +2349,18 @@ packages:
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@sapphire/async-queue@1.5.5':
|
||||
resolution: {integrity: sha512-cvGzxbba6sav2zZkH8GPf2oGk9yYoD5qrNWdu9fRehifgnFZJMV+nuy2nON2roRO4yQQ+v7MK/Pktl/HgfsUXg==}
|
||||
engines: {node: '>=v14.0.0', npm: '>=7.0.0'}
|
||||
|
||||
'@sapphire/shapeshift@4.0.0':
|
||||
resolution: {integrity: sha512-d9dUmWVA7MMiKobL3VpLF8P2aeanRTu6ypG2OIaEv/ZHH/SUQ2iHOVyi5wAPjQ+HmnMuL0whK9ez8I/raWbtIg==}
|
||||
engines: {node: '>=v16'}
|
||||
|
||||
'@sapphire/snowflake@3.5.3':
|
||||
resolution: {integrity: sha512-jjmJywLAFoWeBi1W7994zZyiNWPIiqRRNAmSERxyg93xRGzNYvGjlZ0gR6x0F4gPRi2+0O6S71kOZYyr3cxaIQ==}
|
||||
engines: {node: '>=v14.0.0', npm: '>=7.0.0'}
|
||||
|
||||
'@socket.io/component-emitter@3.1.2':
|
||||
resolution: {integrity: sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==}
|
||||
|
||||
@@ -2676,6 +2719,9 @@ packages:
|
||||
'@types/validator@13.15.10':
|
||||
resolution: {integrity: sha512-T8L6i7wCuyoK8A/ZeLYt1+q0ty3Zb9+qbSSvrIVitzT3YjZqkTZ40IbRsPanlB4h1QB3JVL1SYCdR6ngtFYcuA==}
|
||||
|
||||
'@types/ws@8.18.1':
|
||||
resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==}
|
||||
|
||||
'@typescript-eslint/eslint-plugin@8.54.0':
|
||||
resolution: {integrity: sha512-hAAP5io/7csFStuOmR782YmTthKBJ9ND3WVL60hcOjvtGFb+HJxH4O5huAcmcZ9v9G8P+JETiZ/G1B8MALnWZQ==}
|
||||
engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0}
|
||||
@@ -2817,6 +2863,10 @@ packages:
|
||||
'@vitest/utils@4.0.18':
|
||||
resolution: {integrity: sha512-msMRKLMVLWygpK3u2Hybgi4MNjcYJvwTb0Ru09+fOyCXIgT5raYP041DRRdiJiI3k/2U6SEbAETB3YtBrUkCFA==}
|
||||
|
||||
'@vladfrangu/async_event_emitter@2.4.7':
|
||||
resolution: {integrity: sha512-Xfe6rpCTxSxfbswi/W/Pz7zp1WWSNn4A0eW4mLkQUewCrXXtMj31lCg+iQyTkh/CkusZSq9eDflu7tjEDXUY6g==}
|
||||
engines: {node: '>=v14.0.0', npm: '>=7.0.0'}
|
||||
|
||||
'@webassemblyjs/ast@1.14.1':
|
||||
resolution: {integrity: sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==}
|
||||
|
||||
@@ -3691,6 +3741,13 @@ packages:
|
||||
resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
discord-api-types@0.38.38:
|
||||
resolution: {integrity: sha512-7qcM5IeZrfb+LXW07HvoI5L+j4PQeMZXEkSm1htHAHh4Y9JSMXBWjy/r7zmUCOj4F7zNjMcm7IMWr131MT2h0Q==}
|
||||
|
||||
discord.js@14.25.1:
|
||||
resolution: {integrity: sha512-2l0gsPOLPs5t6GFZfQZKnL1OJNYFcuC/ETWsW4VtKVD/tg4ICa9x+jb9bkPffkMdRpRpuUaO/fKkHCBeiCKh8g==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
dom-accessibility-api@0.5.16:
|
||||
resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==}
|
||||
|
||||
@@ -4582,6 +4639,9 @@ packages:
|
||||
lodash.merge@4.6.2:
|
||||
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
|
||||
|
||||
lodash.snakecase@4.1.1:
|
||||
resolution: {integrity: sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==}
|
||||
|
||||
lodash@4.17.21:
|
||||
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
|
||||
|
||||
@@ -4629,6 +4689,9 @@ packages:
|
||||
resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==}
|
||||
hasBin: true
|
||||
|
||||
magic-bytes.js@1.13.0:
|
||||
resolution: {integrity: sha512-afO2mnxW7GDTXMm5/AoN1WuOcdoKhtgXjIvHmobqTD1grNplhGdv3PFOyjCVmrnOZBIT/gD/koDKpYG+0mvHcg==}
|
||||
|
||||
magic-string@0.30.17:
|
||||
resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==}
|
||||
|
||||
@@ -5729,6 +5792,9 @@ packages:
|
||||
resolution: {integrity: sha512-q5W7tVM71e2xjHZTlgfTDoPF/SmqKG5hddq9SzR49CH2hayqRKJtQ4mtRlSxKaJlR/+9rEM+mnBHf7I2/BQcpQ==}
|
||||
engines: {node: '>=6.10'}
|
||||
|
||||
ts-mixer@6.0.4:
|
||||
resolution: {integrity: sha512-ufKpbmrugz5Aou4wcr5Wc1UUFWOLhq+Fm6qa6P0w0K5Qw2yhaUoiWszhCVuNQyNwrlGiscHOmqYoAox1PtvgjA==}
|
||||
|
||||
tsconfig-paths-webpack-plugin@4.2.0:
|
||||
resolution: {integrity: sha512-zbem3rfRS8BgeNK50Zz5SIQgXzLafiHjOwUAvk/38/o1jHn/V5QAgVUcz884or7WYcPaH3N2CIfUc2u0ul7UcA==}
|
||||
engines: {node: '>=10.13.0'}
|
||||
@@ -5823,6 +5889,10 @@ packages:
|
||||
undici-types@6.21.0:
|
||||
resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
|
||||
|
||||
undici@6.21.3:
|
||||
resolution: {integrity: sha512-gBLkYIlEnSp8pFbT64yFgGE6UIB9tAkhukC23PmMDCe5Nd+cRqKxSjw5y54MK2AZMgZfJWMaNE4nYUHgi1XEOw==}
|
||||
engines: {node: '>=18.17'}
|
||||
|
||||
universalify@2.0.1:
|
||||
resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
@@ -6684,6 +6754,55 @@ snapshots:
|
||||
|
||||
'@csstools/css-tokenizer@3.0.4': {}
|
||||
|
||||
'@discordjs/builders@1.13.1':
|
||||
dependencies:
|
||||
'@discordjs/formatters': 0.6.2
|
||||
'@discordjs/util': 1.2.0
|
||||
'@sapphire/shapeshift': 4.0.0
|
||||
discord-api-types: 0.38.38
|
||||
fast-deep-equal: 3.1.3
|
||||
ts-mixer: 6.0.4
|
||||
tslib: 2.8.1
|
||||
|
||||
'@discordjs/collection@1.5.3': {}
|
||||
|
||||
'@discordjs/collection@2.1.1': {}
|
||||
|
||||
'@discordjs/formatters@0.6.2':
|
||||
dependencies:
|
||||
discord-api-types: 0.38.38
|
||||
|
||||
'@discordjs/rest@2.6.0':
|
||||
dependencies:
|
||||
'@discordjs/collection': 2.1.1
|
||||
'@discordjs/util': 1.2.0
|
||||
'@sapphire/async-queue': 1.5.5
|
||||
'@sapphire/snowflake': 3.5.3
|
||||
'@vladfrangu/async_event_emitter': 2.4.7
|
||||
discord-api-types: 0.38.38
|
||||
magic-bytes.js: 1.13.0
|
||||
tslib: 2.8.1
|
||||
undici: 6.21.3
|
||||
|
||||
'@discordjs/util@1.2.0':
|
||||
dependencies:
|
||||
discord-api-types: 0.38.38
|
||||
|
||||
'@discordjs/ws@1.2.3':
|
||||
dependencies:
|
||||
'@discordjs/collection': 2.1.1
|
||||
'@discordjs/rest': 2.6.0
|
||||
'@discordjs/util': 1.2.0
|
||||
'@sapphire/async-queue': 1.5.5
|
||||
'@types/ws': 8.18.1
|
||||
'@vladfrangu/async_event_emitter': 2.4.7
|
||||
discord-api-types: 0.38.38
|
||||
tslib: 2.8.1
|
||||
ws: 8.19.0
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
- utf-8-validate
|
||||
|
||||
'@dnd-kit/accessibility@3.1.1(react@19.2.4)':
|
||||
dependencies:
|
||||
react: 19.2.4
|
||||
@@ -8358,6 +8477,15 @@ snapshots:
|
||||
'@rollup/rollup-win32-x64-msvc@4.57.0':
|
||||
optional: true
|
||||
|
||||
'@sapphire/async-queue@1.5.5': {}
|
||||
|
||||
'@sapphire/shapeshift@4.0.0':
|
||||
dependencies:
|
||||
fast-deep-equal: 3.1.3
|
||||
lodash: 4.17.23
|
||||
|
||||
'@sapphire/snowflake@3.5.3': {}
|
||||
|
||||
'@socket.io/component-emitter@3.1.2': {}
|
||||
|
||||
'@standard-schema/spec@1.1.0': {}
|
||||
@@ -8760,6 +8888,10 @@ snapshots:
|
||||
|
||||
'@types/validator@13.15.10': {}
|
||||
|
||||
'@types/ws@8.18.1':
|
||||
dependencies:
|
||||
'@types/node': 22.19.7
|
||||
|
||||
'@typescript-eslint/eslint-plugin@8.54.0(@typescript-eslint/parser@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)':
|
||||
dependencies:
|
||||
'@eslint-community/regexpp': 4.12.2
|
||||
@@ -8991,6 +9123,8 @@ snapshots:
|
||||
'@vitest/pretty-format': 4.0.18
|
||||
tinyrainbow: 3.0.3
|
||||
|
||||
'@vladfrangu/async_event_emitter@2.4.7': {}
|
||||
|
||||
'@webassemblyjs/ast@1.14.1':
|
||||
dependencies:
|
||||
'@webassemblyjs/helper-numbers': 1.13.2
|
||||
@@ -9922,6 +10056,27 @@ snapshots:
|
||||
|
||||
detect-libc@2.1.2: {}
|
||||
|
||||
discord-api-types@0.38.38: {}
|
||||
|
||||
discord.js@14.25.1:
|
||||
dependencies:
|
||||
'@discordjs/builders': 1.13.1
|
||||
'@discordjs/collection': 1.5.3
|
||||
'@discordjs/formatters': 0.6.2
|
||||
'@discordjs/rest': 2.6.0
|
||||
'@discordjs/util': 1.2.0
|
||||
'@discordjs/ws': 1.2.3
|
||||
'@sapphire/snowflake': 3.5.3
|
||||
discord-api-types: 0.38.38
|
||||
fast-deep-equal: 3.1.3
|
||||
lodash.snakecase: 4.1.1
|
||||
magic-bytes.js: 1.13.0
|
||||
tslib: 2.8.1
|
||||
undici: 6.21.3
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
- utf-8-validate
|
||||
|
||||
dom-accessibility-api@0.5.16: {}
|
||||
|
||||
dom-accessibility-api@0.6.3: {}
|
||||
@@ -10798,6 +10953,8 @@ snapshots:
|
||||
|
||||
lodash.merge@4.6.2: {}
|
||||
|
||||
lodash.snakecase@4.1.1: {}
|
||||
|
||||
lodash@4.17.21: {}
|
||||
|
||||
lodash@4.17.23: {}
|
||||
@@ -10839,6 +10996,8 @@ snapshots:
|
||||
|
||||
lz-string@1.5.0: {}
|
||||
|
||||
magic-bytes.js@1.13.0: {}
|
||||
|
||||
magic-string@0.30.17:
|
||||
dependencies:
|
||||
'@jridgewell/sourcemap-codec': 1.5.5
|
||||
@@ -12034,6 +12193,8 @@ snapshots:
|
||||
|
||||
ts-dedent@2.2.0: {}
|
||||
|
||||
ts-mixer@6.0.4: {}
|
||||
|
||||
tsconfig-paths-webpack-plugin@4.2.0:
|
||||
dependencies:
|
||||
chalk: 4.1.2
|
||||
@@ -12127,6 +12288,8 @@ snapshots:
|
||||
|
||||
undici-types@6.21.0: {}
|
||||
|
||||
undici@6.21.3: {}
|
||||
|
||||
universalify@2.0.1: {}
|
||||
|
||||
unpipe@1.0.0: {}
|
||||
|
||||
Reference in New Issue
Block a user