@deadragdoll/tellymcp 0.0.9 → 0.0.11

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 (157) hide show
  1. package/.env.example.client +42 -50
  2. package/.env.example.gateway +49 -61
  3. package/CHANGELOG.md +3 -3
  4. package/README-ru.md +205 -384
  5. package/README.md +195 -1194
  6. package/TOOLS.md +294 -377
  7. package/VERSION.md +36 -10
  8. package/config/codex/plugins/telly-workflows/.codex-plugin/plugin.json +18 -0
  9. package/config/codex/plugins/telly-workflows/references/invariants.md +10 -0
  10. package/config/codex/plugins/telly-workflows/skills/telly-browser-screenshot/SKILL.md +27 -0
  11. package/config/codex/plugins/telly-workflows/skills/telly-collab-artifact/SKILL.md +22 -0
  12. package/config/codex/plugins/telly-workflows/skills/telly-human-telegram/SKILL.md +31 -0
  13. package/config/codex/plugins/telly-workflows/skills/telly-partner-note/SKILL.md +36 -0
  14. package/config/templates/env.both.template +40 -20
  15. package/config/templates/env.client.template +34 -18
  16. package/config/templates/env.gateway.template +38 -22
  17. package/dist/cli.js +322 -75
  18. package/dist/codexPluginInstaller.js +215 -0
  19. package/dist/lib/mixins/session.errors.js +34 -1
  20. package/dist/lib/pinoTargets.js +2 -2
  21. package/dist/moleculer.config.js +7 -5
  22. package/dist/services/features/telegram-mcp/approval.service.js +1 -1
  23. package/dist/services/features/telegram-mcp/browser.service.js +95 -2
  24. package/dist/services/features/telegram-mcp/collaboration.service.js +41 -4
  25. package/dist/services/features/telegram-mcp/ensuredb.service.js +145 -26
  26. package/dist/services/features/telegram-mcp/gateway-delivery.service.js +285 -103
  27. package/dist/services/features/telegram-mcp/gateway-rmq.service.js +3 -2
  28. package/dist/services/features/telegram-mcp/gateway-socket.service.js +905 -87
  29. package/dist/services/features/telegram-mcp/gateway.service.js +876 -81
  30. package/dist/services/features/telegram-mcp/mcp-http.service.js +9 -1
  31. package/dist/services/features/telegram-mcp/mcp-server.service.js +17 -26
  32. package/dist/services/features/telegram-mcp/notify.service.js +128 -2
  33. package/dist/services/features/telegram-mcp/runtime.service.js +27 -7
  34. package/dist/services/features/telegram-mcp/session-context.service.js +29 -2
  35. package/dist/services/features/telegram-mcp/src/app/bootstrap/runtime.js +133 -10
  36. package/dist/services/features/telegram-mcp/src/app/config/env.js +161 -51
  37. package/dist/services/features/telegram-mcp/src/app/http.js +375 -42
  38. package/dist/services/features/telegram-mcp/src/app/webapp/assets.js +386 -58
  39. package/dist/services/features/telegram-mcp/src/app/webapp/auth.js +3 -0
  40. package/dist/services/features/telegram-mcp/src/app/webapp/terminal.js +12 -0
  41. package/dist/services/features/telegram-mcp/src/entities/request/model/schema.js +116 -104
  42. package/dist/services/features/telegram-mcp/src/entities/xchange/model/types.js +2 -0
  43. package/dist/services/features/telegram-mcp/src/features/ask-user/model/askUserTelegram.js +1 -1
  44. package/dist/services/features/telegram-mcp/src/features/browser/model/browserScreenshotTool.js +1 -1
  45. package/dist/services/features/telegram-mcp/src/features/browser/model/browserService.js +249 -19
  46. package/dist/services/features/telegram-mcp/src/features/collaboration/model/gatewaySessionsService.js +71 -0
  47. package/dist/services/features/telegram-mcp/src/features/collaboration/model/listGatewaySessionsTool.js +33 -0
  48. package/dist/services/features/telegram-mcp/src/features/collaboration/model/localCollaborationBackend.js +93 -82
  49. package/dist/services/features/telegram-mcp/src/features/collaboration/model/sendPartnerFileService.js +47 -5
  50. package/dist/services/features/telegram-mcp/src/features/collaboration/model/sendPartnerFileTool.js +1 -1
  51. package/dist/services/features/telegram-mcp/src/features/collaboration/model/sendPartnerNoteTool.js +1 -1
  52. package/dist/services/features/telegram-mcp/src/features/distributed-client/model/gatewayClientAccess.js +82 -0
  53. package/dist/services/features/telegram-mcp/src/features/distributed-client/model/gatewayCollaborationBackend.js +22 -14
  54. package/dist/services/features/telegram-mcp/src/features/distributed-gateway/model/gatewayHttpService.js +649 -75
  55. package/dist/services/features/telegram-mcp/src/features/distributed-gateway/model/remoteConsoleActionClient.js +76 -0
  56. package/dist/services/features/telegram-mcp/src/features/embedded-runtime/model/embeddedRuntimeBroker.js +92 -0
  57. package/dist/services/features/telegram-mcp/src/features/foreground-terminal/model/foregroundTerminalRuntime.js +192 -0
  58. package/dist/services/features/telegram-mcp/src/features/notify/model/notifyService.js +382 -3
  59. package/dist/services/features/telegram-mcp/src/features/notify/model/notifyTelegramTool.js +1 -1
  60. package/dist/services/features/telegram-mcp/src/features/notify/model/sendFileToTelegramTool.js +33 -0
  61. package/dist/services/features/telegram-mcp/src/features/session-context/model/clearSessionContextTool.js +1 -1
  62. package/dist/services/features/telegram-mcp/src/features/session-context/model/getSessionContextTool.js +1 -1
  63. package/dist/services/features/telegram-mcp/src/features/session-context/model/renameSessionTool.js +1 -1
  64. package/dist/services/features/telegram-mcp/src/features/session-context/model/sessionContextService.js +42 -200
  65. package/dist/services/features/telegram-mcp/src/features/session-context/model/setSessionContextTool.js +1 -1
  66. package/dist/services/features/telegram-mcp/src/features/terminal-buffer/model/terminalBufferService.js +96 -0
  67. package/dist/services/features/telegram-mcp/src/features/terminal-input/model/terminalInputService.js +97 -0
  68. package/dist/services/features/telegram-mcp/src/features/tools-sync/model/refreshToolsMarkdownService.js +107 -58
  69. package/dist/services/features/telegram-mcp/src/features/tools-sync/model/refreshToolsMarkdownTool.js +1 -1
  70. package/dist/services/features/telegram-mcp/src/features/xchange/model/getXchangeRecordTool.js +28 -0
  71. package/dist/services/features/telegram-mcp/src/features/xchange/model/listXchangeRecordsTool.js +28 -0
  72. package/dist/services/features/telegram-mcp/src/features/xchange/model/markXchangeRecordReadTool.js +28 -0
  73. package/dist/services/features/telegram-mcp/src/features/xchange/model/xchangeService.js +169 -0
  74. package/dist/services/features/telegram-mcp/src/processes/human-approval/model/orchestrator.js +5 -4
  75. package/dist/services/features/telegram-mcp/src/shared/i18n/index.js +46 -0
  76. package/dist/services/features/telegram-mcp/src/shared/i18n/resources/en.js +652 -0
  77. package/dist/services/features/telegram-mcp/src/shared/i18n/resources/ru.js +652 -0
  78. package/dist/services/features/telegram-mcp/src/shared/integrations/memory/processLocalSessionStore.js +27 -0
  79. package/dist/services/features/telegram-mcp/src/shared/integrations/object-storage/minioExchangeStore.js +11 -8
  80. package/dist/services/features/telegram-mcp/src/shared/integrations/redis/stateStore.js +51 -71
  81. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/proxyFetch.js +21 -22
  82. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transport.js +411 -6524
  83. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportAttachmentStore.js +93 -0
  84. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportBroadcastActions.js +385 -0
  85. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportConsoleRegistry.js +143 -0
  86. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportConstructorWiring.js +633 -0
  87. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportContent.js +84 -0
  88. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportContext.js +78 -0
  89. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportDocumentActions.js +36 -0
  90. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportEventActions.js +292 -0
  91. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportFileHandoffActions.js +352 -0
  92. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportFormatting.js +75 -0
  93. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportGatewayActions.js +44 -0
  94. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportLifecycleActions.js +161 -0
  95. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportLive.js +56 -0
  96. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportLiveActions.js +77 -0
  97. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportMenuCallbacks.js +254 -0
  98. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportMenuFactories.js +538 -0
  99. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportMenuFingerprints.js +93 -0
  100. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportMenuFlow.js +344 -0
  101. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportMenuShell.js +62 -0
  102. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportMenuState.js +408 -0
  103. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportMenuText.js +216 -0
  104. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportMessageFlow.js +452 -0
  105. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportOutputActions.js +189 -0
  106. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportPartnerActions.js +286 -0
  107. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportPayloadState.js +101 -0
  108. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportProjectActions.js +463 -0
  109. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportProjectEntryActions.js +202 -0
  110. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportProjectEvents.js +99 -0
  111. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportProjectMenus.js +138 -0
  112. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportProjectState.js +308 -0
  113. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportProjectView.js +426 -0
  114. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportRequestFlow.js +278 -0
  115. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportSessionActions.js +143 -0
  116. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportTerminalActions.js +468 -0
  117. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportTerminalRuntime.js +171 -0
  118. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportTypes.js +2 -0
  119. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportUtils.js +330 -0
  120. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportXchangeState.js +107 -0
  121. package/dist/services/features/telegram-mcp/src/shared/integrations/terminal/client.js +255 -0
  122. package/dist/services/features/telegram-mcp/src/shared/integrations/terminal/ptyRegistry.js +543 -0
  123. package/dist/services/features/telegram-mcp/src/shared/integrations/xchange/sqliteRecordStore.js +223 -0
  124. package/dist/services/features/telegram-mcp/src/shared/lib/gatewayScope.js +24 -0
  125. package/dist/services/features/telegram-mcp/src/shared/lib/logger/logger.js +6 -0
  126. package/dist/services/features/telegram-mcp/src/shared/lib/project-identity/projectIdentity.js +147 -76
  127. package/dist/services/features/telegram-mcp/src/shared/lib/telegramXchangeRecords.js +72 -0
  128. package/dist/services/features/telegram-mcp/src/shared/lib/terminalPromptDetection.js +237 -0
  129. package/dist/services/features/telegram-mcp/src/shared/lib/version/versionHandshake.js +129 -1
  130. package/dist/services/features/telegram-mcp/src/shared/lib/xchangeRecordHints.js +98 -0
  131. package/dist/services/features/telegram-mcp/standalone-http.service.js +13 -1
  132. package/dist/services/features/telegram-mcp/terminal-buffer.service.js +42 -0
  133. package/dist/services/features/telegram-mcp/terminal-input.service.js +41 -0
  134. package/dist/services/features/telegram-mcp/tools-sync.service.js +16 -2
  135. package/dist/services/features/telegram-mcp/xchange.service.js +123 -0
  136. package/docs/STANDALONE-ru.md +172 -0
  137. package/docs/STANDALONE.md +172 -0
  138. package/package.json +11 -5
  139. package/scripts/build-package-artifact.sh +27 -0
  140. package/scripts/deploy-gateway.sh +64 -0
  141. package/scripts/deploy-onebot-branch.sh +27 -0
  142. package/scripts/postinstall.js +11 -36
  143. package/STANDALONE-ru.md +0 -274
  144. package/STANDALONE.md +0 -274
  145. package/dist/services/features/telegram-mcp/inbox.service.js +0 -33
  146. package/dist/services/features/telegram-mcp/pair.service.js +0 -33
  147. package/dist/services/features/telegram-mcp/src/app/webapp/tmux.js +0 -10
  148. package/dist/services/features/telegram-mcp/src/features/inbox/model/deleteTelegramInboxMessageTool.js +0 -33
  149. package/dist/services/features/telegram-mcp/src/features/inbox/model/getTelegramInboxCountTool.js +0 -33
  150. package/dist/services/features/telegram-mcp/src/features/inbox/model/getTelegramInboxTool.js +0 -33
  151. package/dist/services/features/telegram-mcp/src/features/inbox/model/inboxService.js +0 -77
  152. package/dist/services/features/telegram-mcp/src/features/pair-session/model/clearSessionPairingTool.js +0 -33
  153. package/dist/services/features/telegram-mcp/src/features/pair-session/model/createSessionPairCodeTool.js +0 -33
  154. package/dist/services/features/telegram-mcp/src/features/pair-session/model/generatePairCode.js +0 -202
  155. package/dist/services/features/telegram-mcp/src/features/session-context/model/getTmuxTargetTool.js +0 -33
  156. package/dist/services/features/telegram-mcp/src/features/session-context/model/setTmuxTargetTool.js +0 -33
  157. package/dist/services/features/telegram-mcp/src/shared/integrations/tmux/client.js +0 -363
@@ -0,0 +1,538 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TransportMenuFactories = void 0;
4
+ const menu_1 = require("@grammyjs/menu");
5
+ const relay_1 = require("../../../app/webapp/relay");
6
+ const transportUtils_1 = require("./transportUtils");
7
+ function splitSessionDisplayLabel(input) {
8
+ const label = (input.sessionLabel?.trim() || input.sessionId.trim() || "session").trim();
9
+ const separator = " · ";
10
+ const separatorIndex = label.indexOf(separator);
11
+ if (separatorIndex <= 0) {
12
+ return {
13
+ shortLabel: label,
14
+ ownerLabel: null,
15
+ };
16
+ }
17
+ return {
18
+ shortLabel: label.slice(0, separatorIndex).trim() || label,
19
+ ownerLabel: label.slice(separatorIndex + separator.length).trim() || null,
20
+ };
21
+ }
22
+ class TransportMenuFactories {
23
+ host;
24
+ constructor(host) {
25
+ this.host = host;
26
+ }
27
+ async createActiveSessionGroupPayloadForContext(ctx) {
28
+ const principal = this.host.getPrincipalFromContext(ctx);
29
+ if (!principal) {
30
+ return "back-to-sessions";
31
+ }
32
+ const activeSessionId = await this.host.bindingStore.getActiveSessionIdForPrincipal(principal);
33
+ if (!activeSessionId) {
34
+ return "back-to-sessions";
35
+ }
36
+ const session = await this.host.sessionStore.getSession(activeSessionId);
37
+ const display = splitSessionDisplayLabel({
38
+ sessionId: activeSessionId,
39
+ ...(session?.label ? { sessionLabel: session.label } : {}),
40
+ });
41
+ const ownerKey = (0, relay_1.parseLiveRelaySessionId)(activeSessionId)?.clientUuid ??
42
+ display.ownerLabel ??
43
+ activeSessionId;
44
+ const ownerLabel = display.ownerLabel ??
45
+ display.shortLabel ??
46
+ activeSessionId;
47
+ return await this.host.createSessionGroupMenuPayload(ownerLabel, ownerKey);
48
+ }
49
+ createMainMenu() {
50
+ return new menu_1.Menu("telegram-main-menu", {
51
+ fingerprint: async (ctx) => this.host.buildMainMenuFingerprint(ctx),
52
+ ...this.host.createMenuOptions((ctx) => this.host.showMainMenu(ctx)),
53
+ })
54
+ .text(async (ctx) => this.host.tForContext(ctx, "menu:main.buttons.live"), async (ctx) => {
55
+ await this.host.showLiveViewLauncher(ctx);
56
+ })
57
+ .text(async (ctx) => this.host.tForContext(ctx, "menu:main.buttons.content"), async (ctx) => {
58
+ await this.host.sendActiveSessionBuffer(ctx, { mode: "visible" });
59
+ })
60
+ .text(async (ctx) => this.host.tForContext(ctx, "menu:main.buttons.browser"), async (ctx) => {
61
+ await ctx.answerCallbackQuery({
62
+ text: await this.host.tForContext(ctx, "menu:main.actions.open_browser"),
63
+ });
64
+ await this.host.showBrowserMenu(ctx);
65
+ })
66
+ .row()
67
+ .text(async (ctx) => this.host.tForContext(ctx, "menu:main.buttons.collab"), async (ctx) => {
68
+ await this.host.showProjectsEntryPoint(ctx);
69
+ })
70
+ .text(async (ctx) => this.host.tForContext(ctx, "menu:main.buttons.storage"), async (ctx) => {
71
+ await ctx.answerCallbackQuery({
72
+ text: await this.host.tForContext(ctx, "menu:main.actions.open_storage"),
73
+ });
74
+ await this.host.showStorageMenu(ctx);
75
+ })
76
+ .text(async (ctx) => this.host.tForContext(ctx, "menu:main.buttons.settings"), async (ctx) => {
77
+ await ctx.answerCallbackQuery({
78
+ text: await this.host.tForContext(ctx, "menu:main.actions.open_settings"),
79
+ });
80
+ await this.host.showSettingsMenu(ctx);
81
+ })
82
+ .row()
83
+ .text({
84
+ text: async (ctx) => this.host.tForContext(ctx, "menu:main.buttons.back"),
85
+ payload: async (ctx) => await this.createActiveSessionGroupPayloadForContext(ctx),
86
+ }, async (ctx) => {
87
+ await ctx.answerCallbackQuery({
88
+ text: await this.host.tForContext(ctx, "menu:main.actions.back_to_sessions"),
89
+ });
90
+ await this.host.showSessionsMenu(ctx);
91
+ });
92
+ }
93
+ createBrowserMenu() {
94
+ return new menu_1.Menu("telegram-browser-menu", this.host.createMenuOptions((ctx) => this.host.showBrowserMenu(ctx)))
95
+ .text(async (ctx) => this.host.buildScreenshotsButtonLabel(ctx), async (ctx) => {
96
+ await ctx.answerCallbackQuery({
97
+ text: await this.host.tForContext(ctx, "menu:browser.actions.open_screenshots"),
98
+ });
99
+ await this.host.showScreenshotsMenu(ctx);
100
+ })
101
+ .row()
102
+ .text(async (ctx) => this.host.tForContext(ctx, "common:menu.back"), async (ctx) => {
103
+ await ctx.answerCallbackQuery({
104
+ text: await this.host.tForContext(ctx, "menu:browser.actions.back_to_session_menu"),
105
+ });
106
+ await this.host.showMainMenu(ctx);
107
+ });
108
+ }
109
+ createBufferMenu() {
110
+ return new menu_1.Menu("telegram-buffer-menu", this.host.createMenuOptions((ctx) => this.host.showBufferMenu(ctx)))
111
+ .text(async (ctx) => this.host.tForContext(ctx, "menu:buffer.buttons.visible"), async (ctx) => {
112
+ await this.host.sendActiveSessionBuffer(ctx, { mode: "visible" });
113
+ })
114
+ .text(async (ctx) => this.host.tForContext(ctx, "menu:buffer.buttons.full"), async (ctx) => {
115
+ await this.host.sendActiveSessionBuffer(ctx, { mode: "full" });
116
+ })
117
+ .row()
118
+ .text(async (ctx) => this.host.tForContext(ctx, "menu:buffer.buttons.last_300"), async (ctx) => {
119
+ await this.host.sendActiveSessionBuffer(ctx, {
120
+ mode: "lines",
121
+ lines: 300,
122
+ });
123
+ })
124
+ .text(async (ctx) => this.host.tForContext(ctx, "menu:buffer.buttons.last_1000"), async (ctx) => {
125
+ await this.host.sendActiveSessionBuffer(ctx, {
126
+ mode: "lines",
127
+ lines: 1000,
128
+ });
129
+ })
130
+ .row()
131
+ .text(async (ctx) => this.host.tForContext(ctx, "common:menu.back"), async (ctx) => {
132
+ await ctx.answerCallbackQuery({
133
+ text: await this.host.tForContext(ctx, "menu:local.actions.back_to_session_menu"),
134
+ });
135
+ await this.host.showMainMenu(ctx);
136
+ });
137
+ }
138
+ createSettingsMenu() {
139
+ return new menu_1.Menu("telegram-settings-menu", this.host.createMenuOptions((ctx) => this.host.showSettingsMenu(ctx)))
140
+ .text(async (ctx) => this.host.tForContext(ctx, "menu:settings.buttons.info"), async (ctx) => {
141
+ await this.host.showActiveSessionInfo(ctx);
142
+ })
143
+ .row()
144
+ .text(async (ctx) => this.host.tForContext(ctx, "menu:settings.buttons.rename"), async (ctx) => {
145
+ await this.host.beginRenameActiveSession(ctx);
146
+ })
147
+ .row()
148
+ .text(async (ctx) => this.host.tForContext(ctx, "menu:settings.buttons.unpair"), async (ctx) => {
149
+ await ctx.answerCallbackQuery({
150
+ text: await this.host.tForContext(ctx, "menu:settings.actions.confirm_unpair"),
151
+ });
152
+ await this.host.showUnpairConfirmMenu(ctx);
153
+ })
154
+ .row()
155
+ .text(async (ctx) => this.host.tForContext(ctx, "common:menu.back"), async (ctx) => {
156
+ await ctx.answerCallbackQuery({
157
+ text: await this.host.tForContext(ctx, "menu:local.actions.back_to_session_menu"),
158
+ });
159
+ await this.host.showMainMenu(ctx);
160
+ });
161
+ }
162
+ createDeveloperMenu() {
163
+ return new menu_1.Menu("telegram-developer-menu", this.host.createMenuOptions((ctx) => this.host.showDeveloperMenu(ctx)))
164
+ .text("ℹ Info", async (ctx) => {
165
+ await this.host.showDeveloperInfo(ctx);
166
+ })
167
+ .row()
168
+ .text("📣 Broadcast", async (ctx) => {
169
+ await this.host.beginBroadcast(ctx);
170
+ })
171
+ .row()
172
+ .text("🧹 Prune all", async (ctx) => {
173
+ await ctx.answerCallbackQuery({ text: "Confirm prune." });
174
+ await this.host.showPruneConfirmMenu(ctx);
175
+ })
176
+ .row()
177
+ .text("⬅ Back", async (ctx) => {
178
+ await ctx.answerCallbackQuery({ text: "Back to sessions." });
179
+ await this.host.showSessionsMenu(ctx);
180
+ });
181
+ }
182
+ createUnpairConfirmMenu() {
183
+ return new menu_1.Menu("telegram-unpair-confirm-menu", this.host.createMenuOptions((ctx) => this.host.showUnpairConfirmMenu(ctx)))
184
+ .text(async (ctx) => this.host.tForContext(ctx, "menu:settings.buttons.confirm_unpair"), async (ctx) => {
185
+ await this.host.unpairActiveSession(ctx);
186
+ })
187
+ .row()
188
+ .text(async (ctx) => this.host.tForContext(ctx, "common:menu.back"), async (ctx) => {
189
+ await ctx.answerCallbackQuery({
190
+ text: await this.host.tForContext(ctx, "menu:settings.actions.back_to_settings"),
191
+ });
192
+ await this.host.showSettingsMenu(ctx);
193
+ });
194
+ }
195
+ createPruneConfirmMenu() {
196
+ return new menu_1.Menu("telegram-prune-confirm-menu", this.host.createMenuOptions((ctx) => this.host.showPruneConfirmMenu(ctx)))
197
+ .text("⚠ Confirm prune", async (ctx) => {
198
+ await this.host.pruneAllSessions(ctx);
199
+ })
200
+ .row()
201
+ .text("⬅ Back", async (ctx) => {
202
+ await ctx.answerCallbackQuery({ text: "Back to tools." });
203
+ await this.host.showDeveloperMenu(ctx);
204
+ });
205
+ }
206
+ createStorageMenu() {
207
+ return new menu_1.Menu("telegram-storage-menu", {
208
+ fingerprint: async (ctx) => this.host.buildStorageFingerprint(ctx),
209
+ ...this.host.createMenuOptions((ctx) => this.host.showStorageMenu(ctx)),
210
+ })
211
+ .dynamic(async (ctx) => {
212
+ const range = new menu_1.MenuRange();
213
+ const principal = this.host.getPrincipalFromContext(ctx);
214
+ if (!principal) {
215
+ range.text(await this.host.tForContext(ctx, "common:menu.no_telegram_identity_label"), async (innerCtx) => {
216
+ await innerCtx.answerCallbackQuery({
217
+ text: await this.host.tForContext(innerCtx, "common:errors.missing_telegram_context"),
218
+ show_alert: true,
219
+ });
220
+ });
221
+ return range;
222
+ }
223
+ const sessionId = await this.host.bindingStore.getActiveSessionIdForPrincipal(principal);
224
+ if (!sessionId) {
225
+ range.text(await this.host.tForContext(ctx, "common:menu.no_active_session_label"), async (innerCtx) => {
226
+ await innerCtx.answerCallbackQuery({
227
+ text: await this.host.tForContext(innerCtx, "common:errors.no_active_session"),
228
+ show_alert: true,
229
+ });
230
+ });
231
+ return range;
232
+ }
233
+ const entries = await this.host.listActiveSessionStorageEntries(sessionId);
234
+ if (entries.length === 0) {
235
+ range.text(await this.host.tForContext(ctx, "menu:storage.labels.empty"), async (innerCtx) => {
236
+ await innerCtx.answerCallbackQuery({
237
+ text: await this.host.tForContext(innerCtx, "menu:storage.actions.empty"),
238
+ });
239
+ });
240
+ return range;
241
+ }
242
+ for (const entry of entries) {
243
+ range
244
+ .text({
245
+ text: this.host.formatStoragePreviewLabel(entry.filePath, entry.meta),
246
+ payload: async () => this.host.createFileMenuPayload(sessionId, entry.filePath),
247
+ }, async (innerCtx) => {
248
+ await this.host.handleStorageOpen(innerCtx);
249
+ })
250
+ .row();
251
+ }
252
+ return range;
253
+ })
254
+ .text(async (ctx) => this.host.tForContext(ctx, "common:menu.refresh"), async (ctx) => {
255
+ await ctx.answerCallbackQuery({
256
+ text: await this.host.tForContext(ctx, "menu:storage.actions.refreshed"),
257
+ });
258
+ await this.host.showStorageMenu(ctx);
259
+ })
260
+ .text(async (ctx) => this.host.tForContext(ctx, "common:menu.back"), async (ctx) => {
261
+ await ctx.answerCallbackQuery({
262
+ text: await this.host.tForContext(ctx, "menu:local.actions.back_to_session_menu"),
263
+ });
264
+ await this.host.showMainMenu(ctx);
265
+ });
266
+ }
267
+ createScreenshotsMenu() {
268
+ return new menu_1.Menu("telegram-screenshots-menu", {
269
+ fingerprint: async (ctx) => this.host.buildScreenshotsFingerprint(ctx),
270
+ ...this.host.createMenuOptions((ctx) => this.host.showScreenshotsMenu(ctx)),
271
+ })
272
+ .dynamic(async (ctx) => {
273
+ const range = new menu_1.MenuRange();
274
+ const principal = this.host.getPrincipalFromContext(ctx);
275
+ if (!principal) {
276
+ range.text(await this.host.tForContext(ctx, "common:menu.no_telegram_identity_label"), async (innerCtx) => {
277
+ await innerCtx.answerCallbackQuery({
278
+ text: await this.host.tForContext(innerCtx, "common:errors.missing_telegram_context"),
279
+ show_alert: true,
280
+ });
281
+ });
282
+ return range;
283
+ }
284
+ const sessionId = await this.host.bindingStore.getActiveSessionIdForPrincipal(principal);
285
+ if (!sessionId) {
286
+ range.text(await this.host.tForContext(ctx, "common:menu.no_active_session_label"), async (innerCtx) => {
287
+ await innerCtx.answerCallbackQuery({
288
+ text: await this.host.tForContext(innerCtx, "common:errors.no_active_session"),
289
+ show_alert: true,
290
+ });
291
+ });
292
+ return range;
293
+ }
294
+ const filePaths = await this.host.listActiveSessionScreenshots(sessionId);
295
+ if (filePaths.length === 0) {
296
+ range.text(await this.host.tForContext(ctx, "menu:screenshots.labels.empty"), async (innerCtx) => {
297
+ await innerCtx.answerCallbackQuery({
298
+ text: await this.host.tForContext(innerCtx, "menu:screenshots.actions.empty"),
299
+ });
300
+ });
301
+ return range;
302
+ }
303
+ for (const filePath of filePaths) {
304
+ range
305
+ .text({
306
+ text: this.host.formatFilePreviewLabel(filePath),
307
+ payload: async () => this.host.createFileMenuPayload(sessionId, filePath),
308
+ }, async (innerCtx) => {
309
+ await this.host.handleScreenshotOpen(innerCtx);
310
+ })
311
+ .row();
312
+ }
313
+ return range;
314
+ })
315
+ .text(async (ctx) => this.host.tForContext(ctx, "common:menu.refresh"), async (ctx) => {
316
+ await ctx.answerCallbackQuery({
317
+ text: await this.host.tForContext(ctx, "menu:screenshots.actions.refreshed"),
318
+ });
319
+ await this.host.showScreenshotsMenu(ctx);
320
+ })
321
+ .text(async (ctx) => this.host.tForContext(ctx, "common:menu.back"), async (ctx) => {
322
+ await ctx.answerCallbackQuery({
323
+ text: await this.host.tForContext(ctx, "menu:browser.actions.back_to_browser_menu"),
324
+ });
325
+ await this.host.showBrowserMenu(ctx);
326
+ });
327
+ }
328
+ createSessionsMenu() {
329
+ return new menu_1.Menu("telegram-sessions-menu", {
330
+ fingerprint: async (ctx) => this.host.buildSessionsFingerprint(ctx),
331
+ ...this.host.createMenuOptions((ctx) => this.host.showSessionsMenu(ctx)),
332
+ })
333
+ .dynamic(async (ctx) => {
334
+ const range = new menu_1.MenuRange();
335
+ try {
336
+ const principal = this.host.getPrincipalFromContext(ctx);
337
+ if (!principal) {
338
+ range.text(await this.host.tForContext(ctx, "common:menu.no_telegram_identity_label"), async (innerCtx) => {
339
+ await innerCtx.answerCallbackQuery({
340
+ text: await this.host.tForContext(innerCtx, "common:errors.missing_telegram_context"),
341
+ show_alert: true,
342
+ });
343
+ });
344
+ return range;
345
+ }
346
+ const sessionIds = (await this.host.bindingStore.listBoundSessionIdsForPrincipal(principal)).sort();
347
+ if (sessionIds.length === 0) {
348
+ range.text(await this.host.tForContext(ctx, "menu:sessions.labels.no_linked_sessions"), async (innerCtx) => {
349
+ await innerCtx.answerCallbackQuery({
350
+ text: await this.host.tForContext(innerCtx, "menu:sessions.actions.no_linked_sessions"),
351
+ show_alert: true,
352
+ });
353
+ });
354
+ return range;
355
+ }
356
+ const groupedSessions = new Map();
357
+ for (const sessionId of sessionIds) {
358
+ const session = await this.host.sessionStore.getSession(sessionId);
359
+ const display = splitSessionDisplayLabel({
360
+ sessionId,
361
+ ...(session?.label ? { sessionLabel: session.label } : {}),
362
+ });
363
+ const groupKey = (0, relay_1.parseLiveRelaySessionId)(sessionId)?.clientUuid ??
364
+ display.ownerLabel ??
365
+ sessionId;
366
+ const items = groupedSessions.get(groupKey) ?? [];
367
+ items.push({
368
+ sessionId,
369
+ ...(display.shortLabel ? { sessionLabel: display.shortLabel } : {}),
370
+ ...(display.ownerLabel ? { ownerLabel: display.ownerLabel } : {}),
371
+ active: false,
372
+ sortKey: `${display.shortLabel}\u0000${sessionId}`,
373
+ });
374
+ groupedSessions.set(groupKey, items);
375
+ }
376
+ const currentPayloadKey = (0, transportUtils_1.readMenuPayloadKey)(ctx);
377
+ let selectedOwnerLabel = null;
378
+ if (currentPayloadKey) {
379
+ const payload = await this.host.getMenuPayloadByKey(currentPayloadKey);
380
+ if (payload &&
381
+ (payload.kind === "session-group" ||
382
+ payload.kind === "active-session") &&
383
+ typeof payload.ownerKey === "string") {
384
+ selectedOwnerLabel = payload.ownerKey;
385
+ }
386
+ }
387
+ const sortedGroups = [...groupedSessions.entries()].sort((left, right) => {
388
+ const leftKey = left[0] || "\uffff";
389
+ const rightKey = right[0] || "\uffff";
390
+ return leftKey.localeCompare(rightKey);
391
+ });
392
+ if (!selectedOwnerLabel) {
393
+ for (const [groupKey, items] of sortedGroups) {
394
+ const title = items[0]?.ownerLabel ||
395
+ (items.length === 1 ? items[0]?.sessionLabel : null) ||
396
+ "Sessions";
397
+ range.text({
398
+ text: `👤 ${title}`.slice(0, 56),
399
+ payload: async () => this.host.createSessionGroupMenuPayload(title, groupKey),
400
+ }, async (innerCtx) => {
401
+ await this.host.handleSessionGroupSelection(innerCtx);
402
+ });
403
+ range.row();
404
+ }
405
+ return range;
406
+ }
407
+ for (const [groupKey, items] of sortedGroups) {
408
+ if (groupKey !== selectedOwnerLabel) {
409
+ continue;
410
+ }
411
+ items.sort((left, right) => left.sortKey.localeCompare(right.sortKey));
412
+ for (const item of items) {
413
+ range.text({
414
+ text: this.host.formatSessionMenuLabel({
415
+ sessionId: item.sessionId,
416
+ active: item.active,
417
+ ...(item.sessionLabel ? { sessionLabel: item.sessionLabel } : {}),
418
+ }),
419
+ payload: async () => this.host.createSessionMenuPayload(item.sessionId, item.ownerLabel ?? items[0]?.ownerLabel ?? undefined, selectedOwnerLabel ?? groupKey),
420
+ }, async (innerCtx) => {
421
+ await this.host.handleSessionSelection(innerCtx);
422
+ });
423
+ range.row();
424
+ }
425
+ break;
426
+ }
427
+ return range;
428
+ }
429
+ catch (error) {
430
+ this.host.logger.error("Failed to build Telegram sessions menu", {
431
+ chatId: ctx.chat?.id,
432
+ userId: ctx.from?.id,
433
+ error: error instanceof Error ? (error.stack ?? error.message) : String(error),
434
+ });
435
+ range.text(await this.host.tForContext(ctx, "menu:sessions.labels.unavailable"), async (innerCtx) => {
436
+ await innerCtx.answerCallbackQuery({
437
+ text: await this.host.tForContext(innerCtx, "menu:sessions.actions.unavailable"),
438
+ show_alert: true,
439
+ });
440
+ });
441
+ return range;
442
+ }
443
+ })
444
+ .text({
445
+ text: async (ctx) => this.host.tForContext(ctx, "common:menu.refresh"),
446
+ payload: async (ctx) => {
447
+ const currentPayloadKey = (0, transportUtils_1.readMenuPayloadKey)(ctx);
448
+ if (!currentPayloadKey) {
449
+ return "refresh";
450
+ }
451
+ const payload = await this.host.getMenuPayloadByKey(currentPayloadKey);
452
+ if (payload &&
453
+ payload.kind === "session-group" &&
454
+ typeof payload.ownerKey === "string") {
455
+ return currentPayloadKey;
456
+ }
457
+ return "refresh";
458
+ },
459
+ }, async (ctx) => {
460
+ await ctx.answerCallbackQuery({
461
+ text: await this.host.tForContext(ctx, "menu:sessions.actions.refreshed"),
462
+ });
463
+ await this.host.showSessionsMenu(ctx);
464
+ })
465
+ .text({
466
+ text: async (ctx) => this.host.tForContext(ctx, "menu:sessions.labels.tools"),
467
+ payload: async (ctx) => {
468
+ const currentPayloadKey = (0, transportUtils_1.readMenuPayloadKey)(ctx);
469
+ if (!currentPayloadKey) {
470
+ return "tools";
471
+ }
472
+ const payload = await this.host.getMenuPayloadByKey(currentPayloadKey);
473
+ if (payload &&
474
+ payload.kind === "session-group" &&
475
+ typeof payload.ownerKey === "string") {
476
+ return currentPayloadKey;
477
+ }
478
+ return "tools";
479
+ },
480
+ }, async (ctx) => {
481
+ await ctx.answerCallbackQuery({
482
+ text: await this.host.tForContext(ctx, "menu:sessions.actions.open_tools"),
483
+ });
484
+ await this.host.showDeveloperMenu(ctx);
485
+ });
486
+ }
487
+ createStorageMessageMenu() {
488
+ return new menu_1.Menu("telegram-storage-message-menu", {
489
+ fingerprint: (ctx) => (0, transportUtils_1.readMenuPayloadKey)(ctx) ?? "no-payload",
490
+ ...this.host.createMenuOptions((ctx) => this.host.showStorageMenu(ctx)),
491
+ })
492
+ .text({
493
+ text: async (ctx) => this.host.tForContext(ctx, "common:menu.get"),
494
+ payload: (ctx) => (0, transportUtils_1.readMenuPayloadKey)(ctx) ?? "missing",
495
+ }, async (ctx) => {
496
+ await this.host.handleStorageGet(ctx);
497
+ })
498
+ .text({
499
+ text: async (ctx) => this.host.tForContext(ctx, "menu:storage.buttons.delete"),
500
+ payload: (ctx) => (0, transportUtils_1.readMenuPayloadKey)(ctx) ?? "missing",
501
+ }, async (ctx) => {
502
+ await this.host.handleStorageDelete(ctx);
503
+ })
504
+ .row()
505
+ .text(async (ctx) => this.host.tForContext(ctx, "common:menu.back"), async (ctx) => {
506
+ await ctx.answerCallbackQuery({
507
+ text: await this.host.tForContext(ctx, "menu:storage.actions.back_to_storage"),
508
+ });
509
+ await this.host.showStorageMenu(ctx);
510
+ });
511
+ }
512
+ createScreenshotMessageMenu() {
513
+ return new menu_1.Menu("telegram-screenshot-message-menu", {
514
+ fingerprint: (ctx) => (0, transportUtils_1.readMenuPayloadKey)(ctx) ?? "no-payload",
515
+ ...this.host.createMenuOptions((ctx) => this.host.showScreenshotsMenu(ctx)),
516
+ })
517
+ .text({
518
+ text: async (ctx) => this.host.tForContext(ctx, "menu:storage.buttons.get"),
519
+ payload: (ctx) => (0, transportUtils_1.readMenuPayloadKey)(ctx) ?? "missing",
520
+ }, async (ctx) => {
521
+ await this.host.handleScreenshotGet(ctx);
522
+ })
523
+ .text({
524
+ text: async (ctx) => this.host.tForContext(ctx, "menu:storage.buttons.delete"),
525
+ payload: (ctx) => (0, transportUtils_1.readMenuPayloadKey)(ctx) ?? "missing",
526
+ }, async (ctx) => {
527
+ await this.host.handleScreenshotDelete(ctx);
528
+ })
529
+ .row()
530
+ .text(async (ctx) => this.host.tForContext(ctx, "common:menu.back"), async (ctx) => {
531
+ await ctx.answerCallbackQuery({
532
+ text: await this.host.tForContext(ctx, "menu:screenshots.actions.back_to_screenshots"),
533
+ });
534
+ await this.host.showScreenshotsMenu(ctx);
535
+ });
536
+ }
537
+ }
538
+ exports.TransportMenuFactories = TransportMenuFactories;
@@ -0,0 +1,93 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TransportMenuFingerprints = void 0;
4
+ const transportUtils_1 = require("./transportUtils");
5
+ class TransportMenuFingerprints {
6
+ host;
7
+ constructor(host) {
8
+ this.host = host;
9
+ }
10
+ async buildMainMenuFingerprint(ctx) {
11
+ const locale = await this.host.resolveLocaleForContext(ctx);
12
+ const principal = this.host.getPrincipalFromContext(ctx);
13
+ if (!principal) {
14
+ return `${locale}:no-principal`;
15
+ }
16
+ const sessionId = await this.host.bindingStore.getActiveSessionIdForPrincipal(principal);
17
+ if (!sessionId) {
18
+ return `${locale}:no-active-session`;
19
+ }
20
+ return `${locale}:${sessionId}`;
21
+ }
22
+ async buildStorageFingerprint(ctx) {
23
+ const locale = await this.host.resolveLocaleForContext(ctx);
24
+ const principal = this.host.getPrincipalFromContext(ctx);
25
+ if (!principal) {
26
+ return `${locale}:no-principal`;
27
+ }
28
+ const sessionId = await this.host.bindingStore.getActiveSessionIdForPrincipal(principal);
29
+ if (!sessionId) {
30
+ return `${locale}:no-active-session`;
31
+ }
32
+ const entries = await this.host.listActiveSessionStorageEntries(sessionId);
33
+ return `${locale}:${sessionId}:${entries.map((entry) => entry.filePath).join(",")}`;
34
+ }
35
+ async buildScreenshotsFingerprint(ctx) {
36
+ const locale = await this.host.resolveLocaleForContext(ctx);
37
+ const principal = this.host.getPrincipalFromContext(ctx);
38
+ if (!principal) {
39
+ return `${locale}:no-principal`;
40
+ }
41
+ const sessionId = await this.host.bindingStore.getActiveSessionIdForPrincipal(principal);
42
+ if (!sessionId) {
43
+ return `${locale}:no-active-session`;
44
+ }
45
+ const files = await this.host.listActiveSessionScreenshots(sessionId);
46
+ return `${locale}:${sessionId}:${files.join(",")}`;
47
+ }
48
+ async buildSessionsFingerprint(ctx) {
49
+ try {
50
+ const locale = await this.host.resolveLocaleForContext(ctx);
51
+ const principal = this.host.getPrincipalFromContext(ctx);
52
+ if (!principal) {
53
+ return `${locale}:no-principal`;
54
+ }
55
+ const sessionIds = (await this.host.bindingStore.listBoundSessionIdsForPrincipal(principal)).sort();
56
+ const currentPayloadKey = (0, transportUtils_1.readMenuPayloadKey)(ctx);
57
+ let selectedOwnerLabel = "";
58
+ if (currentPayloadKey) {
59
+ const payload = await this.host.getMenuPayloadByKey(currentPayloadKey);
60
+ if (payload &&
61
+ (payload.kind === "session-group" || payload.kind === "active-session") &&
62
+ typeof payload.ownerKey === "string") {
63
+ selectedOwnerLabel = payload.ownerKey;
64
+ }
65
+ }
66
+ return `${locale}:${selectedOwnerLabel}:${sessionIds.join(",")}`;
67
+ }
68
+ catch (error) {
69
+ this.host.logger.warn("Failed to build Telegram sessions menu fingerprint", {
70
+ chatId: ctx.chat?.id,
71
+ userId: ctx.from?.id,
72
+ error: error instanceof Error ? error.message : String(error),
73
+ });
74
+ return "sessions-error";
75
+ }
76
+ }
77
+ async buildScreenshotsButtonLabel(ctx) {
78
+ const locale = await this.host.resolveLocaleForContext(ctx);
79
+ const principal = this.host.getPrincipalFromContext(ctx);
80
+ if (!principal) {
81
+ return this.host.t(locale, "menu:browser.buttons.screenshots");
82
+ }
83
+ const sessionId = await this.host.bindingStore.getActiveSessionIdForPrincipal(principal);
84
+ if (!sessionId) {
85
+ return this.host.t(locale, "menu:browser.buttons.screenshots");
86
+ }
87
+ const count = (await this.host.listActiveSessionScreenshots(sessionId)).length;
88
+ return count > 0
89
+ ? this.host.t(locale, "menu:browser.buttons.screenshots_count", { count })
90
+ : this.host.t(locale, "menu:browser.buttons.screenshots");
91
+ }
92
+ }
93
+ exports.TransportMenuFingerprints = TransportMenuFingerprints;