@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,223 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.upsertXchangeRecord = upsertXchangeRecord;
7
+ exports.listXchangeRecords = listXchangeRecords;
8
+ exports.getXchangeRecord = getXchangeRecord;
9
+ exports.markXchangeRecordRead = markXchangeRecordRead;
10
+ const node_path_1 = __importDefault(require("node:path"));
11
+ const node_sqlite_1 = require("node:sqlite");
12
+ const client_1 = require("../terminal/client");
13
+ const DB_FILE_NAME = "xchange.sqlite3";
14
+ function parseJson(raw, fallback) {
15
+ if (!raw?.trim()) {
16
+ return fallback;
17
+ }
18
+ try {
19
+ return JSON.parse(raw);
20
+ }
21
+ catch {
22
+ return fallback;
23
+ }
24
+ }
25
+ function toRecord(row) {
26
+ return {
27
+ record_id: row.record_id,
28
+ session_id: row.session_id,
29
+ category: row.category,
30
+ direction: row.direction,
31
+ status: row.status,
32
+ ...(row.kind ? { kind: row.kind } : {}),
33
+ summary: row.summary,
34
+ body_text: row.body_text,
35
+ action_desc: row.action_desc,
36
+ tools: parseJson(row.tools_json, []),
37
+ ...(row.note_path ? { note_path: row.note_path } : {}),
38
+ ...(row.note_relative_path ? { note_relative_path: row.note_relative_path } : {}),
39
+ ...(row.source_session_id ? { source_session_id: row.source_session_id } : {}),
40
+ ...(row.source_label ? { source_label: row.source_label } : {}),
41
+ ...(row.source_client_uuid ? { source_client_uuid: row.source_client_uuid } : {}),
42
+ ...(row.source_local_session_id
43
+ ? { source_local_session_id: row.source_local_session_id }
44
+ : {}),
45
+ ...(row.target_session_id ? { target_session_id: row.target_session_id } : {}),
46
+ ...(row.target_label ? { target_label: row.target_label } : {}),
47
+ ...(row.target_client_uuid ? { target_client_uuid: row.target_client_uuid } : {}),
48
+ ...(row.target_local_session_id
49
+ ? { target_local_session_id: row.target_local_session_id }
50
+ : {}),
51
+ ...(row.project_uuid ? { project_uuid: row.project_uuid } : {}),
52
+ ...(row.project_name ? { project_name: row.project_name } : {}),
53
+ ...(row.requires_reply !== null
54
+ ? { requires_reply: Boolean(row.requires_reply) }
55
+ : {}),
56
+ ...(row.expected_reply ? { expected_reply: row.expected_reply } : {}),
57
+ ...(row.in_reply_to ? { in_reply_to: row.in_reply_to } : {}),
58
+ attachments: parseJson(row.attachments_json, []),
59
+ tags: parseJson(row.tags_json, []),
60
+ created_at: row.created_at,
61
+ updated_at: row.updated_at,
62
+ ...(row.read_at ? { read_at: row.read_at } : {}),
63
+ };
64
+ }
65
+ async function resolveDbPath(config, workspaceDir, exchangeDirName) {
66
+ const dir = await (0, client_1.ensureXchangeDir)(config, workspaceDir, exchangeDirName);
67
+ return node_path_1.default.join(dir, DB_FILE_NAME);
68
+ }
69
+ function applySchema(db) {
70
+ db.exec(`
71
+ CREATE TABLE IF NOT EXISTS xchange_records (
72
+ record_id TEXT PRIMARY KEY,
73
+ session_id TEXT NOT NULL,
74
+ category TEXT NOT NULL,
75
+ direction TEXT NOT NULL,
76
+ status TEXT NOT NULL,
77
+ kind TEXT,
78
+ summary TEXT NOT NULL,
79
+ body_text TEXT NOT NULL,
80
+ action_desc TEXT NOT NULL,
81
+ tools_json TEXT NOT NULL,
82
+ note_path TEXT,
83
+ note_relative_path TEXT,
84
+ source_session_id TEXT,
85
+ source_label TEXT,
86
+ source_client_uuid TEXT,
87
+ source_local_session_id TEXT,
88
+ target_session_id TEXT,
89
+ target_label TEXT,
90
+ target_client_uuid TEXT,
91
+ target_local_session_id TEXT,
92
+ project_uuid TEXT,
93
+ project_name TEXT,
94
+ requires_reply INTEGER,
95
+ expected_reply TEXT,
96
+ in_reply_to TEXT,
97
+ attachments_json TEXT NOT NULL,
98
+ tags_json TEXT NOT NULL,
99
+ created_at TEXT NOT NULL,
100
+ updated_at TEXT NOT NULL,
101
+ read_at TEXT
102
+ );
103
+
104
+ CREATE INDEX IF NOT EXISTS idx_xchange_records_session_created
105
+ ON xchange_records(session_id, created_at DESC);
106
+ CREATE INDEX IF NOT EXISTS idx_xchange_records_session_status
107
+ ON xchange_records(session_id, status, created_at DESC);
108
+ CREATE INDEX IF NOT EXISTS idx_xchange_records_session_category
109
+ ON xchange_records(session_id, category, created_at DESC);
110
+ `);
111
+ }
112
+ async function withDatabase(config, workspaceDir, exchangeDirName, callback) {
113
+ const dbPath = await resolveDbPath(config, workspaceDir, exchangeDirName);
114
+ const db = new node_sqlite_1.DatabaseSync(dbPath);
115
+ try {
116
+ applySchema(db);
117
+ return callback(db);
118
+ }
119
+ finally {
120
+ db.close();
121
+ }
122
+ }
123
+ async function upsertXchangeRecord(config, workspaceDir, exchangeDirName, record) {
124
+ await withDatabase(config, workspaceDir, exchangeDirName, (db) => {
125
+ db.prepare(`
126
+ INSERT OR REPLACE INTO xchange_records (
127
+ record_id, session_id, category, direction, status, kind, summary, body_text, action_desc,
128
+ tools_json, note_path, note_relative_path, source_session_id, source_label,
129
+ source_client_uuid, source_local_session_id, target_session_id, target_label,
130
+ target_client_uuid, target_local_session_id, project_uuid, project_name, requires_reply,
131
+ expected_reply, in_reply_to, attachments_json, tags_json, created_at, updated_at, read_at
132
+ ) VALUES (
133
+ @record_id, @session_id, @category, @direction, @status, @kind, @summary, @body_text, @action_desc,
134
+ @tools_json, @note_path, @note_relative_path, @source_session_id, @source_label,
135
+ @source_client_uuid, @source_local_session_id, @target_session_id, @target_label,
136
+ @target_client_uuid, @target_local_session_id, @project_uuid, @project_name, @requires_reply,
137
+ @expected_reply, @in_reply_to, @attachments_json, @tags_json, @created_at, @updated_at, @read_at
138
+ )
139
+ `).run({
140
+ record_id: record.record_id,
141
+ session_id: record.session_id,
142
+ category: record.category,
143
+ direction: record.direction,
144
+ status: record.status,
145
+ kind: record.kind ?? null,
146
+ summary: record.summary,
147
+ body_text: record.body_text,
148
+ action_desc: record.action_desc,
149
+ tools_json: JSON.stringify(record.tools),
150
+ note_path: record.note_path ?? null,
151
+ note_relative_path: record.note_relative_path ?? null,
152
+ source_session_id: record.source_session_id ?? null,
153
+ source_label: record.source_label ?? null,
154
+ source_client_uuid: record.source_client_uuid ?? null,
155
+ source_local_session_id: record.source_local_session_id ?? null,
156
+ target_session_id: record.target_session_id ?? null,
157
+ target_label: record.target_label ?? null,
158
+ target_client_uuid: record.target_client_uuid ?? null,
159
+ target_local_session_id: record.target_local_session_id ?? null,
160
+ project_uuid: record.project_uuid ?? null,
161
+ project_name: record.project_name ?? null,
162
+ requires_reply: typeof record.requires_reply === "boolean"
163
+ ? Number(record.requires_reply)
164
+ : null,
165
+ expected_reply: record.expected_reply ?? null,
166
+ in_reply_to: record.in_reply_to ?? null,
167
+ attachments_json: JSON.stringify(record.attachments),
168
+ tags_json: JSON.stringify(record.tags),
169
+ created_at: record.created_at,
170
+ updated_at: record.updated_at,
171
+ read_at: record.read_at ?? null,
172
+ });
173
+ });
174
+ }
175
+ async function listXchangeRecords(config, workspaceDir, exchangeDirName, sessionId, filter = {}) {
176
+ return withDatabase(config, workspaceDir, exchangeDirName, (db) => {
177
+ const conditions = ["session_id = ?"];
178
+ const values = [sessionId];
179
+ if (filter.status) {
180
+ conditions.push("status = ?");
181
+ values.push(filter.status);
182
+ }
183
+ if (filter.category) {
184
+ conditions.push("category = ?");
185
+ values.push(filter.category);
186
+ }
187
+ if (filter.direction) {
188
+ conditions.push("direction = ?");
189
+ values.push(filter.direction);
190
+ }
191
+ let sql = `
192
+ SELECT * FROM xchange_records
193
+ WHERE ${conditions.join(" AND ")}
194
+ ORDER BY created_at DESC
195
+ `;
196
+ if (typeof filter.limit === "number" && Number.isFinite(filter.limit)) {
197
+ sql += " LIMIT ?";
198
+ values.push(Math.max(1, Math.trunc(filter.limit)));
199
+ }
200
+ const rows = db.prepare(sql).all(...values);
201
+ return rows.map(toRecord);
202
+ });
203
+ }
204
+ async function getXchangeRecord(config, workspaceDir, exchangeDirName, sessionId, recordId) {
205
+ return withDatabase(config, workspaceDir, exchangeDirName, (db) => {
206
+ const row = db.prepare(`
207
+ SELECT * FROM xchange_records
208
+ WHERE session_id = ? AND record_id = ?
209
+ LIMIT 1
210
+ `).get(sessionId, recordId);
211
+ return row ? toRecord(row) : null;
212
+ });
213
+ }
214
+ async function markXchangeRecordRead(config, workspaceDir, exchangeDirName, sessionId, recordId, readAt = new Date().toISOString()) {
215
+ return withDatabase(config, workspaceDir, exchangeDirName, (db) => {
216
+ const result = db.prepare(`
217
+ UPDATE xchange_records
218
+ SET status = 'read', updated_at = ?, read_at = COALESCE(read_at, ?)
219
+ WHERE session_id = ? AND record_id = ?
220
+ `).run(readAt, readAt, sessionId, recordId);
221
+ return (result.changes ?? 0) > 0;
222
+ });
223
+ }
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.normalizeGatewayToken = normalizeGatewayToken;
4
+ exports.gatewayTokenToScopeKey = gatewayTokenToScopeKey;
5
+ exports.resolveGatewayScopeKey = resolveGatewayScopeKey;
6
+ const node_crypto_1 = require("node:crypto");
7
+ function normalizeGatewayToken(value) {
8
+ if (typeof value !== "string") {
9
+ return null;
10
+ }
11
+ const token = value.trim();
12
+ return token ? token : null;
13
+ }
14
+ function gatewayTokenToScopeKey(token) {
15
+ return (0, node_crypto_1.createHash)("sha256").update(token).digest("hex");
16
+ }
17
+ function resolveGatewayScopeKey(input) {
18
+ const gatewayToken = normalizeGatewayToken(input.gateway_token);
19
+ if (gatewayToken) {
20
+ return gatewayTokenToScopeKey(gatewayToken);
21
+ }
22
+ const scopeKey = normalizeGatewayToken(input.scope_key);
23
+ return scopeKey;
24
+ }
@@ -18,7 +18,13 @@ function createLogger(config) {
18
18
  targets: (0, pinoTargets_1.createPinoTargets)({
19
19
  level: config.logging.level,
20
20
  fileEnabled: config.logging.fileEnabled,
21
+ ...(config.logging.stderrLevel
22
+ ? { stderrLevel: config.logging.stderrLevel }
23
+ : {}),
21
24
  filePath: config.logging.filePath,
25
+ ...(config.logging.fileLevel
26
+ ? { fileLevel: config.logging.fileLevel }
27
+ : {}),
22
28
  }),
23
29
  });
24
30
  const baseLogger = (0, pino_1.default)({
@@ -1,9 +1,40 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ProjectIdentityResolver = void 0;
4
+ exports.resolveSessionDefaultsForCwd = resolveSessionDefaultsForCwd;
5
+ exports.readSessionMarkerState = readSessionMarkerState;
6
+ exports.writeSessionMarkerState = writeSessionMarkerState;
4
7
  const node_crypto_1 = require("node:crypto");
5
8
  const node_fs_1 = require("node:fs");
6
9
  const node_path_1 = require("node:path");
10
+ function resolveSessionDefaultsForCwd(input) {
11
+ const inputCwd = resolveInputCwd(input.cwd);
12
+ const resolvedCwd = inputCwd || resolveInputCwd(input.fallbackCwd) || process.cwd();
13
+ const titleBase = (0, node_path_1.basename)(resolvedCwd) || "Project";
14
+ const explicitSessionId = input.session_id?.trim();
15
+ const explicitSessionLabel = input.session_label?.trim();
16
+ const sessionMarker = explicitSessionId || explicitSessionLabel
17
+ ? null
18
+ : readSessionMarkerState(resolvedCwd, input.logger);
19
+ const derivedSessionId = sessionMarker?.localSessionId ||
20
+ `${slugify(titleBase) || "session"}-${shortHash(resolvedCwd)}`;
21
+ const derivedSessionLabel = sessionMarker?.sessionLabel || titleBase;
22
+ if (!sessionMarker && !explicitSessionId && !explicitSessionLabel) {
23
+ writeSessionMarkerState({
24
+ cwd: resolvedCwd,
25
+ localSessionId: explicitSessionId || derivedSessionId,
26
+ sessionLabel: explicitSessionLabel || derivedSessionLabel,
27
+ ...(input.logger ? { logger: input.logger } : {}),
28
+ });
29
+ }
30
+ return {
31
+ sessionId: explicitSessionId || derivedSessionId,
32
+ sessionLabel: explicitSessionLabel || derivedSessionLabel,
33
+ cwd: resolvedCwd,
34
+ sessionIdDerived: !explicitSessionId,
35
+ sessionLabelDerived: !explicitSessionLabel,
36
+ };
37
+ }
7
38
  const SESSION_MARKER_FILE_NAME = ".mcpsession.json";
8
39
  function slugify(input) {
9
40
  return input
@@ -52,6 +83,106 @@ function resolveInputCwd(value) {
52
83
  const trimmed = normalizeOptionalString(value);
53
84
  return trimmed ? (0, node_path_1.resolve)(trimmed) : undefined;
54
85
  }
86
+ function readSessionMarkerState(inputCwd, logger) {
87
+ const resolvedCwd = (0, node_path_1.resolve)(inputCwd);
88
+ const markerPath = (0, node_path_1.join)(resolvedCwd, SESSION_MARKER_FILE_NAME);
89
+ if (!(0, node_fs_1.existsSync)(markerPath)) {
90
+ return null;
91
+ }
92
+ try {
93
+ const parsed = JSON.parse((0, node_fs_1.readFileSync)(markerPath, "utf8"));
94
+ const localSessionId = typeof parsed.local_session_id === "string"
95
+ ? parsed.local_session_id.trim()
96
+ : "";
97
+ if (!localSessionId) {
98
+ return null;
99
+ }
100
+ return {
101
+ localSessionId,
102
+ ...(typeof parsed.session_label === "string" &&
103
+ parsed.session_label.trim()
104
+ ? { sessionLabel: parsed.session_label.trim() }
105
+ : {}),
106
+ ...(typeof parsed.cwd === "string" && parsed.cwd.trim()
107
+ ? { cwd: parsed.cwd.trim() }
108
+ : {}),
109
+ ...(typeof parsed.env_file === "string" && parsed.env_file.trim()
110
+ ? { envFile: parsed.env_file.trim() }
111
+ : {}),
112
+ ...(typeof parsed.last_seen_tools_hash === "string" &&
113
+ parsed.last_seen_tools_hash.trim()
114
+ ? { lastSeenToolsHash: parsed.last_seen_tools_hash.trim() }
115
+ : {}),
116
+ ...(typeof parsed.last_notified_tools_hash === "string" &&
117
+ parsed.last_notified_tools_hash.trim()
118
+ ? { lastNotifiedToolsHash: parsed.last_notified_tools_hash.trim() }
119
+ : {}),
120
+ ...(typeof parsed.updated_at === "string" && parsed.updated_at.trim()
121
+ ? { updatedAt: parsed.updated_at.trim() }
122
+ : {}),
123
+ };
124
+ }
125
+ catch (error) {
126
+ logger?.warn("Failed to read .mcpsession.json, ignoring marker", {
127
+ cwd: resolvedCwd,
128
+ markerPath,
129
+ error: error instanceof Error ? (error.stack ?? error.message) : String(error),
130
+ });
131
+ return null;
132
+ }
133
+ }
134
+ function writeSessionMarkerState(input) {
135
+ const resolvedCwd = (0, node_path_1.resolve)(input.cwd);
136
+ if (!(0, node_fs_1.existsSync)(resolvedCwd)) {
137
+ input.logger?.debug("Skipping .mcpsession.json write because cwd does not exist locally", {
138
+ cwd: resolvedCwd,
139
+ sessionId: input.localSessionId,
140
+ });
141
+ return;
142
+ }
143
+ const markerPath = (0, node_path_1.join)(resolvedCwd, SESSION_MARKER_FILE_NAME);
144
+ const legacyTellyStatePath = (0, node_path_1.join)(resolvedCwd, ".tellysession.json");
145
+ const now = new Date().toISOString();
146
+ const current = readSessionMarkerState(resolvedCwd, input.logger);
147
+ try {
148
+ (0, node_fs_1.writeFileSync)(markerPath, `${JSON.stringify({
149
+ version: 1,
150
+ local_session_id: input.localSessionId,
151
+ ...(input.sessionLabel ? { session_label: input.sessionLabel } : {}),
152
+ cwd: resolvedCwd,
153
+ ...(typeof input.envFile === "string" && input.envFile.trim()
154
+ ? { env_file: input.envFile.trim() }
155
+ : current?.envFile
156
+ ? { env_file: current.envFile }
157
+ : {}),
158
+ ...(typeof input.lastSeenToolsHash === "string" && input.lastSeenToolsHash.trim()
159
+ ? { last_seen_tools_hash: input.lastSeenToolsHash.trim() }
160
+ : current?.lastSeenToolsHash
161
+ ? { last_seen_tools_hash: current.lastSeenToolsHash }
162
+ : {}),
163
+ ...(typeof input.lastNotifiedToolsHash === "string" &&
164
+ input.lastNotifiedToolsHash.trim()
165
+ ? { last_notified_tools_hash: input.lastNotifiedToolsHash.trim() }
166
+ : current?.lastNotifiedToolsHash
167
+ ? { last_notified_tools_hash: current.lastNotifiedToolsHash }
168
+ : {}),
169
+ created_at: now,
170
+ updated_at: now,
171
+ ...(current ? { first_seen_local_session_id: current.localSessionId } : {}),
172
+ }, null, 2)}\n`, "utf8");
173
+ if ((0, node_fs_1.existsSync)(legacyTellyStatePath)) {
174
+ (0, node_fs_1.rmSync)(legacyTellyStatePath, { force: true });
175
+ }
176
+ }
177
+ catch (error) {
178
+ input.logger?.warn("Failed to write .mcpsession.json", {
179
+ cwd: resolvedCwd,
180
+ markerPath,
181
+ sessionId: input.localSessionId,
182
+ error: error instanceof Error ? (error.stack ?? error.message) : String(error),
183
+ });
184
+ }
185
+ }
55
186
  class ProjectIdentityResolver {
56
187
  config;
57
188
  logger;
@@ -76,29 +207,13 @@ class ProjectIdentityResolver {
76
207
  return this.identity;
77
208
  }
78
209
  resolveSessionDefaults(input) {
79
- const inputCwd = resolveInputCwd(input.cwd);
80
- const resolvedCwd = inputCwd || this.identity.cwd;
81
- const titleBase = (0, node_path_1.basename)(resolvedCwd) || this.identity.resolvedTitle || "Project";
82
- const sessionMarker = this.readSessionMarker(resolvedCwd);
83
- const derivedSessionId = sessionMarker?.localSessionId ||
84
- `${slugify(titleBase) || "session"}-${shortHash(resolvedCwd)}`;
85
- const derivedSessionLabel = sessionMarker?.sessionLabel || titleBase;
86
- const explicitSessionId = input.session_id?.trim();
87
- const explicitSessionLabel = input.session_label?.trim();
88
- if (!sessionMarker) {
89
- this.writeSessionMarker(resolvedCwd, {
90
- localSessionId: explicitSessionId || derivedSessionId,
91
- sessionLabel: explicitSessionLabel || derivedSessionLabel,
92
- cwd: resolvedCwd,
93
- });
94
- }
95
- return {
96
- sessionId: explicitSessionId || derivedSessionId,
97
- sessionLabel: explicitSessionLabel || derivedSessionLabel,
98
- cwd: resolvedCwd,
99
- sessionIdDerived: !explicitSessionId,
100
- sessionLabelDerived: !explicitSessionLabel,
101
- };
210
+ return resolveSessionDefaultsForCwd({
211
+ ...input,
212
+ session_id: input.session_id?.trim() || this.config.project.sessionId?.trim(),
213
+ session_label: input.session_label?.trim() || this.config.project.sessionLabel?.trim(),
214
+ fallbackCwd: this.identity.cwd,
215
+ logger: this.logger,
216
+ });
102
217
  }
103
218
  persistSessionMarker(input) {
104
219
  const resolvedCwd = resolveInputCwd(input.cwd) || this.identity.cwd;
@@ -107,6 +222,7 @@ class ProjectIdentityResolver {
107
222
  localSessionId: input.sessionId,
108
223
  sessionLabel: input.sessionLabel || current?.sessionLabel,
109
224
  cwd: resolvedCwd,
225
+ envFile: input.envFile || current?.envFile,
110
226
  });
111
227
  }
112
228
  removeSessionMarker(cwd) {
@@ -163,61 +279,16 @@ class ProjectIdentityResolver {
163
279
  };
164
280
  }
165
281
  readSessionMarker(cwd) {
166
- const markerPath = (0, node_path_1.join)(cwd, SESSION_MARKER_FILE_NAME);
167
- if (!(0, node_fs_1.existsSync)(markerPath)) {
168
- return null;
169
- }
170
- try {
171
- const parsed = JSON.parse((0, node_fs_1.readFileSync)(markerPath, "utf8"));
172
- const localSessionId = typeof parsed.local_session_id === "string"
173
- ? parsed.local_session_id.trim()
174
- : "";
175
- if (!localSessionId) {
176
- return null;
177
- }
178
- return {
179
- localSessionId,
180
- ...(typeof parsed.session_label === "string" &&
181
- parsed.session_label.trim()
182
- ? { sessionLabel: parsed.session_label.trim() }
183
- : {}),
184
- ...(typeof parsed.cwd === "string" && parsed.cwd.trim()
185
- ? { cwd: parsed.cwd.trim() }
186
- : {}),
187
- };
188
- }
189
- catch (error) {
190
- this.logger.warn("Failed to read .mcpsession.json, ignoring marker", {
191
- cwd,
192
- markerPath,
193
- error: error instanceof Error ? (error.stack ?? error.message) : String(error),
194
- });
195
- return null;
196
- }
282
+ return readSessionMarkerState(cwd, this.logger);
197
283
  }
198
284
  writeSessionMarker(inputCwd, input) {
199
- const markerPath = (0, node_path_1.join)(inputCwd, SESSION_MARKER_FILE_NAME);
200
- const now = new Date().toISOString();
201
- const current = this.readSessionMarker(inputCwd);
202
- try {
203
- (0, node_fs_1.writeFileSync)(markerPath, `${JSON.stringify({
204
- version: 1,
205
- local_session_id: input.localSessionId,
206
- ...(input.sessionLabel ? { session_label: input.sessionLabel } : {}),
207
- cwd: input.cwd,
208
- created_at: now,
209
- updated_at: now,
210
- ...(current ? { first_seen_local_session_id: current.localSessionId } : {}),
211
- }, null, 2)}\n`, "utf8");
212
- }
213
- catch (error) {
214
- this.logger.warn("Failed to write .mcpsession.json", {
215
- cwd: inputCwd,
216
- markerPath,
217
- sessionId: input.localSessionId,
218
- error: error instanceof Error ? (error.stack ?? error.message) : String(error),
219
- });
220
- }
285
+ writeSessionMarkerState({
286
+ cwd: inputCwd,
287
+ localSessionId: input.localSessionId,
288
+ sessionLabel: input.sessionLabel,
289
+ envFile: input.envFile,
290
+ logger: this.logger,
291
+ });
221
292
  }
222
293
  }
223
294
  exports.ProjectIdentityResolver = ProjectIdentityResolver;
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.deriveXchangeSummary = deriveXchangeSummary;
4
+ exports.writeTelegramMessageXchangeRecord = writeTelegramMessageXchangeRecord;
5
+ exports.writeLocalTaskXchangeRecord = writeLocalTaskXchangeRecord;
6
+ const xchangeRecordHints_1 = require("./xchangeRecordHints");
7
+ const ids_1 = require("./ids/ids");
8
+ const sqliteRecordStore_1 = require("../integrations/xchange/sqliteRecordStore");
9
+ function resolveWorkspaceDir(session, sessionId) {
10
+ const workspaceDir = session?.cwd?.trim();
11
+ if (!workspaceDir) {
12
+ throw new Error(`Workspace cwd is not registered for console '${sessionId}'.`);
13
+ }
14
+ return workspaceDir;
15
+ }
16
+ function deriveXchangeSummary(text, fallback) {
17
+ const firstLine = text
18
+ .split(/\r?\n/u)
19
+ .map((line) => line.trim())
20
+ .find(Boolean);
21
+ const summary = firstLine || fallback;
22
+ return summary.length > 160 ? `${summary.slice(0, 157)}...` : summary;
23
+ }
24
+ async function writeTelegramMessageXchangeRecord(input) {
25
+ const recordId = (0, ids_1.createInboxMessageId)(new Date(input.createdAt));
26
+ const workspaceDir = resolveWorkspaceDir(input.session, input.sessionId);
27
+ const kind = input.kind ?? "request";
28
+ const prefersBrowserScreenshot = (0, xchangeRecordHints_1.detectIncomingTelegramBrowserScreenshotRequest)({
29
+ kind,
30
+ text: input.text,
31
+ ...(input.summary?.trim() ? { summary: input.summary.trim() } : {}),
32
+ });
33
+ await (0, sqliteRecordStore_1.upsertXchangeRecord)(input.config.terminal, workspaceDir, input.config.exchange.dir, {
34
+ record_id: recordId,
35
+ session_id: input.sessionId,
36
+ category: "telegram_message",
37
+ direction: "incoming",
38
+ status: "new",
39
+ kind,
40
+ summary: input.summary?.trim() ||
41
+ deriveXchangeSummary(input.text, "Telegram message"),
42
+ body_text: input.text,
43
+ action_desc: (0, xchangeRecordHints_1.buildIncomingTelegramMessageActionDesc)(kind, prefersBrowserScreenshot),
44
+ tools: (0, xchangeRecordHints_1.buildIncomingTelegramMessageTools)(kind, prefersBrowserScreenshot),
45
+ attachments: input.attachments ?? [],
46
+ tags: input.tags ?? ["telegram", "human"],
47
+ created_at: input.createdAt,
48
+ updated_at: input.createdAt,
49
+ });
50
+ return recordId;
51
+ }
52
+ async function writeLocalTaskXchangeRecord(input) {
53
+ const recordId = (0, ids_1.createInboxMessageId)(new Date(input.createdAt));
54
+ const workspaceDir = resolveWorkspaceDir(input.session, input.sessionId);
55
+ await (0, sqliteRecordStore_1.upsertXchangeRecord)(input.config.terminal, workspaceDir, input.config.exchange.dir, {
56
+ record_id: recordId,
57
+ session_id: input.sessionId,
58
+ category: input.category ?? "local_handoff",
59
+ direction: input.direction ?? "local",
60
+ status: "new",
61
+ ...(input.kind ? { kind: input.kind } : {}),
62
+ summary: input.summary.trim(),
63
+ body_text: input.text,
64
+ action_desc: input.actionDesc,
65
+ tools: input.tools,
66
+ attachments: input.attachments ?? [],
67
+ tags: input.tags ?? ["local", "task"],
68
+ created_at: input.createdAt,
69
+ updated_at: input.createdAt,
70
+ });
71
+ return recordId;
72
+ }