crewly 1.4.2 → 1.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/config/skills/orchestrator/reply-gchat/execute.sh +4 -4
  2. package/config/templates/dev-fullstack/norms/docker-deploy-cleanup.md +28 -0
  3. package/dist/backend/backend/src/constants.d.ts +45 -14
  4. package/dist/backend/backend/src/constants.d.ts.map +1 -1
  5. package/dist/backend/backend/src/constants.js +45 -14
  6. package/dist/backend/backend/src/constants.js.map +1 -1
  7. package/dist/backend/backend/src/controllers/cloud/cloud.controller.d.ts.map +1 -1
  8. package/dist/backend/backend/src/controllers/cloud/cloud.controller.js +14 -3
  9. package/dist/backend/backend/src/controllers/cloud/cloud.controller.js.map +1 -1
  10. package/dist/backend/backend/src/controllers/cloud/relay.controller.d.ts +15 -3
  11. package/dist/backend/backend/src/controllers/cloud/relay.controller.d.ts.map +1 -1
  12. package/dist/backend/backend/src/controllers/cloud/relay.controller.js +46 -8
  13. package/dist/backend/backend/src/controllers/cloud/relay.controller.js.map +1 -1
  14. package/dist/backend/backend/src/controllers/cloud/relay.routes.d.ts.map +1 -1
  15. package/dist/backend/backend/src/controllers/cloud/relay.routes.js +2 -1
  16. package/dist/backend/backend/src/controllers/cloud/relay.routes.js.map +1 -1
  17. package/dist/backend/backend/src/controllers/messaging/messenger.routes.d.ts.map +1 -1
  18. package/dist/backend/backend/src/controllers/messaging/messenger.routes.js +86 -3
  19. package/dist/backend/backend/src/controllers/messaging/messenger.routes.js.map +1 -1
  20. package/dist/backend/backend/src/index.d.ts +5 -0
  21. package/dist/backend/backend/src/index.d.ts.map +1 -1
  22. package/dist/backend/backend/src/index.js +33 -0
  23. package/dist/backend/backend/src/index.js.map +1 -1
  24. package/dist/backend/backend/src/services/cloud/cloud-client.service.d.ts +27 -0
  25. package/dist/backend/backend/src/services/cloud/cloud-client.service.d.ts.map +1 -1
  26. package/dist/backend/backend/src/services/cloud/cloud-client.service.js +28 -0
  27. package/dist/backend/backend/src/services/cloud/cloud-client.service.js.map +1 -1
  28. package/dist/backend/backend/src/services/cloud/relay-client.service.d.ts +47 -44
  29. package/dist/backend/backend/src/services/cloud/relay-client.service.d.ts.map +1 -1
  30. package/dist/backend/backend/src/services/cloud/relay-client.service.js +185 -152
  31. package/dist/backend/backend/src/services/cloud/relay-client.service.js.map +1 -1
  32. package/dist/backend/backend/src/services/cloud/relay-server.service.d.ts.map +1 -1
  33. package/dist/backend/backend/src/services/cloud/relay-server.service.js +3 -12
  34. package/dist/backend/backend/src/services/cloud/relay-server.service.js.map +1 -1
  35. package/dist/backend/backend/src/services/cloud/relay.types.d.ts +27 -4
  36. package/dist/backend/backend/src/services/cloud/relay.types.d.ts.map +1 -1
  37. package/dist/backend/backend/src/services/cloud/relay.types.js.map +1 -1
  38. package/dist/backend/backend/src/services/messaging/adapters/telegram-messenger.adapter.d.ts +16 -8
  39. package/dist/backend/backend/src/services/messaging/adapters/telegram-messenger.adapter.d.ts.map +1 -1
  40. package/dist/backend/backend/src/services/messaging/adapters/telegram-messenger.adapter.js +30 -35
  41. package/dist/backend/backend/src/services/messaging/adapters/telegram-messenger.adapter.js.map +1 -1
  42. package/dist/backend/backend/src/services/messaging/response-router.service.d.ts +8 -0
  43. package/dist/backend/backend/src/services/messaging/response-router.service.d.ts.map +1 -1
  44. package/dist/backend/backend/src/services/messaging/response-router.service.js +16 -0
  45. package/dist/backend/backend/src/services/messaging/response-router.service.js.map +1 -1
  46. package/dist/backend/backend/src/services/telegram/index.d.ts +14 -0
  47. package/dist/backend/backend/src/services/telegram/index.d.ts.map +1 -0
  48. package/dist/backend/backend/src/services/telegram/index.js +11 -0
  49. package/dist/backend/backend/src/services/telegram/index.js.map +1 -0
  50. package/dist/backend/backend/src/services/telegram/telegram-credentials.service.d.ts +54 -0
  51. package/dist/backend/backend/src/services/telegram/telegram-credentials.service.d.ts.map +1 -0
  52. package/dist/backend/backend/src/services/telegram/telegram-credentials.service.js +98 -0
  53. package/dist/backend/backend/src/services/telegram/telegram-credentials.service.js.map +1 -0
  54. package/dist/backend/backend/src/services/telegram/telegram-initializer.d.ts +76 -0
  55. package/dist/backend/backend/src/services/telegram/telegram-initializer.d.ts.map +1 -0
  56. package/dist/backend/backend/src/services/telegram/telegram-initializer.js +131 -0
  57. package/dist/backend/backend/src/services/telegram/telegram-initializer.js.map +1 -0
  58. package/dist/backend/backend/src/services/telegram/telegram-orchestrator-bridge.d.ts +73 -0
  59. package/dist/backend/backend/src/services/telegram/telegram-orchestrator-bridge.d.ts.map +1 -0
  60. package/dist/backend/backend/src/services/telegram/telegram-orchestrator-bridge.js +172 -0
  61. package/dist/backend/backend/src/services/telegram/telegram-orchestrator-bridge.js.map +1 -0
  62. package/dist/backend/backend/src/services/telegram/telegram-thread-store.service.d.ts +86 -0
  63. package/dist/backend/backend/src/services/telegram/telegram-thread-store.service.d.ts.map +1 -0
  64. package/dist/backend/backend/src/services/telegram/telegram-thread-store.service.js +157 -0
  65. package/dist/backend/backend/src/services/telegram/telegram-thread-store.service.js.map +1 -0
  66. package/dist/backend/backend/src/services/telegram/telegram.service.d.ts +173 -0
  67. package/dist/backend/backend/src/services/telegram/telegram.service.d.ts.map +1 -0
  68. package/dist/backend/backend/src/services/telegram/telegram.service.js +304 -0
  69. package/dist/backend/backend/src/services/telegram/telegram.service.js.map +1 -0
  70. package/dist/cli/backend/src/constants.d.ts +45 -14
  71. package/dist/cli/backend/src/constants.d.ts.map +1 -1
  72. package/dist/cli/backend/src/constants.js +45 -14
  73. package/dist/cli/backend/src/constants.js.map +1 -1
  74. package/dist/cli/cli/src/commands/migrate.d.ts +101 -0
  75. package/dist/cli/cli/src/commands/migrate.d.ts.map +1 -0
  76. package/dist/cli/cli/src/commands/migrate.js +335 -0
  77. package/dist/cli/cli/src/commands/migrate.js.map +1 -0
  78. package/dist/cli/cli/src/index.js +8 -0
  79. package/dist/cli/cli/src/index.js.map +1 -1
  80. package/frontend/dist/assets/{index-f1dc9f80.css → index-2b76b01d.css} +1 -1
  81. package/frontend/dist/assets/{index-c35cdbc5.js → index-83869ca7.js} +321 -321
  82. package/frontend/dist/index.html +2 -2
  83. package/package.json +1 -1
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Telegram Initializer
3
+ *
4
+ * Handles automatic Telegram connection on application startup.
5
+ * Checks for environment variables or saved credentials and initializes
6
+ * the TelegramService + bridge if configured.
7
+ *
8
+ * @module services/telegram/telegram-initializer
9
+ */
10
+ import { TelegramConfig } from './telegram-credentials.service.js';
11
+ import type { MessageQueueService } from '../messaging/message-queue.service.js';
12
+ /**
13
+ * Result of initialization attempt.
14
+ */
15
+ export interface TelegramInitResult {
16
+ /** Whether initialization was attempted */
17
+ attempted: boolean;
18
+ /** Whether initialization succeeded */
19
+ success: boolean;
20
+ /** Error message if failed */
21
+ error?: string;
22
+ }
23
+ /**
24
+ * Check if Telegram is configured via environment variables.
25
+ *
26
+ * @returns True if TELEGRAM_BOT_TOKEN is set
27
+ */
28
+ export declare function isTelegramConfigured(): boolean;
29
+ /**
30
+ * Get Telegram configuration from environment variables.
31
+ *
32
+ * @returns TelegramConfig object or null if not configured
33
+ */
34
+ export declare function getTelegramConfigFromEnv(): TelegramConfig | null;
35
+ /**
36
+ * Get Telegram configuration from environment variables or saved credentials.
37
+ * Environment variables take priority over saved credentials.
38
+ *
39
+ * @returns TelegramConfig object or null if not configured
40
+ */
41
+ export declare function getTelegramConfig(): Promise<TelegramConfig | null>;
42
+ /**
43
+ * Options for Telegram initialization.
44
+ */
45
+ export interface TelegramInitOptions {
46
+ /** Optional MessageQueueService for enqueuing messages to orchestrator */
47
+ messageQueueService?: MessageQueueService;
48
+ }
49
+ /**
50
+ * Initialize Telegram integration if configured via environment variables
51
+ * or saved credentials.
52
+ *
53
+ * This function is designed to be called during application startup.
54
+ * It safely handles cases where Telegram is not configured.
55
+ *
56
+ * @param options - Optional initialization options
57
+ * @returns Result object indicating success or failure
58
+ *
59
+ * @example
60
+ * ```typescript
61
+ * const result = await initializeTelegramIfConfigured({
62
+ * messageQueueService: myQueueService,
63
+ * });
64
+ * if (result.success) {
65
+ * console.log('Telegram connected!');
66
+ * }
67
+ * ```
68
+ */
69
+ export declare function initializeTelegramIfConfigured(options?: TelegramInitOptions): Promise<TelegramInitResult>;
70
+ /**
71
+ * Gracefully shutdown Telegram integration.
72
+ *
73
+ * Call this during application shutdown to disconnect cleanly.
74
+ */
75
+ export declare function shutdownTelegram(): Promise<void>;
76
+ //# sourceMappingURL=telegram-initializer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"telegram-initializer.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/telegram/telegram-initializer.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,EAA2B,cAAc,EAAE,MAAM,mCAAmC,CAAC;AAC5F,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,uCAAuC,CAAC;AAKjF;;GAEG;AACH,MAAM,WAAW,kBAAkB;IAClC,2CAA2C;IAC3C,SAAS,EAAE,OAAO,CAAC;IACnB,uCAAuC;IACvC,OAAO,EAAE,OAAO,CAAC;IACjB,8BAA8B;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,IAAI,OAAO,CAE9C;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,IAAI,cAAc,GAAG,IAAI,CAYhE;AAED;;;;;GAKG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CAqBxE;AAED;;GAEG;AACH,MAAM,WAAW,mBAAmB;IACnC,0EAA0E;IAC1E,mBAAmB,CAAC,EAAE,mBAAmB,CAAC;CAC1C;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,8BAA8B,CACnD,OAAO,CAAC,EAAE,mBAAmB,GAC3B,OAAO,CAAC,kBAAkB,CAAC,CA+B7B;AAED;;;;GAIG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC,CAYtD"}
@@ -0,0 +1,131 @@
1
+ /**
2
+ * Telegram Initializer
3
+ *
4
+ * Handles automatic Telegram connection on application startup.
5
+ * Checks for environment variables or saved credentials and initializes
6
+ * the TelegramService + bridge if configured.
7
+ *
8
+ * @module services/telegram/telegram-initializer
9
+ */
10
+ import { getTelegramService } from './telegram.service.js';
11
+ import { getTelegramOrchestratorBridge } from './telegram-orchestrator-bridge.js';
12
+ import { loadTelegramCredentials } from './telegram-credentials.service.js';
13
+ import { LoggerService } from '../core/logger.service.js';
14
+ const logger = LoggerService.getInstance().createComponentLogger('TelegramInitializer');
15
+ /**
16
+ * Check if Telegram is configured via environment variables.
17
+ *
18
+ * @returns True if TELEGRAM_BOT_TOKEN is set
19
+ */
20
+ export function isTelegramConfigured() {
21
+ return !!process.env.TELEGRAM_BOT_TOKEN;
22
+ }
23
+ /**
24
+ * Get Telegram configuration from environment variables.
25
+ *
26
+ * @returns TelegramConfig object or null if not configured
27
+ */
28
+ export function getTelegramConfigFromEnv() {
29
+ const botToken = process.env.TELEGRAM_BOT_TOKEN;
30
+ if (!botToken) {
31
+ return null;
32
+ }
33
+ return {
34
+ botToken,
35
+ defaultChatId: process.env.TELEGRAM_DEFAULT_CHAT_ID,
36
+ allowedUserIds: process.env.TELEGRAM_ALLOWED_USERS?.split(',').filter(Boolean),
37
+ };
38
+ }
39
+ /**
40
+ * Get Telegram configuration from environment variables or saved credentials.
41
+ * Environment variables take priority over saved credentials.
42
+ *
43
+ * @returns TelegramConfig object or null if not configured
44
+ */
45
+ export async function getTelegramConfig() {
46
+ // Env vars take priority
47
+ const envConfig = getTelegramConfigFromEnv();
48
+ if (envConfig) {
49
+ return envConfig;
50
+ }
51
+ // Fall back to saved credentials
52
+ try {
53
+ const savedConfig = await loadTelegramCredentials();
54
+ if (savedConfig) {
55
+ logger.info('Loaded Telegram credentials from saved config');
56
+ return savedConfig;
57
+ }
58
+ }
59
+ catch (error) {
60
+ logger.warn('Failed to load saved Telegram credentials', {
61
+ error: error instanceof Error ? error.message : String(error),
62
+ });
63
+ }
64
+ return null;
65
+ }
66
+ /**
67
+ * Initialize Telegram integration if configured via environment variables
68
+ * or saved credentials.
69
+ *
70
+ * This function is designed to be called during application startup.
71
+ * It safely handles cases where Telegram is not configured.
72
+ *
73
+ * @param options - Optional initialization options
74
+ * @returns Result object indicating success or failure
75
+ *
76
+ * @example
77
+ * ```typescript
78
+ * const result = await initializeTelegramIfConfigured({
79
+ * messageQueueService: myQueueService,
80
+ * });
81
+ * if (result.success) {
82
+ * console.log('Telegram connected!');
83
+ * }
84
+ * ```
85
+ */
86
+ export async function initializeTelegramIfConfigured(options) {
87
+ const config = await getTelegramConfig();
88
+ if (!config) {
89
+ logger.info('Not configured — skipping initialization');
90
+ return { attempted: false, success: false };
91
+ }
92
+ try {
93
+ const telegramService = getTelegramService();
94
+ await telegramService.initialize(config);
95
+ const bridge = getTelegramOrchestratorBridge();
96
+ // Set the message queue service if provided
97
+ if (options?.messageQueueService) {
98
+ bridge.setMessageQueueService(options.messageQueueService);
99
+ }
100
+ await bridge.initialize();
101
+ // Start polling for incoming messages
102
+ telegramService.startPolling();
103
+ logger.info('Successfully connected and polling started');
104
+ return { attempted: true, success: true };
105
+ }
106
+ catch (error) {
107
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
108
+ logger.error('Failed to initialize', { error: errorMessage });
109
+ return { attempted: true, success: false, error: errorMessage };
110
+ }
111
+ }
112
+ /**
113
+ * Gracefully shutdown Telegram integration.
114
+ *
115
+ * Call this during application shutdown to disconnect cleanly.
116
+ */
117
+ export async function shutdownTelegram() {
118
+ try {
119
+ const telegramService = getTelegramService();
120
+ if (telegramService.isConnected()) {
121
+ await telegramService.disconnect();
122
+ logger.info('Disconnected');
123
+ }
124
+ }
125
+ catch (error) {
126
+ logger.error('Error during shutdown', {
127
+ error: error instanceof Error ? error.message : String(error),
128
+ });
129
+ }
130
+ }
131
+ //# sourceMappingURL=telegram-initializer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"telegram-initializer.js","sourceRoot":"","sources":["../../../../../../backend/src/services/telegram/telegram-initializer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Telegram-Orchestrator Bridge
3
+ *
4
+ * Routes messages between Telegram and the Crewly orchestrator,
5
+ * enabling mobile control of AI teams via Telegram bot.
6
+ *
7
+ * Flow:
8
+ * 1. TelegramService emits 'message' event for each incoming text
9
+ * 2. This bridge enqueues the message to MessageQueueService
10
+ * 3. QueueProcessor delivers it to the orchestrator
11
+ * 4. ResponseRouter calls the telegramResolve callback
12
+ * 5. Bridge sends the response back to the Telegram chat
13
+ *
14
+ * @module services/telegram/telegram-orchestrator-bridge
15
+ */
16
+ import type { MessageQueueService } from '../messaging/message-queue.service.js';
17
+ /**
18
+ * TelegramOrchestratorBridge routes incoming Telegram messages to the
19
+ * orchestrator via the message queue, and sends responses back.
20
+ *
21
+ * @example
22
+ * ```typescript
23
+ * const bridge = getTelegramOrchestratorBridge();
24
+ * bridge.setMessageQueueService(queueService);
25
+ * await bridge.initialize();
26
+ * ```
27
+ */
28
+ export declare class TelegramOrchestratorBridge {
29
+ private logger;
30
+ private telegramService;
31
+ private messageQueueService;
32
+ private threadStore;
33
+ private initialized;
34
+ constructor();
35
+ /**
36
+ * Set the MessageQueueService for enqueuing incoming messages.
37
+ *
38
+ * @param service - The MessageQueueService instance
39
+ */
40
+ setMessageQueueService(service: MessageQueueService): void;
41
+ /**
42
+ * Initialize the bridge by subscribing to TelegramService events.
43
+ * Must be called after TelegramService.initialize() and startPolling().
44
+ */
45
+ initialize(): Promise<void>;
46
+ /**
47
+ * Handle an incoming Telegram message by enqueuing it for the orchestrator.
48
+ *
49
+ * @param msg - The incoming Telegram message
50
+ */
51
+ private handleIncomingMessage;
52
+ /**
53
+ * Enqueue a Telegram message into the message queue with a resolve callback.
54
+ *
55
+ * @param msg - The incoming message to enqueue
56
+ */
57
+ private enqueueMessage;
58
+ /**
59
+ * Clean up the bridge by removing event listeners.
60
+ */
61
+ destroy(): void;
62
+ }
63
+ /**
64
+ * Get the TelegramOrchestratorBridge singleton.
65
+ *
66
+ * @returns The bridge instance
67
+ */
68
+ export declare function getTelegramOrchestratorBridge(): TelegramOrchestratorBridge;
69
+ /**
70
+ * Reset the TelegramOrchestratorBridge singleton (for testing).
71
+ */
72
+ export declare function resetTelegramOrchestratorBridge(): void;
73
+ //# sourceMappingURL=telegram-orchestrator-bridge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"telegram-orchestrator-bridge.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/telegram/telegram-orchestrator-bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AASH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,uCAAuC,CAAC;AAKjF;;;;;;;;;;GAUG;AACH,qBAAa,0BAA0B;IACtC,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,eAAe,CAAkB;IACzC,OAAO,CAAC,mBAAmB,CAAoC;IAC/D,OAAO,CAAC,WAAW,CAA6B;IAChD,OAAO,CAAC,WAAW,CAAS;;IAS5B;;;;OAIG;IACH,sBAAsB,CAAC,OAAO,EAAE,mBAAmB,GAAG,IAAI;IAI1D;;;OAGG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAmBjC;;;;OAIG;YACW,qBAAqB;IA4BnC;;;;OAIG;YACW,cAAc;IAsD5B;;OAEG;IACH,OAAO,IAAI,IAAI;CAKf;AAKD;;;;GAIG;AACH,wBAAgB,6BAA6B,IAAI,0BAA0B,CAK1E;AAED;;GAEG;AACH,wBAAgB,+BAA+B,IAAI,IAAI,CAKtD"}
@@ -0,0 +1,172 @@
1
+ /**
2
+ * Telegram-Orchestrator Bridge
3
+ *
4
+ * Routes messages between Telegram and the Crewly orchestrator,
5
+ * enabling mobile control of AI teams via Telegram bot.
6
+ *
7
+ * Flow:
8
+ * 1. TelegramService emits 'message' event for each incoming text
9
+ * 2. This bridge enqueues the message to MessageQueueService
10
+ * 3. QueueProcessor delivers it to the orchestrator
11
+ * 4. ResponseRouter calls the telegramResolve callback
12
+ * 5. Bridge sends the response back to the Telegram chat
13
+ *
14
+ * @module services/telegram/telegram-orchestrator-bridge
15
+ */
16
+ import { getTelegramService } from './telegram.service.js';
17
+ import { setTelegramThreadStore, TelegramThreadStoreService, } from './telegram-thread-store.service.js';
18
+ import { isOrchestratorActive, getOrchestratorOfflineMessage } from '../orchestrator/index.js';
19
+ import { TELEGRAM_CONSTANTS, MESSAGE_QUEUE_CONSTANTS } from '../../constants.js';
20
+ import { LoggerService } from '../core/logger.service.js';
21
+ import { formatError } from '../../utils/format-error.js';
22
+ /**
23
+ * TelegramOrchestratorBridge routes incoming Telegram messages to the
24
+ * orchestrator via the message queue, and sends responses back.
25
+ *
26
+ * @example
27
+ * ```typescript
28
+ * const bridge = getTelegramOrchestratorBridge();
29
+ * bridge.setMessageQueueService(queueService);
30
+ * await bridge.initialize();
31
+ * ```
32
+ */
33
+ export class TelegramOrchestratorBridge {
34
+ logger;
35
+ telegramService;
36
+ messageQueueService = null;
37
+ threadStore;
38
+ initialized = false;
39
+ constructor() {
40
+ this.logger = LoggerService.getInstance().createComponentLogger('TelegramBridge');
41
+ this.telegramService = getTelegramService();
42
+ this.threadStore = new TelegramThreadStoreService();
43
+ setTelegramThreadStore(this.threadStore);
44
+ }
45
+ /**
46
+ * Set the MessageQueueService for enqueuing incoming messages.
47
+ *
48
+ * @param service - The MessageQueueService instance
49
+ */
50
+ setMessageQueueService(service) {
51
+ this.messageQueueService = service;
52
+ }
53
+ /**
54
+ * Initialize the bridge by subscribing to TelegramService events.
55
+ * Must be called after TelegramService.initialize() and startPolling().
56
+ */
57
+ async initialize() {
58
+ if (this.initialized) {
59
+ this.logger.warn('Bridge already initialized');
60
+ return;
61
+ }
62
+ this.telegramService.on('message', (msg) => {
63
+ this.handleIncomingMessage(msg).catch((error) => {
64
+ this.logger.error('Failed to handle incoming message', {
65
+ error: formatError(error),
66
+ chatId: msg.chatId,
67
+ });
68
+ });
69
+ });
70
+ this.initialized = true;
71
+ this.logger.info('Bridge initialized');
72
+ }
73
+ /**
74
+ * Handle an incoming Telegram message by enqueuing it for the orchestrator.
75
+ *
76
+ * @param msg - The incoming Telegram message
77
+ */
78
+ async handleIncomingMessage(msg) {
79
+ // Store the message in the thread file
80
+ await this.threadStore.appendUserMessage(msg.chatId, msg.userName, msg.text);
81
+ // Check if orchestrator is active
82
+ if (!(await isOrchestratorActive())) {
83
+ const offlineMsg = getOrchestratorOfflineMessage();
84
+ await this.telegramService.sendMessage(msg.chatId, offlineMsg, msg.messageId);
85
+ return;
86
+ }
87
+ // Enqueue via MessageQueueService if available
88
+ if (this.messageQueueService) {
89
+ await this.enqueueMessage(msg);
90
+ }
91
+ else {
92
+ this.logger.warn('No MessageQueueService — cannot deliver message to orchestrator');
93
+ await this.telegramService.sendMessage(msg.chatId, 'Message queue is not available. Please try again later.', msg.messageId);
94
+ }
95
+ }
96
+ /**
97
+ * Enqueue a Telegram message into the message queue with a resolve callback.
98
+ *
99
+ * @param msg - The incoming message to enqueue
100
+ */
101
+ async enqueueMessage(msg) {
102
+ if (!this.messageQueueService)
103
+ return;
104
+ // Create a promise that will be resolved by the ResponseRouter
105
+ const responsePromise = new Promise((resolve) => {
106
+ const conversationId = `${TELEGRAM_CONSTANTS.CHAT_PREFIX}-${msg.chatId}`;
107
+ this.messageQueueService.enqueue({
108
+ content: msg.text,
109
+ conversationId,
110
+ source: 'telegram',
111
+ sourceMetadata: {
112
+ chatId: msg.chatId,
113
+ messageId: msg.messageId,
114
+ userId: msg.userId,
115
+ userName: msg.userName,
116
+ telegramResolve: resolve,
117
+ },
118
+ });
119
+ });
120
+ // Wait for response and send it back to Telegram
121
+ try {
122
+ const response = await Promise.race([
123
+ responsePromise,
124
+ new Promise((_, reject) => setTimeout(() => reject(new Error('Response timeout')), MESSAGE_QUEUE_CONSTANTS.DEFAULT_MESSAGE_TIMEOUT)),
125
+ ]);
126
+ // Store the bot reply
127
+ await this.threadStore.appendBotReply(msg.chatId, response);
128
+ // Send reply back to Telegram
129
+ await this.telegramService.sendMessage(msg.chatId, response, msg.messageId);
130
+ }
131
+ catch (error) {
132
+ this.logger.error('Failed to deliver response to Telegram', {
133
+ error: formatError(error),
134
+ chatId: msg.chatId,
135
+ });
136
+ await this.telegramService.sendMessage(msg.chatId, 'Sorry, something went wrong processing your message. Please try again.', msg.messageId).catch(() => {
137
+ // Swallow send failure for error message
138
+ });
139
+ }
140
+ }
141
+ /**
142
+ * Clean up the bridge by removing event listeners.
143
+ */
144
+ destroy() {
145
+ this.telegramService.removeAllListeners('message');
146
+ this.initialized = false;
147
+ this.logger.info('Bridge destroyed');
148
+ }
149
+ }
150
+ /** Singleton instance */
151
+ let instance = null;
152
+ /**
153
+ * Get the TelegramOrchestratorBridge singleton.
154
+ *
155
+ * @returns The bridge instance
156
+ */
157
+ export function getTelegramOrchestratorBridge() {
158
+ if (!instance) {
159
+ instance = new TelegramOrchestratorBridge();
160
+ }
161
+ return instance;
162
+ }
163
+ /**
164
+ * Reset the TelegramOrchestratorBridge singleton (for testing).
165
+ */
166
+ export function resetTelegramOrchestratorBridge() {
167
+ if (instance) {
168
+ instance.destroy();
169
+ }
170
+ instance = null;
171
+ }
172
+ //# sourceMappingURL=telegram-orchestrator-bridge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"telegram-orchestrator-bridge.js","sourceRoot":"","sources":["../../../../../../backend/src/services/telegram/telegram-orchestrator-bridge.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Telegram Thread Store Service
3
+ *
4
+ * Persists Telegram chat conversations as markdown files so the
5
+ * orchestrator can read conversation history after restart.
6
+ *
7
+ * Storage layout:
8
+ * ~/.crewly/telegram-threads/
9
+ * {chatId}.md — Chat conversation file
10
+ *
11
+ * @module services/telegram/telegram-thread-store
12
+ */
13
+ /**
14
+ * TelegramThreadStoreService manages persistent storage of Telegram
15
+ * chat conversations as markdown files.
16
+ *
17
+ * @example
18
+ * ```typescript
19
+ * const store = new TelegramThreadStoreService();
20
+ * await store.appendUserMessage('12345', 'Alice', 'Hello bot!');
21
+ * await store.appendBotReply('12345', 'Hello Alice!');
22
+ * ```
23
+ */
24
+ export declare class TelegramThreadStoreService {
25
+ private baseDir;
26
+ /**
27
+ * Create a new TelegramThreadStoreService.
28
+ *
29
+ * @param crewlyHome - Base crewly home directory (defaults to ~/.crewly)
30
+ */
31
+ constructor(crewlyHome?: string);
32
+ /**
33
+ * Compute the file path for a chat conversation file.
34
+ *
35
+ * @param chatId - Telegram chat ID
36
+ * @returns Absolute path to the chat markdown file
37
+ */
38
+ getChatFilePath(chatId: string): string;
39
+ /**
40
+ * Ensure the chat file exists, creating it with frontmatter if needed.
41
+ *
42
+ * @param chatId - Telegram chat ID
43
+ * @param userName - Name of the user who started the conversation
44
+ * @returns Absolute path to the chat file
45
+ */
46
+ ensureChatFile(chatId: string, userName: string): Promise<string>;
47
+ /**
48
+ * Append a user message to the chat conversation file.
49
+ *
50
+ * @param chatId - Telegram chat ID
51
+ * @param userName - Display name of the sender
52
+ * @param message - Message content
53
+ */
54
+ appendUserMessage(chatId: string, userName: string, message: string): Promise<void>;
55
+ /**
56
+ * Append a bot reply to the chat conversation file.
57
+ *
58
+ * @param chatId - Telegram chat ID
59
+ * @param message - Bot response content
60
+ */
61
+ appendBotReply(chatId: string, message: string): Promise<void>;
62
+ /**
63
+ * Read the latest conversation thread file path for a given chat.
64
+ *
65
+ * @param chatId - Telegram chat ID
66
+ * @returns Path to the thread file, or null if not found
67
+ */
68
+ getLatestThreadPath(chatId: string): Promise<string | null>;
69
+ }
70
+ /**
71
+ * Get the TelegramThreadStoreService singleton.
72
+ *
73
+ * @returns The service instance or null if not initialized
74
+ */
75
+ export declare function getTelegramThreadStore(): TelegramThreadStoreService | null;
76
+ /**
77
+ * Set the TelegramThreadStoreService singleton.
78
+ *
79
+ * @param store - The service instance to set
80
+ */
81
+ export declare function setTelegramThreadStore(store: TelegramThreadStoreService): void;
82
+ /**
83
+ * Reset the TelegramThreadStoreService singleton (for testing).
84
+ */
85
+ export declare function resetTelegramThreadStore(): void;
86
+ //# sourceMappingURL=telegram-thread-store.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"telegram-thread-store.service.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/telegram/telegram-thread-store.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAaH;;;;;;;;;;GAUG;AACH,qBAAa,0BAA0B;IACtC,OAAO,CAAC,OAAO,CAAS;IAExB;;;;OAIG;gBACS,UAAU,CAAC,EAAE,MAAM;IAK/B;;;;;OAKG;IACH,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAMvC;;;;;;OAMG;IACG,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IA2BvE;;;;;;OAMG;IACG,iBAAiB,CACtB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,GACb,OAAO,CAAC,IAAI,CAAC;IAOhB;;;;;OAKG;IACG,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAepE;;;;;OAKG;IACG,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;CASjE;AAKD;;;;GAIG;AACH,wBAAgB,sBAAsB,IAAI,0BAA0B,GAAG,IAAI,CAE1E;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,0BAA0B,GAAG,IAAI,CAE9E;AAED;;GAEG;AACH,wBAAgB,wBAAwB,IAAI,IAAI,CAE/C"}