@0xmaxma/claude-gateway 1.3.4 → 1.3.6

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 (55) hide show
  1. package/README.md +1 -1
  2. package/config.template.json +9 -7
  3. package/dist/agent/runner.d.ts +20 -0
  4. package/dist/agent/runner.d.ts.map +1 -1
  5. package/dist/agent/runner.js +94 -1
  6. package/dist/agent/runner.js.map +1 -1
  7. package/dist/api/gateway-router.d.ts +14 -0
  8. package/dist/api/gateway-router.d.ts.map +1 -1
  9. package/dist/api/gateway-router.js +279 -7
  10. package/dist/api/gateway-router.js.map +1 -1
  11. package/dist/discord/receiver.d.ts +1 -0
  12. package/dist/discord/receiver.d.ts.map +1 -1
  13. package/dist/discord/receiver.js +7 -1
  14. package/dist/discord/receiver.js.map +1 -1
  15. package/dist/session/process.d.ts +8 -0
  16. package/dist/session/process.d.ts.map +1 -1
  17. package/dist/session/process.js +34 -0
  18. package/dist/session/process.js.map +1 -1
  19. package/dist/shell/claude-pty-shell.js +211 -4
  20. package/dist/shell/claude-pty-shell.js.map +1 -1
  21. package/dist/shell/emitter.d.ts +13 -0
  22. package/dist/shell/emitter.d.ts.map +1 -1
  23. package/dist/shell/emitter.js +16 -0
  24. package/dist/shell/emitter.js.map +1 -1
  25. package/dist/shell/menu-cancel.d.ts +50 -0
  26. package/dist/shell/menu-cancel.d.ts.map +1 -0
  27. package/dist/shell/menu-cancel.js +62 -0
  28. package/dist/shell/menu-cancel.js.map +1 -0
  29. package/dist/shell/pty-serialize.d.ts +23 -0
  30. package/dist/shell/pty-serialize.d.ts.map +1 -0
  31. package/dist/shell/pty-serialize.js +131 -0
  32. package/dist/shell/pty-serialize.js.map +1 -0
  33. package/dist/shell/pty-stream-registry.d.ts +59 -0
  34. package/dist/shell/pty-stream-registry.d.ts.map +1 -0
  35. package/dist/shell/pty-stream-registry.js +279 -0
  36. package/dist/shell/pty-stream-registry.js.map +1 -0
  37. package/dist/shell/screen.d.ts +43 -0
  38. package/dist/shell/screen.d.ts.map +1 -1
  39. package/dist/shell/screen.js +91 -1
  40. package/dist/shell/screen.js.map +1 -1
  41. package/dist/telegram/receiver.d.ts +1 -0
  42. package/dist/telegram/receiver.d.ts.map +1 -1
  43. package/dist/telegram/receiver.js +7 -1
  44. package/dist/telegram/receiver.js.map +1 -1
  45. package/dist/ui/web-ui.d.ts +2 -2
  46. package/dist/ui/web-ui.d.ts.map +1 -1
  47. package/dist/ui/web-ui.js +682 -114
  48. package/dist/ui/web-ui.js.map +1 -1
  49. package/mcp/tools/discord/module.ts +88 -1
  50. package/mcp/tools/discord/outbound.ts +36 -0
  51. package/mcp/tools/discord/types.ts +2 -0
  52. package/mcp/tools/telegram/menu-parser.ts +37 -0
  53. package/mcp/tools/telegram/receiver-server.ts +83 -0
  54. package/mcp/tools/telegram/typing.ts +7 -1
  55. package/package.json +4 -2
package/README.md CHANGED
@@ -29,7 +29,7 @@ A self-hosted multi-agent gateway for Claude Code. Connect Claude agents to Tele
29
29
  - **App Store** — install, update, and host Docker-compose apps on the gateway; apps get a reverse proxy at `/app/:name/:portName/*`, optional Unix socket bridge for host scripts, and optional AI agent injection
30
30
  - **Self-update API** — check for newer versions of `claude-gateway` and `claude-code` and trigger an update via a single API call; no SSH or shell access needed
31
31
  - **Session persistence** — conversation history saved and restored across restarts
32
- - **PTY backend** — optional interactive pseudo-terminal backend (`gateway.headless: false`) for tools that require a real TTY; uses `TranscriptTailer` for reliable output instead of ANSI parsing; app-agents always stay headless
32
+ - **PTY shell (wrap-shell mode)** — optional interactive pseudo-terminal backend (`gateway.headless: false`) for tools that require a real TTY; includes a live browser viewer (xterm.js) and a `/api/v1/sessions/:sessionId/screen` endpoint that returns the visible screen as plain text — agents can poll it to detect hang states, menus, or unexpected output without parsing ANSI escape codes; app-agents always stay headless
33
33
 
34
34
  ---
35
35
 
@@ -10,17 +10,19 @@
10
10
  "claude.dangerouslySkipPermissions"
11
11
  ]
12
12
  },
13
- "configVersion": "1.0.8",
13
+ "configVersion": "1.0.9",
14
14
  "gateway": {
15
15
  "logDir": "~/.claude-gateway/logs",
16
16
  "timezone": "Asia/Bangkok",
17
17
  "models": [
18
- { "id": "claude-fable-5", "label": "Fable 5", "alias": "fable", "contextWindow": 1000000 },
19
- { "id": "claude-opus-4-8", "label": "Opus 4.8", "alias": "opus", "contextWindow": 1000000 },
20
- { "id": "claude-opus-4-7", "label": "Opus 4.7", "alias": "opus47", "contextWindow": 1000000 },
21
- { "id": "claude-opus-4-6", "label": "Opus 4.6", "alias": "opus46", "contextWindow": 1000000 },
22
- { "id": "claude-sonnet-4-6", "label": "Sonnet 4.6", "alias": "sonnet", "contextWindow": 1000000 },
23
- { "id": "claude-haiku-4-5-20251001", "label": "Haiku 4.5", "alias": "haiku", "contextWindow": 200000 }
18
+ { "id": "claude-fable-5", "label": "Fable 5", "alias": "fable", "contextWindow": 1000000 },
19
+ { "id": "claude-opus-4-8[1m]", "label": "Opus 4.8 (1M)", "alias": "opus[1m]", "contextWindow": 1000000 },
20
+ { "id": "claude-sonnet-4-6[1m]", "label": "Sonnet 4.6 (1M)", "alias": "sonnet[1m]", "contextWindow": 1000000 },
21
+ { "id": "claude-opus-4-8", "label": "Opus 4.8", "alias": "opus", "contextWindow": 200000 },
22
+ { "id": "claude-opus-4-7", "label": "Opus 4.7", "alias": "opus47", "contextWindow": 200000 },
23
+ { "id": "claude-opus-4-6", "label": "Opus 4.6", "alias": "opus46", "contextWindow": 200000 },
24
+ { "id": "claude-sonnet-4-6", "label": "Sonnet 4.6", "alias": "sonnet", "contextWindow": 200000 },
25
+ { "id": "claude-haiku-4-5-20251001", "label": "Haiku 4.5", "alias": "haiku", "contextWindow": 200000 }
24
26
  ],
25
27
  "api": {
26
28
  "keys": [
@@ -29,6 +29,8 @@ export declare class AgentRunner extends EventEmitter {
29
29
  private readonly sessionSpawnLocks;
30
30
  private readonly pendingImagePaths;
31
31
  private readonly pendingApiAttachments;
32
+ private readonly sessionHistory;
33
+ private readonly apiChatIds;
32
34
  private skillRegistry;
33
35
  private readonly configPath;
34
36
  private readonly historyDb;
@@ -133,6 +135,13 @@ export declare class AgentRunner extends EventEmitter {
133
135
  private writeTypingDone;
134
136
  private triggerSummaryAndRestart;
135
137
  private writeAutoForward;
138
+ /**
139
+ * Signal the channel receiver to render an interactive menu as native UI
140
+ * (inline buttons on Telegram/Discord). The receiver maps each option to a
141
+ * `choice:N` callback whose tap arrives back as a normal "N" message — the
142
+ * same as the user typing the number.
143
+ */
144
+ private writeMenuForward;
136
145
  private startIdleCleaner;
137
146
  start(): Promise<void>;
138
147
  updateAgentConfig(newConfig: AgentConfig): void;
@@ -145,6 +154,17 @@ export declare class AgentRunner extends EventEmitter {
145
154
  private _startCleanupScheduler;
146
155
  restart(): Promise<void>;
147
156
  isRunning(): boolean;
157
+ getSessionsSummary(): Array<{
158
+ chatId: string;
159
+ sessionId: string;
160
+ source: string;
161
+ mode: string;
162
+ model: string;
163
+ isRunning: boolean;
164
+ spawnedAt: number;
165
+ uptimeSec: number;
166
+ tokens: number;
167
+ }>;
148
168
  /**
149
169
  * Send a message to an API session and wait for the response.
150
170
  *
@@ -1 +1 @@
1
- {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/agent/runner.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/agent/runner.ts"],"names":[],"mappings":"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"}
@@ -128,6 +128,12 @@ class AgentRunner extends events_1.EventEmitter {
128
128
  this.pendingImagePaths = new Map();
129
129
  // Buffers attachment file paths registered via api_reply tool for the current API session turn.
130
130
  this.pendingApiAttachments = new Map();
131
+ // Session history ring-buffer (last 10 spawned, newest first)
132
+ this.sessionHistory = [];
133
+ // For API sessions the map key is the sessionId, so the real caller chatId
134
+ // (e.g. the app/agent identifier) is not captured at spawn. Record it here
135
+ // keyed by sessionId so the dashboard can show the actual chat id.
136
+ this.apiChatIds = new Map();
131
137
  // Skill registry for detecting /skill-name commands in user messages
132
138
  this.skillRegistry = { skills: new Map() };
133
139
  // Cancel function for the daily history cleanup timer
@@ -619,6 +625,9 @@ class AgentRunner extends events_1.EventEmitter {
619
625
  // Auto-forward result text to channel if agent didn't call reply tool.
620
626
  let replyCalled = false;
621
627
  let replyToolUseId = null; // track id to detect failed tool calls
628
+ // Set when an interactive-menu prompt was rendered to the channel this turn,
629
+ // so the result's plain-text auto-forward is skipped (no duplicate message).
630
+ let menuSentThisTurn = false;
622
631
  let typingDoneTimer = null;
623
632
  const TYPING_DONE_DELAY_MS = 3000;
624
633
  const replyToolName = source === 'discord' ? 'mcp__gateway__discord_reply' : 'mcp__gateway__telegram_reply';
@@ -667,6 +676,31 @@ class AgentRunner extends events_1.EventEmitter {
667
676
  }
668
677
  }
669
678
  }
679
+ // Interactive select menu blocking the PTY: render it as channel-native
680
+ // UI (inline buttons). This output handler only runs for Telegram/Discord
681
+ // sessions; API uses a separate path and falls back to the result text's
682
+ // numbered list (no buttons), as intended.
683
+ if (obj['type'] === 'system' && obj['subtype'] === 'menu_prompt') {
684
+ const promptText = typeof obj['prompt'] === 'string' ? obj['prompt'] : '';
685
+ const rawOptions = Array.isArray(obj['options']) ? obj['options'] : [];
686
+ const options = rawOptions
687
+ .map((o) => ({ label: typeof o?.label === 'string' ? o.label : '' }))
688
+ .filter((o) => o.label);
689
+ if (promptText && options.length) {
690
+ this.writeMenuForward(mapKey, promptText, options);
691
+ menuSentThisTurn = true;
692
+ // Persist the question to chat history so it's visible in the transcript.
693
+ const channelSrc = this.channelSourceMap.get(mapKey) ?? 'telegram';
694
+ this.historyDb.insertMessage({
695
+ chatId: `${channelSrc}-${mapKey}`,
696
+ sessionId: actualSessionId,
697
+ source: channelSrc,
698
+ role: 'assistant',
699
+ content: promptText,
700
+ ts: Date.now(),
701
+ });
702
+ }
703
+ }
670
704
  if (obj['type'] === 'result') {
671
705
  proc.setProcessing(false);
672
706
  // Telegram: accumulate image size via stat of local file (FIFO, one per turn)
@@ -699,7 +733,9 @@ class AgentRunner extends events_1.EventEmitter {
699
733
  // Suppress the corrupted-thinking 400: the session auto-respawns to recover,
700
734
  // so the raw API error must not reach the user's chat or the history DB.
701
735
  const isThinkingCorruption = obj['is_error'] === true && process_1.SessionProcess.isThinkingCorruptionError(resultText);
702
- if (resultText.trim() && !proc.queryMode && !replyCalled && !isThinkingCorruption) {
736
+ // Skip when a menu was rendered to buttons this turn — the result
737
+ // text is the same numbered list and would duplicate the menu message.
738
+ if (resultText.trim() && !proc.queryMode && !replyCalled && !isThinkingCorruption && !menuSentThisTurn) {
703
739
  const text = resultText.trim();
704
740
  const channelSrcForResult = this.channelSourceMap.get(mapKey) ?? 'telegram';
705
741
  // Persist assistant reply to permanent history DB
@@ -721,6 +757,7 @@ class AgentRunner extends events_1.EventEmitter {
721
757
  }
722
758
  replyCalled = false; // reset for next turn
723
759
  replyToolUseId = null;
760
+ menuSentThisTurn = false;
724
761
  // Delay typing done — agent may continue with more work
725
762
  typingDoneTimer = setTimeout(() => {
726
763
  this.writeTypingDone(mapKey);
@@ -775,6 +812,9 @@ class AgentRunner extends events_1.EventEmitter {
775
812
  });
776
813
  }
777
814
  this.sessions.set(mapKey, proc);
815
+ this.sessionHistory.unshift({ chatId: mapKey, sessionId: proc.sessionId, source: proc.source, mode: proc.backend, model: proc.model, spawnedAt: proc.spawnedAt });
816
+ if (this.sessionHistory.length > 10)
817
+ this.sessionHistory.length = 10;
778
818
  if (source === 'telegram' || source === 'discord') {
779
819
  this.channelSourceMap.set(mapKey, source);
780
820
  }
@@ -1112,6 +1152,27 @@ class AgentRunner extends events_1.EventEmitter {
1112
1152
  // Non-fatal
1113
1153
  }
1114
1154
  }
1155
+ /**
1156
+ * Signal the channel receiver to render an interactive menu as native UI
1157
+ * (inline buttons on Telegram/Discord). The receiver maps each option to a
1158
+ * `choice:N` callback whose tap arrives back as a normal "N" message — the
1159
+ * same as the user typing the number.
1160
+ */
1161
+ writeMenuForward(chatId, text, options) {
1162
+ const typingDir = this.getTypingDir(chatId);
1163
+ try {
1164
+ fs.mkdirSync(typingDir, { recursive: true });
1165
+ // Write atomically (tmp + rename): the receiver polls this directory every
1166
+ // second, so a non-atomic write could be read mid-flush as truncated JSON.
1167
+ const finalPath = path.join(typingDir, `${chatId}.menu`);
1168
+ const tmpPath = `${finalPath}.tmp`;
1169
+ fs.writeFileSync(tmpPath, JSON.stringify({ text, options }));
1170
+ fs.renameSync(tmpPath, finalPath);
1171
+ }
1172
+ catch {
1173
+ // Non-fatal — the result text still carries the numbered list as a fallback.
1174
+ }
1175
+ }
1115
1176
  startIdleCleaner() {
1116
1177
  this.idleCleanerTimer = setInterval(async () => {
1117
1178
  for (const [id, proc] of this.sessions) {
@@ -1220,6 +1281,34 @@ class AgentRunner extends events_1.EventEmitter {
1220
1281
  isRunning() {
1221
1282
  return this.receiver?.isRunning() ?? false;
1222
1283
  }
1284
+ getSessionsSummary() {
1285
+ const now = Date.now();
1286
+ // A single logical session can appear multiple times in the ring buffer: a
1287
+ // restart / model-switch / error-recovery respawn pushes a fresh entry with
1288
+ // the SAME sessionId but a new spawnedAt. History is newest-first (unshift),
1289
+ // so the first occurrence of a (source, sessionId, chatId) is the current
1290
+ // incarnation — collapse to it so the dashboard shows one row per session
1291
+ // instead of duplicating it.
1292
+ const seen = new Set();
1293
+ const out = [];
1294
+ for (const e of this.sessionHistory) {
1295
+ const dedupKey = `${e.source}:${e.sessionId}:${e.chatId}`;
1296
+ if (seen.has(dedupKey))
1297
+ continue;
1298
+ seen.add(dedupKey);
1299
+ const proc = this.sessions.get(e.chatId);
1300
+ // Running only when the live process IS this incarnation: a stale entry
1301
+ // from before a respawn must not borrow the new process's running state.
1302
+ const isRunning = !!proc && proc.spawnedAt === e.spawnedAt;
1303
+ // For API sessions the ring-buffer chatId equals the sessionId (the map key);
1304
+ // surface the real caller chatId instead when we have it.
1305
+ const chatId = e.source === 'api' ? (this.apiChatIds.get(e.sessionId) ?? e.chatId) : e.chatId;
1306
+ // Live context-window token usage from the running process (0 when stopped).
1307
+ const tokens = isRunning ? (proc?.totalTokens ?? 0) : 0;
1308
+ out.push({ ...e, chatId, isRunning, uptimeSec: Math.floor((now - e.spawnedAt) / 1000), tokens });
1309
+ }
1310
+ return out;
1311
+ }
1223
1312
  /**
1224
1313
  * Send a message to an API session and wait for the response.
1225
1314
  *
@@ -1239,6 +1328,7 @@ class AgentRunner extends events_1.EventEmitter {
1239
1328
  });
1240
1329
  // Use model from request body if provided, otherwise use agent default
1241
1330
  const session = await this.getOrSpawnSession(sessionId, 'api', undefined, opts.model);
1331
+ this.apiChatIds.set(sessionId, chatId);
1242
1332
  // Promote UI-uploaded files from staging to permanent per-session storage
1243
1333
  const finalMediaFiles = opts.mediaFiles?.length
1244
1334
  ? await promoteUiUploads(this.agentsBaseDir, this.agentConfig.id, sessionId, opts.mediaFiles, this.logger)
@@ -1411,6 +1501,7 @@ class AgentRunner extends events_1.EventEmitter {
1411
1501
  });
1412
1502
  // Use model from request body if provided, otherwise use agent default
1413
1503
  const session = await this.getOrSpawnSession(sessionId, 'api', undefined, opts.model);
1504
+ this.apiChatIds.set(sessionId, chatId);
1414
1505
  // Promote UI-uploaded files from staging to permanent per-session storage
1415
1506
  const finalMediaFilesStream = opts.mediaFiles?.length
1416
1507
  ? await promoteUiUploads(this.agentsBaseDir, this.agentConfig.id, sessionId, opts.mediaFiles, this.logger)
@@ -1631,6 +1722,8 @@ class AgentRunner extends events_1.EventEmitter {
1631
1722
  .filter((a) => a !== null);
1632
1723
  }
1633
1724
  cleanupApiSessionMediaDir(sessionId, source) {
1725
+ // Always evict the chat-id mapping — safe no-op for non-api sessions.
1726
+ this.apiChatIds.delete(sessionId);
1634
1727
  if (source !== 'api')
1635
1728
  return;
1636
1729
  const mediaDir = path.join(this.agentsBaseDir, this.agentConfig.id, 'media', `api-${sessionId}`);