@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
package/dist/cli.js CHANGED
@@ -9,25 +9,16 @@ const node_path_1 = __importDefault(require("node:path"));
9
9
  const node_child_process_1 = require("node:child_process");
10
10
  const node_net_1 = __importDefault(require("node:net"));
11
11
  const dotenv_1 = require("dotenv");
12
+ const ioredis_1 = __importDefault(require("ioredis"));
12
13
  const picocolors_1 = __importDefault(require("picocolors"));
13
14
  const ws_1 = __importDefault(require("ws"));
15
+ const codexPluginInstaller_1 = require("./codexPluginInstaller");
14
16
  const versionHandshake_1 = require("./services/features/telegram-mcp/src/shared/lib/version/versionHandshake");
17
+ const projectIdentity_1 = require("./services/features/telegram-mcp/src/shared/lib/project-identity/projectIdentity");
18
+ const foregroundTerminalRuntime_1 = require("./services/features/telegram-mcp/src/features/foreground-terminal/model/foregroundTerminalRuntime");
15
19
  const distDir = __dirname;
16
20
  const packageRoot = node_path_1.default.resolve(distDir, "..");
17
21
  const cliPackageVersion = (0, versionHandshake_1.getTellyMcpPackageVersion)(__dirname);
18
- function getTmuxStatus() {
19
- const result = (0, node_child_process_1.spawnSync)("tmux", ["-V"], {
20
- encoding: "utf8",
21
- stdio: ["ignore", "pipe", "ignore"],
22
- });
23
- if (result.status === 0) {
24
- return {
25
- found: true,
26
- version: (result.stdout || "tmux").trim(),
27
- };
28
- }
29
- return { found: false };
30
- }
31
22
  function printBanner(title, subtitle) {
32
23
  process.stdout.write(`${picocolors_1.default.bold(picocolors_1.default.cyan("TellyMCP"))} ${picocolors_1.default.bold(picocolors_1.default.white(`v${cliPackageVersion}`))} ${picocolors_1.default.dim(title)}\n`);
33
24
  if (subtitle) {
@@ -42,16 +33,6 @@ function printSection(title, lines) {
42
33
  }
43
34
  process.stdout.write("\n");
44
35
  }
45
- function getTmuxInstallHints() {
46
- if (process.platform === "darwin") {
47
- return ["brew install tmux"];
48
- }
49
- return [
50
- "Ubuntu/Debian: sudo apt install tmux",
51
- "Fedora/RHEL: sudo dnf install tmux",
52
- "Arch: sudo pacman -S tmux",
53
- ];
54
- }
55
36
  async function getPlaywrightBrowserStatus(browserEnabled) {
56
37
  if (!browserEnabled) {
57
38
  return { enabled: false };
@@ -81,14 +62,18 @@ async function getPlaywrightBrowserStatus(browserEnabled) {
81
62
  }
82
63
  }
83
64
  function printHelp() {
84
- const tmux = getTmuxStatus();
85
65
  printBanner("CLI", "Telegram control plane for MCP-connected coding agents");
86
66
  printSection("Usage", [
87
67
  " tellymcp init <client|gateway|both> [directory]",
88
68
  " tellymcp run [--env <file>]",
89
69
  " tellymcp run --env=<file>",
70
+ " tellymcp run --env .env-client -s backendDev",
71
+ " tellymcp run # if .mcpsession.json already stores env_file + local_session_id",
90
72
  " tellymcp doctor [--env <file>]",
73
+ " tellymcp system-prune [--env <file>] --yes",
91
74
  " tellymcp browser install",
75
+ " tellymcp codex-plugin install",
76
+ " tellymcp codex-plugin status",
92
77
  " tellymcp mcp [--url <url>] [--bearer <token>] [--format claude|legacy]",
93
78
  " tellymcp help",
94
79
  ]);
@@ -97,24 +82,94 @@ function printHelp() {
97
82
  " tellymcp init gateway ./gateway-node",
98
83
  " tellymcp run",
99
84
  " tellymcp run --env .env.client",
85
+ " tellymcp run --env .env-client -s backendDev",
86
+ " tellymcp run # reuses .mcpsession.json in the current workspace",
100
87
  " tellymcp doctor --env .env.client",
88
+ " tellymcp system-prune --env .env.gateway --yes",
101
89
  " tellymcp browser install",
90
+ " tellymcp codex-plugin install",
91
+ " tellymcp codex-plugin status",
102
92
  " tellymcp mcp --help",
103
93
  ]);
104
- if (tmux.found) {
105
- printSection("tmux", [
106
- `${picocolors_1.default.green(" OK")} ${tmux.version}`,
107
- " Live view and session nudges are available.",
108
- ]);
94
+ printSection("terminal", [
95
+ `${picocolors_1.default.green(" OK")} built-in PTY runtime`,
96
+ " Live view, session nudges and browser flows use the built-in terminal runtime.",
97
+ ]);
98
+ }
99
+ function resolveMarkerEnvPath(rawPath, cwd) {
100
+ return node_path_1.default.isAbsolute(rawPath) ? rawPath : node_path_1.default.resolve(cwd, rawPath);
101
+ }
102
+ function formatMarkerEnvPath(envPath, cwd) {
103
+ const resolvedCwd = node_path_1.default.resolve(cwd);
104
+ const resolvedEnvPath = node_path_1.default.resolve(envPath);
105
+ const relativePath = node_path_1.default.relative(resolvedCwd, resolvedEnvPath);
106
+ return relativePath && !relativePath.startsWith("..") && !node_path_1.default.isAbsolute(relativePath)
107
+ ? relativePath
108
+ : resolvedEnvPath;
109
+ }
110
+ function getSessionMarkerForCwd(cwd) {
111
+ return (0, projectIdentity_1.readSessionMarkerState)(cwd);
112
+ }
113
+ function resolveCliSessionDefaults(input) {
114
+ return (0, projectIdentity_1.resolveSessionDefaultsForCwd)({
115
+ cwd: process.cwd(),
116
+ ...(input.sessionId?.trim() ? { session_id: input.sessionId.trim() } : {}),
117
+ ...(input.sessionLabel?.trim()
118
+ ? { session_label: input.sessionLabel.trim() }
119
+ : {}),
120
+ });
121
+ }
122
+ function persistCliSessionMarker(input) {
123
+ const current = getSessionMarkerForCwd(input.cwd);
124
+ const resolved = resolveCliSessionDefaults({
125
+ envPath: input.envPath,
126
+ sessionId: input.sessionId,
127
+ sessionLabel: input.sessionLabel,
128
+ }) ?? null;
129
+ const localSessionId = input.sessionId?.trim() || current?.localSessionId || resolved?.sessionId;
130
+ if (!localSessionId) {
131
+ return;
109
132
  }
110
- else {
111
- printSection("tmux", [
112
- `${picocolors_1.default.yellow(" WARN")} tmux was not found on this system.`,
113
- " TellyMCP will still run, but Live view and nudges will be limited.",
114
- " Install examples:",
115
- ...getTmuxInstallHints().map((line) => ` ${line}`),
116
- ]);
133
+ (0, projectIdentity_1.writeSessionMarkerState)({
134
+ cwd: input.cwd,
135
+ localSessionId,
136
+ ...(input.sessionLabel?.trim()
137
+ ? { sessionLabel: input.sessionLabel.trim() }
138
+ : current?.sessionLabel
139
+ ? { sessionLabel: current.sessionLabel }
140
+ : resolved?.sessionLabel
141
+ ? { sessionLabel: resolved.sessionLabel }
142
+ : {}),
143
+ envFile: formatMarkerEnvPath(input.envPath, input.cwd),
144
+ });
145
+ }
146
+ function loadCliEnv(args) {
147
+ const envPath = resolveRunEnvPath(args);
148
+ const marker = getSessionMarkerForCwd(process.cwd());
149
+ const explicitSessionOverride = readFlagValue(args, "-s") ?? readFlagValue(args, "--session");
150
+ const sessionOverride = explicitSessionOverride ?? marker?.localSessionId ?? null;
151
+ const sessionLabelOverride = explicitSessionOverride
152
+ ? explicitSessionOverride
153
+ : marker?.sessionLabel ?? sessionOverride ?? null;
154
+ if (!(0, node_fs_1.existsSync)(envPath)) {
155
+ fail(`Missing env file: ${envPath}`);
117
156
  }
157
+ const envContent = (0, node_fs_1.readFileSync)(envPath, "utf8");
158
+ const fileEnv = (0, dotenv_1.parse)(envContent);
159
+ const runtimeEnvOverrides = Object.fromEntries(Object.entries(process.env).filter(([, value]) => typeof value === "string"));
160
+ return {
161
+ envPath,
162
+ parsed: {
163
+ ...fileEnv,
164
+ ...runtimeEnvOverrides,
165
+ ...(sessionOverride
166
+ ? {
167
+ TELLYMCP_SESSION_ID: sessionOverride,
168
+ TELLYMCP_SESSION_LABEL: sessionLabelOverride || sessionOverride,
169
+ }
170
+ : {}),
171
+ },
172
+ };
118
173
  }
119
174
  function printMcpHelp() {
120
175
  printBanner("MCP helper", "Prints JSON snippets for Claude, Codex, and other MCP clients");
@@ -130,10 +185,11 @@ function printMcpHelp() {
130
185
  " Copy the printed JSON into your agent's MCP config.",
131
186
  ]);
132
187
  printSection("What you need", [
133
- " 1. tmux must be installed on the machine where tellymcp runs.",
188
+ " 1. Terminal live view and nudges use the built-in PTY runtime.",
134
189
  " 2. Your MCP endpoint depends on mode:",
135
190
  " - client/local: http://127.0.0.1:8787/mcp",
136
191
  " - gateway/both behind nginx: https://your-host.example/api/mcp",
192
+ " 3. For local and remote agents, use the MCP HTTP endpoint exposed by tellymcp run.",
137
193
  ]);
138
194
  printSection("Claude / modern streamable-http example", [
139
195
  "{",
@@ -189,6 +245,18 @@ function printBrowserHelp() {
189
245
  " Avoids generic npx warnings about missing local project dependencies.",
190
246
  ]);
191
247
  }
248
+ function printCodexPluginHelp() {
249
+ printBanner("codex plugin", "Install or inspect the bundled Codex workflow plugin");
250
+ printSection("Usage", [
251
+ " tellymcp codex-plugin install",
252
+ " tellymcp codex-plugin status",
253
+ ]);
254
+ printSection("What this command does", [
255
+ " Copies the bundled telly-workflows plugin from the package into a managed local Codex plugin directory.",
256
+ " Ensures the local personal marketplace entry points at that managed plugin source.",
257
+ " If the Codex CLI is installed, checks whether the installed plugin version matches the bundled package version and installs or updates it when needed.",
258
+ ]);
259
+ }
192
260
  function fail(message) {
193
261
  process.stderr.write(`${message}\n`);
194
262
  process.exit(1);
@@ -240,6 +308,7 @@ function initWorkspace(mode, directoryArg) {
240
308
  }
241
309
  function resolveRunEnvPath(args) {
242
310
  const [firstArg, secondArg] = args;
311
+ const marker = getSessionMarkerForCwd(process.cwd());
243
312
  if (firstArg?.startsWith("--env=")) {
244
313
  const value = firstArg.slice("--env=".length).trim();
245
314
  if (!value) {
@@ -253,6 +322,9 @@ function resolveRunEnvPath(args) {
253
322
  }
254
323
  return node_path_1.default.resolve(process.cwd(), secondArg);
255
324
  }
325
+ if (marker?.envFile?.trim()) {
326
+ return resolveMarkerEnvPath(marker.envFile.trim(), process.cwd());
327
+ }
256
328
  return node_path_1.default.resolve(process.cwd(), ".env");
257
329
  }
258
330
  function joinUrlPath(left, right) {
@@ -433,32 +505,13 @@ async function checkWebSocketUrl(url, timeoutMs = 3000) {
433
505
  });
434
506
  }
435
507
  async function runDoctor(args) {
436
- const envPath = resolveRunEnvPath(args);
437
- const tmux = getTmuxStatus();
508
+ const { envPath, parsed } = loadCliEnv(args);
438
509
  printBanner("doctor", "Local installation diagnostics");
439
- if (tmux.found) {
440
- printSection("tmux", [
441
- `${picocolors_1.default.green(" OK")} ${tmux.version}`,
442
- " Live view and session nudges should work.",
443
- ]);
444
- }
445
- else {
446
- printSection("tmux", [
447
- `${picocolors_1.default.yellow(" WARN")} tmux was not found.`,
448
- " TellyMCP will still run, but Live view and nudges will be limited.",
449
- " Install examples:",
450
- ...getTmuxInstallHints().map((line) => ` ${line}`),
451
- ]);
452
- }
453
- if (!(0, node_fs_1.existsSync)(envPath)) {
454
- printSection("env", [
455
- `${picocolors_1.default.red(" ERROR")} Missing env file: ${envPath}`,
456
- " Run 'tellymcp init client' or pass --env <file>.",
457
- ]);
458
- return;
459
- }
460
- const envContent = (0, node_fs_1.readFileSync)(envPath, "utf8");
461
- const parsed = (0, dotenv_1.parse)(envContent);
510
+ printSection("terminal", [
511
+ `${picocolors_1.default.green(" OK")} built-in PTY runtime`,
512
+ ` shell: ${parsed.TERMINAL_SHELL?.trim() || process.env.SHELL || "bash"}`,
513
+ ` size: ${parsed.TERMINAL_COLS?.trim() || "120"}x${parsed.TERMINAL_ROWS?.trim() || "40"}`,
514
+ ]);
462
515
  const mode = (parsed.DISTRIBUTED_MODE || "client").trim();
463
516
  const httpHost = (parsed.MCP_HTTP_HOST || "0.0.0.0").trim();
464
517
  const httpPort = mode === "gateway" || mode === "both"
@@ -488,6 +541,10 @@ async function runDoctor(args) {
488
541
  printSection("env", [
489
542
  `${picocolors_1.default.green(" OK")} ${envPath}`,
490
543
  ` mode: ${mode}`,
544
+ " terminal transport: built-in PTY",
545
+ ...(parsed.TELLYMCP_SESSION_ID
546
+ ? [` session override: ${parsed.TELLYMCP_SESSION_ID}`]
547
+ : []),
491
548
  ` bind: http://${httpHost}:${httpPort}`,
492
549
  ` mcp: http://${httpHost}:${httpPort}${mcpUrlPath}`,
493
550
  ` web: http://${httpHost}:${httpPort}${webappUrlPath}`,
@@ -624,6 +681,119 @@ async function runDoctor(args) {
624
681
  ]);
625
682
  }
626
683
  }
684
+ function hasFlag(args, flagName) {
685
+ return args.includes(flagName);
686
+ }
687
+ async function runSystemPrune(args) {
688
+ const confirmed = hasFlag(args, "--yes");
689
+ if (!confirmed) {
690
+ fail("system-prune is destructive. Re-run with --yes.");
691
+ }
692
+ const filteredArgs = args.filter((arg) => arg !== "--yes");
693
+ const { envPath, parsed } = loadCliEnv(filteredArgs);
694
+ const mode = (parsed.DISTRIBUTED_MODE || "client").trim();
695
+ const redisHost = (parsed.REDIS_HOST || "127.0.0.1").trim();
696
+ const redisPort = Number(parsed.REDIS_PORT || 6379);
697
+ const redisDb = Number(parsed.REDIS_DB || 1);
698
+ const redisUsername = parsed.REDIS_USERNAME?.trim();
699
+ const redisPassword = parsed.REDIS_PASSWORD?.trim();
700
+ const dbHost = parsed.DB_HOST?.trim();
701
+ const dbPort = Number(parsed.DB_PORT || 5432);
702
+ const dbUser = parsed.DB_USER?.trim();
703
+ const dbPassword = parsed.DB_PASSWORD?.trim();
704
+ const dbName = parsed.DB_NAME?.trim();
705
+ const dbSchema = (parsed.DB_SCHEME || "mcp").trim();
706
+ const xchangeDir = node_path_1.default.resolve(process.cwd(), parsed.MCP_XCHANGE_DIR || ".mcp-xchange");
707
+ const sessionMarkerPath = node_path_1.default.resolve(process.cwd(), ".mcpsession.json");
708
+ const sqliteDbPath = node_path_1.default.join(xchangeDir, "xchange.sqlite3");
709
+ printBanner("system-prune", "Destroying local and gateway state");
710
+ printSection("Target", [
711
+ ` env: ${envPath}`,
712
+ ` mode: ${mode}`,
713
+ ` redis: ${redisHost}:${redisPort}/${redisDb}`,
714
+ ...(dbHost && dbUser && dbName
715
+ ? [` postgres: ${dbHost}:${dbPort}/${dbName} schema ${dbSchema}`]
716
+ : [` postgres: ${picocolors_1.default.dim("skipped (not configured)")}`]),
717
+ ` xchange dir: ${xchangeDir}`,
718
+ ` session marker: ${sessionMarkerPath}`,
719
+ ]);
720
+ const redis = new ioredis_1.default({
721
+ host: redisHost,
722
+ port: redisPort,
723
+ db: redisDb,
724
+ ...(redisUsername ? { username: redisUsername } : {}),
725
+ ...(redisPassword ? { password: redisPassword } : {}),
726
+ maxRetriesPerRequest: 1,
727
+ enableReadyCheck: true,
728
+ });
729
+ let deletedRedisKeys = 0;
730
+ try {
731
+ let cursor = "0";
732
+ do {
733
+ const [nextCursor, keys] = await redis.scan(cursor, "MATCH", "telegram-mcp:*", "COUNT", 500);
734
+ cursor = nextCursor;
735
+ if (keys.length > 0) {
736
+ deletedRedisKeys += await redis.del(...keys);
737
+ }
738
+ } while (cursor !== "0");
739
+ }
740
+ finally {
741
+ redis.disconnect();
742
+ }
743
+ let truncatedTables = [];
744
+ if (dbHost && dbUser && dbName) {
745
+ const pgModule = (await import("pg"));
746
+ const { Client: PgClient } = pgModule;
747
+ const pg = new PgClient({
748
+ host: dbHost,
749
+ port: dbPort,
750
+ user: dbUser,
751
+ password: dbPassword,
752
+ database: dbName,
753
+ });
754
+ try {
755
+ await pg.connect();
756
+ truncatedTables = [
757
+ "gateway_deliveries",
758
+ "gateway_message_artifacts",
759
+ "gateway_messages",
760
+ "gateway_session_links",
761
+ "gateway_sessions",
762
+ "gateway_project_members",
763
+ "gateway_projects",
764
+ "gateway_clients",
765
+ ];
766
+ await pg.query(`TRUNCATE TABLE ${truncatedTables
767
+ .map((table) => `"${dbSchema}"."${table}"`)
768
+ .join(", ")} RESTART IDENTITY CASCADE`);
769
+ }
770
+ finally {
771
+ await pg.end();
772
+ }
773
+ }
774
+ let deletedLocalArtifacts = 0;
775
+ if ((0, node_fs_1.existsSync)(sqliteDbPath)) {
776
+ (0, node_fs_1.rmSync)(sqliteDbPath, { force: true });
777
+ deletedLocalArtifacts += 1;
778
+ }
779
+ if ((0, node_fs_1.existsSync)(xchangeDir)) {
780
+ (0, node_fs_1.rmSync)(xchangeDir, { recursive: true, force: true });
781
+ deletedLocalArtifacts += 1;
782
+ }
783
+ if ((0, node_fs_1.existsSync)(sessionMarkerPath)) {
784
+ (0, node_fs_1.rmSync)(sessionMarkerPath, { force: true });
785
+ deletedLocalArtifacts += 1;
786
+ }
787
+ printSection("Result", [
788
+ `${picocolors_1.default.green(" OK")} redis keys deleted: ${deletedRedisKeys}`,
789
+ ...(truncatedTables.length > 0
790
+ ? [
791
+ `${picocolors_1.default.green(" OK")} postgres tables truncated: ${truncatedTables.join(", ")}`,
792
+ ]
793
+ : [`${picocolors_1.default.dim(" SKIP")} postgres tables: not configured`]),
794
+ `${picocolors_1.default.green(" OK")} local artifacts removed: ${deletedLocalArtifacts}`,
795
+ ]);
796
+ }
627
797
  function runBrowserCommand(args) {
628
798
  const [subcommand] = args;
629
799
  if (!subcommand || subcommand === "--help" || subcommand === "-h") {
@@ -651,10 +821,78 @@ function runBrowserCommand(args) {
651
821
  process.exit(code ?? 0);
652
822
  });
653
823
  }
654
- function runRuntime(args) {
655
- const envPath = resolveRunEnvPath(args);
656
- if (!(0, node_fs_1.existsSync)(envPath)) {
657
- fail(`Missing ${envPath}. Run 'tellymcp init <client|gateway|both>' first or pass --env <file>.`);
824
+ function runCodexPluginCommand(args) {
825
+ const [subcommand] = args;
826
+ if (!subcommand || subcommand === "--help" || subcommand === "-h") {
827
+ printCodexPluginHelp();
828
+ return;
829
+ }
830
+ if (subcommand !== "install" && subcommand !== "status") {
831
+ fail("Supported codex-plugin subcommands: install, status");
832
+ }
833
+ if (subcommand === "status") {
834
+ const status = (0, codexPluginInstaller_1.getCodexPluginStatus)(packageRoot);
835
+ printBanner("codex plugin status", "Bundled telly-workflows plugin");
836
+ printSection("plugin", [
837
+ ` name: ${status.pluginName}`,
838
+ ` bundled version: ${status.bundledVersion}`,
839
+ ` source version: ${status.sourceVersion ?? "not synced yet"}`,
840
+ ` installed version: ${status.installedVersion ?? "not installed"}`,
841
+ ` codex cli: ${status.codexAvailable ? "detected" : "not detected"}`,
842
+ ` marketplace registered: ${status.marketplaceRegistered ? "yes" : "no"}`,
843
+ ` up to date: ${status.upToDate ? "yes" : "no"}`,
844
+ ]);
845
+ printSection("paths", [
846
+ ` bundled: ${status.bundledPluginDir}`,
847
+ ` managed: ${status.managedPluginDir}`,
848
+ ` marketplace root: ${status.marketplaceRoot}`,
849
+ ` marketplace file: ${status.marketplaceFile}`,
850
+ ]);
851
+ return;
852
+ }
853
+ const status = (0, codexPluginInstaller_1.installCodexPlugin)(packageRoot);
854
+ printBanner("codex plugin install", "Bundled telly-workflows plugin");
855
+ printSection("result", [
856
+ ` plugin: ${status.pluginName}@${status.marketplaceName}`,
857
+ ` bundled version: ${status.bundledVersion}`,
858
+ ` source version: ${status.sourceVersion ?? "unknown"}`,
859
+ ` installed version: ${status.installedVersion ?? "not installed"}`,
860
+ ` marketplace registered: ${status.marketplaceRegistered ? "yes" : "no"}`,
861
+ ` up to date: ${status.upToDate ? "yes" : "no"}`,
862
+ ]);
863
+ printSection("paths", [
864
+ ` managed plugin dir: ${status.managedPluginDir}`,
865
+ ` marketplace file: ${status.marketplaceFile}`,
866
+ ]);
867
+ if (!status.codexAvailable) {
868
+ printSection("next", [
869
+ " Codex CLI was not detected on this machine.",
870
+ " The plugin source and marketplace manifest were synced locally.",
871
+ " Install Codex, then rerun: tellymcp codex-plugin install",
872
+ ]);
873
+ }
874
+ }
875
+ async function runRuntime(args) {
876
+ const { envPath, parsed } = loadCliEnv(args);
877
+ if (parsed.TELLYMCP_SESSION_ID) {
878
+ process.env.TELLYMCP_SESSION_ID = parsed.TELLYMCP_SESSION_ID;
879
+ }
880
+ if (parsed.TELLYMCP_SESSION_LABEL) {
881
+ process.env.TELLYMCP_SESSION_LABEL = parsed.TELLYMCP_SESSION_LABEL;
882
+ }
883
+ persistCliSessionMarker({
884
+ cwd: process.cwd(),
885
+ envPath,
886
+ sessionId: parsed.TELLYMCP_SESSION_ID,
887
+ sessionLabel: parsed.TELLYMCP_SESSION_LABEL,
888
+ });
889
+ if ((0, foregroundTerminalRuntime_1.isForegroundPtyClientMode)(parsed)) {
890
+ await (0, foregroundTerminalRuntime_1.runForegroundPtyRuntime)({
891
+ envPath,
892
+ packageRoot,
893
+ printBanner,
894
+ });
895
+ return;
658
896
  }
659
897
  const runnerPath = node_path_1.default.join(packageRoot, "node_modules", "moleculer", "bin", "moleculer-runner.js");
660
898
  const configPath = node_path_1.default.join(packageRoot, "dist", "moleculer.config.js");
@@ -669,13 +907,7 @@ function runRuntime(args) {
669
907
  fail(`Missing compiled services: ${servicesPath}`);
670
908
  }
671
909
  printBanner("run", "Starting packaged runtime");
672
- const tmux = getTmuxStatus();
673
- if (tmux.found) {
674
- process.stdout.write(`${picocolors_1.default.green("tmux detected:")} ${tmux.version}\n`);
675
- }
676
- else {
677
- process.stdout.write(`${picocolors_1.default.yellow("tmux not found.")} Live view and nudges may be limited.\n`);
678
- }
910
+ process.stdout.write(`${picocolors_1.default.green("terminal runtime:")} built-in PTY\n`);
679
911
  process.stdout.write(`${picocolors_1.default.cyan("Using env:")} ${envPath}\n\n`);
680
912
  const child = (0, node_child_process_1.spawn)(process.execPath, [
681
913
  runnerPath,
@@ -691,6 +923,12 @@ function runRuntime(args) {
691
923
  ...process.env,
692
924
  ENV_FILE: envPath,
693
925
  TELLYMCP_STANDALONE_HTTP: "true",
926
+ ...(parsed.TELLYMCP_SESSION_ID
927
+ ? { TELLYMCP_SESSION_ID: parsed.TELLYMCP_SESSION_ID }
928
+ : {}),
929
+ ...(parsed.TELLYMCP_SESSION_LABEL
930
+ ? { TELLYMCP_SESSION_LABEL: parsed.TELLYMCP_SESSION_LABEL }
931
+ : {}),
694
932
  },
695
933
  });
696
934
  child.on("exit", (code, signal) => {
@@ -703,7 +941,8 @@ function runRuntime(args) {
703
941
  }
704
942
  async function main(argv) {
705
943
  const [rawCommand, firstArg, secondArg] = argv;
706
- const command = rawCommand === "init" || rawCommand === "run" || rawCommand === "help" || rawCommand === "mcp" || rawCommand === "doctor" || rawCommand === "browser"
944
+ const command = rawCommand === "init" || rawCommand === "run" || rawCommand === "help" || rawCommand === "mcp" || rawCommand === "doctor" || rawCommand === "browser" || rawCommand === "system-prune"
945
+ || rawCommand === "codex-plugin"
707
946
  ? rawCommand
708
947
  : "help";
709
948
  if (command === "help" || !rawCommand || rawCommand === "--help" || rawCommand === "-h") {
@@ -726,6 +965,14 @@ async function main(argv) {
726
965
  runBrowserCommand(argv.slice(1));
727
966
  return;
728
967
  }
729
- runRuntime(argv.slice(1));
968
+ if (command === "codex-plugin") {
969
+ runCodexPluginCommand(argv.slice(1));
970
+ return;
971
+ }
972
+ if (command === "system-prune") {
973
+ await runSystemPrune(argv.slice(1));
974
+ return;
975
+ }
976
+ await runRuntime(argv.slice(1));
730
977
  }
731
978
  void main(process.argv.slice(2));