@deadragdoll/tellymcp 0.0.10 → 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 (153) hide show
  1. package/.env.example.client +42 -52
  2. package/.env.example.gateway +48 -62
  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 +11 -11
  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 +39 -20
  15. package/config/templates/env.client.template +34 -19
  16. package/config/templates/env.gateway.template +37 -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/browser.service.js +94 -1
  23. package/dist/services/features/telegram-mcp/collaboration.service.js +40 -3
  24. package/dist/services/features/telegram-mcp/ensuredb.service.js +145 -26
  25. package/dist/services/features/telegram-mcp/gateway-delivery.service.js +285 -103
  26. package/dist/services/features/telegram-mcp/gateway-socket.service.js +897 -85
  27. package/dist/services/features/telegram-mcp/gateway.service.js +876 -81
  28. package/dist/services/features/telegram-mcp/mcp-http.service.js +8 -0
  29. package/dist/services/features/telegram-mcp/mcp-server.service.js +17 -26
  30. package/dist/services/features/telegram-mcp/notify.service.js +127 -1
  31. package/dist/services/features/telegram-mcp/session-context.service.js +28 -1
  32. package/dist/services/features/telegram-mcp/src/app/bootstrap/runtime.js +132 -10
  33. package/dist/services/features/telegram-mcp/src/app/config/env.js +158 -52
  34. package/dist/services/features/telegram-mcp/src/app/http.js +375 -42
  35. package/dist/services/features/telegram-mcp/src/app/webapp/assets.js +386 -58
  36. package/dist/services/features/telegram-mcp/src/app/webapp/auth.js +3 -0
  37. package/dist/services/features/telegram-mcp/src/app/webapp/terminal.js +12 -0
  38. package/dist/services/features/telegram-mcp/src/entities/request/model/schema.js +116 -104
  39. package/dist/services/features/telegram-mcp/src/entities/xchange/model/types.js +2 -0
  40. package/dist/services/features/telegram-mcp/src/features/ask-user/model/askUserTelegram.js +1 -1
  41. package/dist/services/features/telegram-mcp/src/features/browser/model/browserScreenshotTool.js +1 -1
  42. package/dist/services/features/telegram-mcp/src/features/browser/model/browserService.js +249 -19
  43. package/dist/services/features/telegram-mcp/src/features/collaboration/model/gatewaySessionsService.js +71 -0
  44. package/dist/services/features/telegram-mcp/src/features/collaboration/model/listGatewaySessionsTool.js +33 -0
  45. package/dist/services/features/telegram-mcp/src/features/collaboration/model/localCollaborationBackend.js +93 -82
  46. package/dist/services/features/telegram-mcp/src/features/collaboration/model/sendPartnerFileService.js +47 -5
  47. package/dist/services/features/telegram-mcp/src/features/collaboration/model/sendPartnerFileTool.js +1 -1
  48. package/dist/services/features/telegram-mcp/src/features/collaboration/model/sendPartnerNoteTool.js +1 -1
  49. package/dist/services/features/telegram-mcp/src/features/distributed-client/model/gatewayClientAccess.js +82 -0
  50. package/dist/services/features/telegram-mcp/src/features/distributed-client/model/gatewayCollaborationBackend.js +22 -14
  51. package/dist/services/features/telegram-mcp/src/features/distributed-gateway/model/gatewayHttpService.js +649 -75
  52. package/dist/services/features/telegram-mcp/src/features/distributed-gateway/model/remoteConsoleActionClient.js +76 -0
  53. package/dist/services/features/telegram-mcp/src/features/embedded-runtime/model/embeddedRuntimeBroker.js +92 -0
  54. package/dist/services/features/telegram-mcp/src/features/foreground-terminal/model/foregroundTerminalRuntime.js +192 -0
  55. package/dist/services/features/telegram-mcp/src/features/notify/model/notifyService.js +382 -3
  56. package/dist/services/features/telegram-mcp/src/features/notify/model/notifyTelegramTool.js +1 -1
  57. package/dist/services/features/telegram-mcp/src/features/notify/model/sendFileToTelegramTool.js +33 -0
  58. package/dist/services/features/telegram-mcp/src/features/session-context/model/clearSessionContextTool.js +1 -1
  59. package/dist/services/features/telegram-mcp/src/features/session-context/model/getSessionContextTool.js +1 -1
  60. package/dist/services/features/telegram-mcp/src/features/session-context/model/renameSessionTool.js +1 -1
  61. package/dist/services/features/telegram-mcp/src/features/session-context/model/sessionContextService.js +42 -200
  62. package/dist/services/features/telegram-mcp/src/features/session-context/model/setSessionContextTool.js +1 -1
  63. package/dist/services/features/telegram-mcp/src/features/terminal-buffer/model/terminalBufferService.js +96 -0
  64. package/dist/services/features/telegram-mcp/src/features/terminal-input/model/terminalInputService.js +97 -0
  65. package/dist/services/features/telegram-mcp/src/features/tools-sync/model/refreshToolsMarkdownService.js +107 -58
  66. package/dist/services/features/telegram-mcp/src/features/tools-sync/model/refreshToolsMarkdownTool.js +1 -1
  67. package/dist/services/features/telegram-mcp/src/features/xchange/model/getXchangeRecordTool.js +28 -0
  68. package/dist/services/features/telegram-mcp/src/features/xchange/model/listXchangeRecordsTool.js +28 -0
  69. package/dist/services/features/telegram-mcp/src/features/xchange/model/markXchangeRecordReadTool.js +28 -0
  70. package/dist/services/features/telegram-mcp/src/features/xchange/model/xchangeService.js +169 -0
  71. package/dist/services/features/telegram-mcp/src/processes/human-approval/model/orchestrator.js +5 -4
  72. package/dist/services/features/telegram-mcp/src/shared/i18n/resources/en.js +139 -42
  73. package/dist/services/features/telegram-mcp/src/shared/i18n/resources/ru.js +135 -38
  74. package/dist/services/features/telegram-mcp/src/shared/integrations/memory/processLocalSessionStore.js +27 -0
  75. package/dist/services/features/telegram-mcp/src/shared/integrations/object-storage/minioExchangeStore.js +11 -8
  76. package/dist/services/features/telegram-mcp/src/shared/integrations/redis/stateStore.js +42 -71
  77. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/proxyFetch.js +21 -22
  78. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transport.js +415 -7101
  79. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportAttachmentStore.js +93 -0
  80. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportBroadcastActions.js +385 -0
  81. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportConsoleRegistry.js +143 -0
  82. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportConstructorWiring.js +633 -0
  83. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportContent.js +84 -0
  84. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportContext.js +78 -0
  85. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportDocumentActions.js +36 -0
  86. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportEventActions.js +292 -0
  87. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportFileHandoffActions.js +352 -0
  88. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportFormatting.js +75 -0
  89. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportGatewayActions.js +44 -0
  90. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportLifecycleActions.js +161 -0
  91. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportLive.js +56 -0
  92. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportLiveActions.js +77 -0
  93. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportMenuCallbacks.js +254 -0
  94. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportMenuFactories.js +538 -0
  95. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportMenuFingerprints.js +93 -0
  96. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportMenuFlow.js +344 -0
  97. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportMenuShell.js +62 -0
  98. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportMenuState.js +408 -0
  99. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportMenuText.js +216 -0
  100. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportMessageFlow.js +452 -0
  101. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportOutputActions.js +189 -0
  102. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportPartnerActions.js +286 -0
  103. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportPayloadState.js +101 -0
  104. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportProjectActions.js +463 -0
  105. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportProjectEntryActions.js +202 -0
  106. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportProjectEvents.js +99 -0
  107. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportProjectMenus.js +138 -0
  108. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportProjectState.js +308 -0
  109. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportProjectView.js +426 -0
  110. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportRequestFlow.js +278 -0
  111. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportSessionActions.js +143 -0
  112. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportTerminalActions.js +468 -0
  113. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportTerminalRuntime.js +171 -0
  114. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportTypes.js +2 -0
  115. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportUtils.js +330 -0
  116. package/dist/services/features/telegram-mcp/src/shared/integrations/telegram/transportXchangeState.js +107 -0
  117. package/dist/services/features/telegram-mcp/src/shared/integrations/terminal/client.js +255 -0
  118. package/dist/services/features/telegram-mcp/src/shared/integrations/terminal/ptyRegistry.js +543 -0
  119. package/dist/services/features/telegram-mcp/src/shared/integrations/xchange/sqliteRecordStore.js +223 -0
  120. package/dist/services/features/telegram-mcp/src/shared/lib/gatewayScope.js +24 -0
  121. package/dist/services/features/telegram-mcp/src/shared/lib/logger/logger.js +6 -0
  122. package/dist/services/features/telegram-mcp/src/shared/lib/project-identity/projectIdentity.js +147 -76
  123. package/dist/services/features/telegram-mcp/src/shared/lib/telegramXchangeRecords.js +72 -0
  124. package/dist/services/features/telegram-mcp/src/shared/lib/terminalPromptDetection.js +237 -0
  125. package/dist/services/features/telegram-mcp/src/shared/lib/version/versionHandshake.js +129 -1
  126. package/dist/services/features/telegram-mcp/src/shared/lib/xchangeRecordHints.js +98 -0
  127. package/dist/services/features/telegram-mcp/standalone-http.service.js +12 -0
  128. package/dist/services/features/telegram-mcp/terminal-buffer.service.js +42 -0
  129. package/dist/services/features/telegram-mcp/terminal-input.service.js +41 -0
  130. package/dist/services/features/telegram-mcp/tools-sync.service.js +15 -1
  131. package/dist/services/features/telegram-mcp/xchange.service.js +123 -0
  132. package/docs/STANDALONE-ru.md +172 -0
  133. package/docs/STANDALONE.md +172 -0
  134. package/package.json +10 -5
  135. package/scripts/build-package-artifact.sh +27 -0
  136. package/scripts/deploy-gateway.sh +64 -0
  137. package/scripts/deploy-onebot-branch.sh +27 -0
  138. package/scripts/postinstall.js +11 -36
  139. package/STANDALONE-ru.md +0 -274
  140. package/STANDALONE.md +0 -274
  141. package/dist/services/features/telegram-mcp/inbox.service.js +0 -33
  142. package/dist/services/features/telegram-mcp/pair.service.js +0 -33
  143. package/dist/services/features/telegram-mcp/src/app/webapp/tmux.js +0 -10
  144. package/dist/services/features/telegram-mcp/src/features/inbox/model/deleteTelegramInboxMessageTool.js +0 -33
  145. package/dist/services/features/telegram-mcp/src/features/inbox/model/getTelegramInboxCountTool.js +0 -33
  146. package/dist/services/features/telegram-mcp/src/features/inbox/model/getTelegramInboxTool.js +0 -33
  147. package/dist/services/features/telegram-mcp/src/features/inbox/model/inboxService.js +0 -77
  148. package/dist/services/features/telegram-mcp/src/features/pair-session/model/clearSessionPairingTool.js +0 -33
  149. package/dist/services/features/telegram-mcp/src/features/pair-session/model/createSessionPairCodeTool.js +0 -33
  150. package/dist/services/features/telegram-mcp/src/features/pair-session/model/generatePairCode.js +0 -202
  151. package/dist/services/features/telegram-mcp/src/features/session-context/model/getTmuxTargetTool.js +0 -33
  152. package/dist/services/features/telegram-mcp/src/features/session-context/model/setTmuxTargetTool.js +0 -33
  153. package/dist/services/features/telegram-mcp/src/shared/integrations/tmux/client.js +0 -363
@@ -4,6 +4,9 @@ exports.RefreshToolsMarkdownService = void 0;
4
4
  const node_crypto_1 = require("node:crypto");
5
5
  const node_fs_1 = require("node:fs");
6
6
  const node_path_1 = require("node:path");
7
+ const schema_1 = require("../../../entities/request/model/schema");
8
+ const projectIdentity_1 = require("../../../shared/lib/project-identity/projectIdentity");
9
+ const versionHandshake_1 = require("../../../shared/lib/version/versionHandshake");
7
10
  function normalizeGatewayBaseUrl(value) {
8
11
  const url = new URL(value);
9
12
  url.pathname = url.pathname.replace(/\/+$/u, "");
@@ -15,27 +18,84 @@ function normalizeGatewayBaseUrl(value) {
15
18
  function computeContentHash(content) {
16
19
  return (0, node_crypto_1.createHash)("sha256").update(content).digest("hex");
17
20
  }
21
+ function normalizeClientLocalSessionId(mode, value) {
22
+ const trimmed = value?.trim();
23
+ if (!trimmed || mode !== "client") {
24
+ return trimmed || undefined;
25
+ }
26
+ const separatorIndex = trimmed.indexOf(":");
27
+ if (separatorIndex <= 0 || separatorIndex === trimmed.length - 1) {
28
+ return trimmed;
29
+ }
30
+ return trimmed.slice(separatorIndex + 1).trim() || trimmed;
31
+ }
32
+ function normalizeRemoteRefreshOutput(value) {
33
+ const candidate = value && typeof value === "object" && "structuredContent" in value
34
+ ? value.structuredContent
35
+ : value && typeof value === "object" && "result" in value
36
+ ? value.result
37
+ : value;
38
+ const parsed = schema_1.refreshToolsMarkdownOutputSchema.safeParse(candidate);
39
+ return parsed.success ? parsed.data : null;
40
+ }
18
41
  class RefreshToolsMarkdownService {
19
42
  config;
20
43
  sessionStore;
21
44
  logger;
22
45
  projectIdentityResolver;
23
- constructor(config, sessionStore, logger, projectIdentityResolver) {
46
+ remoteConsoleInvoker;
47
+ constructor(config, sessionStore, logger, projectIdentityResolver, remoteConsoleInvoker) {
24
48
  this.config = config;
25
49
  this.sessionStore = sessionStore;
26
50
  this.logger = logger;
27
51
  this.projectIdentityResolver = projectIdentityResolver;
52
+ this.remoteConsoleInvoker = remoteConsoleInvoker;
28
53
  }
29
54
  async refresh(input = {}) {
30
- const resolved = this.projectIdentityResolver.resolveSessionDefaults(input);
55
+ const normalizedSessionId = normalizeClientLocalSessionId(this.config.distributed.mode, input.session_id);
56
+ const resolved = this.projectIdentityResolver.resolveSessionDefaults({
57
+ ...input,
58
+ ...(normalizedSessionId ? { session_id: normalizedSessionId } : {}),
59
+ });
60
+ const explicitCwd = input.cwd?.trim() ? (0, node_path_1.resolve)(input.cwd.trim()) : null;
61
+ const requestedSessionId = normalizedSessionId ?? "";
62
+ const knownHash = input.known_hash?.trim() || null;
63
+ const remoteLookupRequested = Boolean(this.remoteConsoleInvoker) &&
64
+ this.config.distributed.mode !== "client";
65
+ const remote = remoteLookupRequested && requestedSessionId
66
+ ? await this.remoteConsoleInvoker?.invokeForRelaySession(requestedSessionId, "telegramMcp.toolsSync.refreshToolsMarkdownRemote", input)
67
+ : null;
68
+ if (remote) {
69
+ const normalizedRemote = normalizeRemoteRefreshOutput(remote);
70
+ if (normalizedRemote) {
71
+ return normalizedRemote;
72
+ }
73
+ this.logger.error("refresh_tools_markdown received invalid remote console output", {
74
+ sessionId: requestedSessionId,
75
+ remote,
76
+ });
77
+ throw new Error(`Invalid remote refresh_tools_markdown output: ${JSON.stringify(remote)}`);
78
+ }
79
+ if (remoteLookupRequested) {
80
+ this.logger.error("refresh_tools_markdown could not resolve remote console target", {
81
+ sessionId: resolved.sessionId,
82
+ requestedSessionId,
83
+ explicitCwd,
84
+ });
85
+ throw new Error(requestedSessionId
86
+ ? "Could not resolve remote console target for refresh_tools_markdown. Use the canonical gateway session_id in the format client_uuid:local_session_id."
87
+ : "refresh_tools_markdown requires explicit session_id in gateway mode. Use the canonical gateway session_id in the format client_uuid:local_session_id.");
88
+ }
31
89
  const session = await this.sessionStore.getSession(resolved.sessionId);
32
- const workspaceDir = input.cwd?.trim()
33
- ? (0, node_path_1.resolve)(input.cwd.trim())
34
- : session?.cwd?.trim()
35
- ? (0, node_path_1.resolve)(session.cwd.trim())
36
- : undefined;
37
- const saveLocally = input.save_locally !== false;
38
- const gatewayToolsPath = (0, node_path_1.join)(process.cwd(), "TOOLS.md");
90
+ const sessionCwd = session?.cwd?.trim() ? (0, node_path_1.resolve)(session.cwd.trim()) : null;
91
+ const workspaceDir = requestedSessionId
92
+ ? sessionCwd ?? explicitCwd ?? resolved.cwd
93
+ : explicitCwd ?? sessionCwd ?? resolved.cwd;
94
+ const packageRoot = (0, versionHandshake_1.getTellyMcpPackageRoot)(__dirname);
95
+ if (!packageRoot) {
96
+ throw new Error("Could not resolve installed package root for TOOLS.md.");
97
+ }
98
+ const gatewayToolsPath = (0, node_path_1.join)(packageRoot, "TOOLS.md");
39
99
  let source = "local";
40
100
  let content;
41
101
  if (this.config.distributed.gatewayPublicUrl) {
@@ -59,64 +119,53 @@ class RefreshToolsMarkdownService {
59
119
  else {
60
120
  content = (0, node_fs_1.readFileSync)(gatewayToolsPath, "utf8");
61
121
  }
62
- if (!workspaceDir) {
63
- throw new Error("Could not resolve target workspace for TOOLS.md. Pair the session with cwd first or pass cwd/session_id explicitly.");
64
- }
65
- const toolsPath = (0, node_path_1.join)(workspaceDir, "TOOLS.md");
66
- if (saveLocally) {
67
- (0, node_fs_1.writeFileSync)(toolsPath, content, "utf8");
68
- const appliedHash = computeContentHash(content);
69
- await this.sessionStore.setSession({
70
- sessionId: resolved.sessionId,
71
- ...(session?.label ? { label: session.label } : {}),
72
- ...(session?.cwd ? { cwd: session.cwd } : { cwd: workspaceDir }),
73
- ...(session?.linkedSessionId
74
- ? { linkedSessionId: session.linkedSessionId }
75
- : {}),
76
- ...(session?.activeProjectUuid
77
- ? { activeProjectUuid: session.activeProjectUuid }
78
- : {}),
79
- ...(session?.activeProjectName
80
- ? { activeProjectName: session.activeProjectName }
81
- : {}),
82
- ...(session?.task ? { task: session.task } : {}),
83
- ...(session?.summary ? { summary: session.summary } : {}),
84
- ...(session?.files ? { files: session.files } : {}),
85
- ...(session?.decisions ? { decisions: session.decisions } : {}),
86
- ...(session?.risks ? { risks: session.risks } : {}),
87
- ...(session?.tmuxSessionName
88
- ? { tmuxSessionName: session.tmuxSessionName }
89
- : {}),
90
- ...(session?.tmuxWindowName
91
- ? { tmuxWindowName: session.tmuxWindowName }
92
- : {}),
93
- ...(typeof session?.tmuxWindowIndex === "number"
94
- ? { tmuxWindowIndex: session.tmuxWindowIndex }
95
- : {}),
96
- ...(session?.tmuxPaneId ? { tmuxPaneId: session.tmuxPaneId } : {}),
97
- ...(typeof session?.tmuxPaneIndex === "number"
98
- ? { tmuxPaneIndex: session.tmuxPaneIndex }
99
- : {}),
100
- ...(session?.tmuxTarget ? { tmuxTarget: session.tmuxTarget } : {}),
101
- ...(session?.lastTmuxNudgeAt
102
- ? { lastTmuxNudgeAt: session.lastTmuxNudgeAt }
103
- : {}),
104
- lastSeenToolsHash: appliedHash,
105
- lastNotifiedToolsHash: appliedHash,
106
- updatedAt: new Date().toISOString(),
122
+ const currentHash = computeContentHash(content);
123
+ const changed = knownHash !== currentHash;
124
+ await this.sessionStore.setSession({
125
+ sessionId: resolved.sessionId,
126
+ ...(session?.label ? { label: session.label } : {}),
127
+ ...(session?.cwd ? { cwd: session.cwd } : workspaceDir ? { cwd: workspaceDir } : {}),
128
+ ...(session?.activeProjectUuid
129
+ ? { activeProjectUuid: session.activeProjectUuid }
130
+ : {}),
131
+ ...(session?.activeProjectName
132
+ ? { activeProjectName: session.activeProjectName }
133
+ : {}),
134
+ ...(session?.task ? { task: session.task } : {}),
135
+ ...(session?.summary ? { summary: session.summary } : {}),
136
+ ...(session?.files ? { files: session.files } : {}),
137
+ ...(session?.decisions ? { decisions: session.decisions } : {}),
138
+ ...(session?.risks ? { risks: session.risks } : {}),
139
+ ...(session?.terminalTarget ? { terminalTarget: session.terminalTarget } : {}),
140
+ ...(session?.lastTerminalNudgeAt
141
+ ? { lastTerminalNudgeAt: session.lastTerminalNudgeAt }
142
+ : {}),
143
+ lastSeenToolsHash: currentHash,
144
+ lastNotifiedToolsHash: currentHash,
145
+ updatedAt: new Date().toISOString(),
146
+ });
147
+ if (workspaceDir) {
148
+ (0, projectIdentity_1.writeSessionMarkerState)({
149
+ cwd: workspaceDir,
150
+ localSessionId: resolved.sessionId,
151
+ lastSeenToolsHash: currentHash,
152
+ lastNotifiedToolsHash: currentHash,
153
+ logger: this.logger,
107
154
  });
108
155
  }
109
156
  this.logger.info("TOOLS.md refreshed", {
110
157
  source,
111
- saved: saveLocally,
112
- path: toolsPath,
113
158
  bytes: Buffer.byteLength(content, "utf8"),
159
+ currentHash,
160
+ changed,
114
161
  });
115
162
  return {
116
163
  source,
117
- saved: saveLocally,
164
+ session_id: resolved.sessionId,
165
+ current_hash: currentHash,
166
+ changed,
167
+ ...(changed ? { content } : {}),
118
168
  bytes: Buffer.byteLength(content, "utf8"),
119
- ...(saveLocally ? { path: toolsPath } : {}),
120
169
  };
121
170
  }
122
171
  }
@@ -18,7 +18,7 @@ class RefreshToolsMarkdownTool {
18
18
  register(server) {
19
19
  server.registerTool("refresh_tools_markdown", {
20
20
  title: "Refresh TOOLS.md",
21
- description: "Use this when the user asks to refresh or update agent instructions, tools documentation, or gateway-side working rules. Download the canonical TOOLS.md from the configured gateway, overwrite the local workspace TOOLS.md, then re-read that local TOOLS.md before continuing. If no gateway is configured, refresh from the local file.",
21
+ description: "Use this when the user asks to refresh or update agent instructions, tools documentation, or gateway-side working rules. In gateway mode, always pass explicit session_id equal to the canonical gateway console id client_uuid:local_session_id. If the current console id is already known from prior context, reuse it directly and do not call list_gateway_sessions again. Only call list_gateway_sessions when the console id is unknown, then take session_id from the matching record exactly as returned. Do not use workspace-derived ids or cwd for routing. Prefer hash-based refresh: pass known_hash from the last applied TOOLS state. The tool returns current_hash and changed; content is included only when changed=true. There is no local file-save mode: read and apply returned content directly.",
22
22
  inputSchema: schema_1.refreshToolsMarkdownInputSchema,
23
23
  outputSchema: schema_1.refreshToolsMarkdownOutputSchema,
24
24
  }, async (args) => {
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GetXchangeRecordTool = void 0;
4
+ const schema_1 = require("../../../entities/request/model/schema");
5
+ function createContent(output) {
6
+ return [{ type: "text", text: JSON.stringify(output, null, 2) }];
7
+ }
8
+ class GetXchangeRecordTool {
9
+ xchangeService;
10
+ constructor(xchangeService) {
11
+ this.xchangeService = xchangeService;
12
+ }
13
+ register(server) {
14
+ server.registerTool("get_xchange_record", {
15
+ title: "Get Xchange Record",
16
+ description: "Read one structured .mcp-xchange record by record_id. Use this to get the full body_text, action_desc, tools, attachments, routing metadata, and reply requirements for a collaboration item, local handoff, or human Telegram message.",
17
+ inputSchema: schema_1.getXchangeRecordInputSchema,
18
+ outputSchema: schema_1.getXchangeRecordOutputSchema,
19
+ }, async (args) => {
20
+ const output = await this.xchangeService.getRecord(args);
21
+ return {
22
+ content: createContent(output),
23
+ structuredContent: output,
24
+ };
25
+ });
26
+ }
27
+ }
28
+ exports.GetXchangeRecordTool = GetXchangeRecordTool;
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ListXchangeRecordsTool = void 0;
4
+ const schema_1 = require("../../../entities/request/model/schema");
5
+ function createContent(output) {
6
+ return [{ type: "text", text: JSON.stringify(output, null, 2) }];
7
+ }
8
+ class ListXchangeRecordsTool {
9
+ xchangeService;
10
+ constructor(xchangeService) {
11
+ this.xchangeService = xchangeService;
12
+ }
13
+ register(server) {
14
+ server.registerTool("list_xchange_records", {
15
+ title: "List Xchange Records",
16
+ description: "List structured .mcp-xchange records for the current console from the local sqlite store. Use this first for partner notes, local handoffs, unread collaboration items, human Telegram messages, and follow-up work instead of parsing markdown index files or relying on inbox-style flows.",
17
+ inputSchema: schema_1.listXchangeRecordsInputSchema,
18
+ outputSchema: schema_1.listXchangeRecordsOutputSchema,
19
+ }, async (args) => {
20
+ const output = await this.xchangeService.listRecords(args);
21
+ return {
22
+ content: createContent(output),
23
+ structuredContent: output,
24
+ };
25
+ });
26
+ }
27
+ }
28
+ exports.ListXchangeRecordsTool = ListXchangeRecordsTool;
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MarkXchangeRecordReadTool = void 0;
4
+ const schema_1 = require("../../../entities/request/model/schema");
5
+ function createContent(output) {
6
+ return [{ type: "text", text: JSON.stringify(output, null, 2) }];
7
+ }
8
+ class MarkXchangeRecordReadTool {
9
+ xchangeService;
10
+ constructor(xchangeService) {
11
+ this.xchangeService = xchangeService;
12
+ }
13
+ register(server) {
14
+ server.registerTool("mark_xchange_record_read", {
15
+ title: "Mark Xchange Record Read",
16
+ description: "Mark a structured .mcp-xchange record as read after you have consumed its body_text, attachments, and next-step instructions.",
17
+ inputSchema: schema_1.markXchangeRecordReadInputSchema,
18
+ outputSchema: schema_1.markXchangeRecordReadOutputSchema,
19
+ }, async (args) => {
20
+ const output = await this.xchangeService.markRead(args);
21
+ return {
22
+ content: createContent(output),
23
+ structuredContent: output,
24
+ };
25
+ });
26
+ }
27
+ }
28
+ exports.MarkXchangeRecordReadTool = MarkXchangeRecordReadTool;
@@ -0,0 +1,169 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.XchangeService = void 0;
4
+ const sqliteRecordStore_1 = require("../../../shared/integrations/xchange/sqliteRecordStore");
5
+ class XchangeService {
6
+ config;
7
+ sessionStore;
8
+ maintenanceStore;
9
+ xchangeFileMetaStore;
10
+ logger;
11
+ projectIdentityResolver;
12
+ remoteConsoleInvoker;
13
+ constructor(config, sessionStore, maintenanceStore, xchangeFileMetaStore, logger, projectIdentityResolver, remoteConsoleInvoker) {
14
+ this.config = config;
15
+ this.sessionStore = sessionStore;
16
+ this.maintenanceStore = maintenanceStore;
17
+ this.xchangeFileMetaStore = xchangeFileMetaStore;
18
+ this.logger = logger;
19
+ this.projectIdentityResolver = projectIdentityResolver;
20
+ this.remoteConsoleInvoker = remoteConsoleInvoker;
21
+ }
22
+ async listRecords(input) {
23
+ const resolved = this.projectIdentityResolver.resolveSessionDefaults(input);
24
+ const sessionId = await this.normalizeSessionIdForAccess(resolved.sessionId);
25
+ const remote = this.config.distributed.mode !== "client"
26
+ ? await this.remoteConsoleInvoker?.invokeForRelaySession(sessionId, "telegramMcp.xchange.listRecordsRemote", {
27
+ ...input,
28
+ session_id: sessionId,
29
+ })
30
+ : null;
31
+ if (remote) {
32
+ return remote;
33
+ }
34
+ const workspaceDir = await this.resolveWorkspaceDir(sessionId);
35
+ const records = await (0, sqliteRecordStore_1.listXchangeRecords)(this.config.terminal, workspaceDir, this.config.exchange.dir, sessionId, {
36
+ ...(input.status ? { status: input.status } : {}),
37
+ ...(input.category ? { category: input.category } : {}),
38
+ ...(input.direction ? { direction: input.direction } : {}),
39
+ ...(typeof input.limit === "number" ? { limit: input.limit } : {}),
40
+ });
41
+ this.logger.info("Xchange records listed", {
42
+ sessionId,
43
+ sessionIdDerived: resolved.sessionIdDerived,
44
+ total: records.length,
45
+ status: input.status,
46
+ category: input.category,
47
+ direction: input.direction,
48
+ limit: input.limit,
49
+ });
50
+ return {
51
+ session_id: sessionId,
52
+ total: records.length,
53
+ records,
54
+ };
55
+ }
56
+ async getRecord(input) {
57
+ const resolved = this.projectIdentityResolver.resolveSessionDefaults(input);
58
+ const sessionId = await this.normalizeSessionIdForAccess(resolved.sessionId);
59
+ const remote = this.config.distributed.mode !== "client"
60
+ ? await this.remoteConsoleInvoker?.invokeForRelaySession(sessionId, "telegramMcp.xchange.getRecordRemote", {
61
+ ...input,
62
+ session_id: sessionId,
63
+ })
64
+ : null;
65
+ if (remote) {
66
+ return remote;
67
+ }
68
+ const workspaceDir = await this.resolveWorkspaceDir(sessionId);
69
+ const record = await (0, sqliteRecordStore_1.getXchangeRecord)(this.config.terminal, workspaceDir, this.config.exchange.dir, sessionId, input.record_id);
70
+ this.logger.info("Xchange record fetched", {
71
+ sessionId,
72
+ sessionIdDerived: resolved.sessionIdDerived,
73
+ recordId: input.record_id,
74
+ exists: Boolean(record),
75
+ });
76
+ return {
77
+ session_id: sessionId,
78
+ record,
79
+ };
80
+ }
81
+ async markRead(input) {
82
+ const resolved = this.projectIdentityResolver.resolveSessionDefaults(input);
83
+ const sessionId = await this.normalizeSessionIdForAccess(resolved.sessionId);
84
+ const remote = this.config.distributed.mode !== "client"
85
+ ? await this.remoteConsoleInvoker?.invokeForRelaySession(sessionId, "telegramMcp.xchange.markReadRemote", {
86
+ ...input,
87
+ session_id: sessionId,
88
+ })
89
+ : null;
90
+ if (remote) {
91
+ return remote;
92
+ }
93
+ const workspaceDir = await this.resolveWorkspaceDir(sessionId);
94
+ const updated = await (0, sqliteRecordStore_1.markXchangeRecordRead)(this.config.terminal, workspaceDir, this.config.exchange.dir, sessionId, input.record_id);
95
+ this.logger.info("Xchange record marked as read", {
96
+ sessionId,
97
+ sessionIdDerived: resolved.sessionIdDerived,
98
+ recordId: input.record_id,
99
+ updated,
100
+ });
101
+ return {
102
+ session_id: sessionId,
103
+ record_id: input.record_id,
104
+ updated,
105
+ };
106
+ }
107
+ async listFileMetas(input) {
108
+ const resolved = this.projectIdentityResolver.resolveSessionDefaults(input);
109
+ const sessionId = await this.normalizeSessionIdForAccess(resolved.sessionId);
110
+ const metas = await this.xchangeFileMetaStore.listXchangeFileMetas(sessionId);
111
+ const filtered = input.source
112
+ ? metas.filter((meta) => meta.source === input.source)
113
+ : metas;
114
+ filtered.sort((left, right) => right.filePath.localeCompare(left.filePath));
115
+ return {
116
+ session_id: sessionId,
117
+ metas: filtered,
118
+ };
119
+ }
120
+ async getFileMeta(input) {
121
+ const resolved = this.projectIdentityResolver.resolveSessionDefaults(input);
122
+ const sessionId = await this.normalizeSessionIdForAccess(resolved.sessionId);
123
+ return {
124
+ session_id: sessionId,
125
+ file_path: input.file_path,
126
+ meta: await this.xchangeFileMetaStore.getXchangeFileMeta(sessionId, input.file_path),
127
+ };
128
+ }
129
+ async deleteFileMeta(input) {
130
+ const resolved = this.projectIdentityResolver.resolveSessionDefaults(input);
131
+ const sessionId = await this.normalizeSessionIdForAccess(resolved.sessionId);
132
+ return {
133
+ session_id: sessionId,
134
+ file_path: input.file_path,
135
+ deleted: await this.xchangeFileMetaStore.deleteXchangeFileMeta(sessionId, input.file_path),
136
+ };
137
+ }
138
+ async normalizeSessionIdForAccess(sessionId) {
139
+ const trimmed = sessionId.trim();
140
+ if (!trimmed) {
141
+ return trimmed;
142
+ }
143
+ const direct = await this.sessionStore.getSession(trimmed);
144
+ if (direct) {
145
+ return trimmed;
146
+ }
147
+ const separatorIndex = trimmed.indexOf(":");
148
+ if (separatorIndex <= 0) {
149
+ return trimmed;
150
+ }
151
+ const localClientUuid = await this.maintenanceStore.getGatewayClientUuid();
152
+ const clientUuid = trimmed.slice(0, separatorIndex).trim();
153
+ const localSessionId = trimmed.slice(separatorIndex + 1).trim();
154
+ if (!localClientUuid || clientUuid !== localClientUuid || !localSessionId) {
155
+ return trimmed;
156
+ }
157
+ const localSession = await this.sessionStore.getSession(localSessionId);
158
+ return localSession ? localSessionId : trimmed;
159
+ }
160
+ async resolveWorkspaceDir(sessionId) {
161
+ const session = await this.sessionStore.getSession(sessionId);
162
+ const workspaceDir = session?.cwd?.trim();
163
+ if (!workspaceDir) {
164
+ throw new Error(`Workspace cwd is not registered for console '${sessionId}'.`);
165
+ }
166
+ return workspaceDir;
167
+ }
168
+ }
169
+ exports.XchangeService = XchangeService;
@@ -55,8 +55,9 @@ class HumanApprovalOrchestrator {
55
55
  session_id: input.session_id,
56
56
  });
57
57
  const binding = await this.bindingStore.getBinding(resolved.sessionId);
58
- if (!binding) {
59
- throw new Error("Session is not linked to Telegram. Call create_session_pair_code first.");
58
+ const canUseGatewayProxy = Boolean(this.config.distributed.gatewayPublicUrl);
59
+ if (!binding && !canUseGatewayProxy) {
60
+ throw new Error("Session is not available through the gateway console registry yet. Open /menu in the gateway bot and select the console first.");
60
61
  }
61
62
  const session = await this.sessionStore.getSession(resolved.sessionId);
62
63
  const merged = mergeSavedContext(input, session);
@@ -88,8 +89,8 @@ class HumanApprovalOrchestrator {
88
89
  ...(input.fallback_if_timeout
89
90
  ? { fallbackIfTimeout: (0, redactSecrets_1.redactSecrets)(input.fallback_if_timeout) }
90
91
  : {}),
91
- telegramChatId: binding.telegramChatId,
92
- telegramUserId: binding.telegramUserId,
92
+ telegramChatId: binding?.telegramChatId ?? 0,
93
+ telegramUserId: binding?.telegramUserId ?? 0,
93
94
  queuedAt: new Date().toISOString(),
94
95
  status: this.config.mode === "queue" ? "queued" : "active",
95
96
  };