@0xmaxma/claude-gateway 1.1.9 → 1.2.0

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 (67) hide show
  1. package/README.md +61 -1
  2. package/dist/agent/builtin-commands.d.ts +10 -0
  3. package/dist/agent/builtin-commands.d.ts.map +1 -0
  4. package/dist/agent/builtin-commands.js +38 -0
  5. package/dist/agent/builtin-commands.js.map +1 -0
  6. package/dist/agent/runner.d.ts +7 -5
  7. package/dist/agent/runner.d.ts.map +1 -1
  8. package/dist/agent/runner.js +56 -30
  9. package/dist/agent/runner.js.map +1 -1
  10. package/dist/agent/workspace-loader.d.ts.map +1 -1
  11. package/dist/agent/workspace-loader.js +9 -4
  12. package/dist/agent/workspace-loader.js.map +1 -1
  13. package/dist/api/apps-router.d.ts +7 -0
  14. package/dist/api/apps-router.d.ts.map +1 -0
  15. package/dist/api/apps-router.js +242 -0
  16. package/dist/api/apps-router.js.map +1 -0
  17. package/dist/api/gateway-router.d.ts +17 -1
  18. package/dist/api/gateway-router.d.ts.map +1 -1
  19. package/dist/api/gateway-router.js +171 -2
  20. package/dist/api/gateway-router.js.map +1 -1
  21. package/dist/api/router.d.ts.map +1 -1
  22. package/dist/api/router.js +385 -4
  23. package/dist/api/router.js.map +1 -1
  24. package/dist/apps/agent-manager.d.ts +76 -0
  25. package/dist/apps/agent-manager.d.ts.map +1 -0
  26. package/dist/apps/agent-manager.js +311 -0
  27. package/dist/apps/agent-manager.js.map +1 -0
  28. package/dist/apps/compose-generator.d.ts +108 -0
  29. package/dist/apps/compose-generator.d.ts.map +1 -0
  30. package/dist/apps/compose-generator.js +687 -0
  31. package/dist/apps/compose-generator.js.map +1 -0
  32. package/dist/apps/installer.d.ts +101 -0
  33. package/dist/apps/installer.d.ts.map +1 -0
  34. package/dist/apps/installer.js +898 -0
  35. package/dist/apps/installer.js.map +1 -0
  36. package/dist/apps/registry-client.d.ts +37 -0
  37. package/dist/apps/registry-client.d.ts.map +1 -0
  38. package/dist/apps/registry-client.js +106 -0
  39. package/dist/apps/registry-client.js.map +1 -0
  40. package/dist/apps/registry.d.ts +54 -0
  41. package/dist/apps/registry.d.ts.map +1 -0
  42. package/dist/apps/registry.js +182 -0
  43. package/dist/apps/registry.js.map +1 -0
  44. package/dist/apps/socket-server.d.ts +46 -0
  45. package/dist/apps/socket-server.d.ts.map +1 -0
  46. package/dist/apps/socket-server.js +297 -0
  47. package/dist/apps/socket-server.js.map +1 -0
  48. package/dist/config/watcher.d.ts +1 -0
  49. package/dist/config/watcher.d.ts.map +1 -1
  50. package/dist/config/watcher.js +55 -2
  51. package/dist/config/watcher.js.map +1 -1
  52. package/dist/index.js +170 -3
  53. package/dist/index.js.map +1 -1
  54. package/dist/session/process.d.ts.map +1 -1
  55. package/dist/session/process.js +47 -6
  56. package/dist/session/process.js.map +1 -1
  57. package/dist/types.d.ts +6 -0
  58. package/dist/types.d.ts.map +1 -1
  59. package/mcp/server.ts +2 -0
  60. package/mcp/tools/apps/client.ts +78 -0
  61. package/mcp/tools/apps/module.ts +211 -0
  62. package/mcp/tools/apps/skills/app-status/SKILL.md +48 -0
  63. package/mcp/tools/apps/skills/create-app-yaml/SKILL.md +94 -0
  64. package/mcp/tools/apps/skills/install-app/SKILL.md +102 -0
  65. package/mcp/tools/apps/skills/list-apps/SKILL.md +34 -0
  66. package/mcp/tools/telegram/receiver-server.ts +36 -2
  67. package/package.json +1 -1
package/README.md CHANGED
@@ -26,6 +26,7 @@ A self-hosted multi-agent gateway for Claude Code. Connect Claude agents to Tele
26
26
  - **Config auto-migration** — automatic schema migration when config format changes
27
27
  - **Access control** — allowlist, open, or pairing-based Telegram access policies
28
28
  - **HTTP API** — REST API with key-based auth for external integrations
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
29
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
30
31
  - **Session persistence** — conversation history saved and restored across restarts
31
32
 
@@ -62,6 +63,10 @@ cat > ~/.claude-gateway/.env << 'EOF'
62
63
  # HTTP port (default: 10850)
63
64
  # PORT=10850
64
65
 
66
+ # Bind address (default: 0.0.0.0 — all interfaces)
67
+ # Set to 127.0.0.1 if a host-network reverse proxy (e.g. Traefik) is used
68
+ # GATEWAY_BIND=127.0.0.1
69
+
65
70
  # Path to gateway config (default: ~/.claude-gateway/config.json)
66
71
  # GATEWAY_CONFIG=~/.claude-gateway/config.json
67
72
  EOF
@@ -414,6 +419,15 @@ Pass API key via `X-Api-Key: <key>` or `Authorization: Bearer <key>` header.
414
419
  | `POST` | `/api/v1/agents/wizard/:wizardId/channel` | Verify bot token and generate pairing code (admin) |
415
420
  | `POST` | `/api/v1/agents/wizard/:wizardId/channel/verify` | Poll for pairing code confirmation (admin) |
416
421
  | `POST` | `/api/v1/agents/wizard/:wizardId/complete` | Skip channel and finalise wizard (admin) |
422
+ | `GET` | `/api/v1/apps/registry` | Browse community app registry (admin key) |
423
+ | `POST` | `/api/v1/apps/install` | Install app from registry, GitHub, or local path → `jobId` (admin) |
424
+ | `GET` | `/api/v1/apps/jobs/:jobId` | Poll install/update job status and logs |
425
+ | `GET` | `/api/v1/apps` | List installed apps |
426
+ | `GET` | `/api/v1/apps/:name` | Get app info |
427
+ | `DELETE` | `/api/v1/apps/:name` | Uninstall app (admin) |
428
+ | `POST` | `/api/v1/apps/:name/start\|stop\|restart` | Start/stop/restart app containers (admin) |
429
+ | `POST` | `/api/v1/apps/:name/update` | Blue-green update with auto-rollback → `jobId` (admin) |
430
+ | `GET` | `/app/:name/:portName/*` | Reverse proxy to installed app (no auth) |
417
431
 
418
432
  **Wizard API** — create agents programmatically with the same flow as the interactive `make create-agent` terminal wizard. The wizard generates workspace files via Claude, writes them on confirm, and optionally pairs a Telegram/Discord bot. State is in-memory with a 30-minute TTL; nothing is written until `/confirm`. See [API.md](./API.md) for the full wizard flow.
419
433
 
@@ -421,6 +435,52 @@ See **[API.md](./API.md)** for full reference with request/response schemas and
421
435
 
422
436
  ---
423
437
 
438
+ ## App Store
439
+
440
+ Install Docker-compose apps on the gateway. Apps get a reverse-proxied HTTP endpoint, an optional Unix socket bridge for executing host scripts, and optional AI agent injection.
441
+
442
+ **Quick install from registry:**
443
+
444
+ ```bash
445
+ curl -X POST http://localhost:10850/api/v1/apps/install \
446
+ -H "X-Api-Key: <admin-key>" \
447
+ -H "Content-Type: application/json" \
448
+ -d '{"registry_app": "getpod-manager", "env_vars": {"API_KEY": "<secret>"}}'
449
+ ```
450
+
451
+ **Poll until done:**
452
+
453
+ ```bash
454
+ curl http://localhost:10850/api/v1/apps/jobs/<jobId> -H "X-Api-Key: <key>" | jq .status
455
+ ```
456
+
457
+ **App is then live at** `/app/getpod-manager/<portName>/`.
458
+
459
+ Apps can also be installed from a GitHub URL (`github_url` + `commit`) or a local path (`local_path`) for development. Updates use a **blue-green swap with automatic rollback** — the old containers stay intact until the new version passes its healthcheck.
460
+
461
+ **Reverse proxy configuration:**
462
+
463
+ The gateway proxies `/app/:name/:portName/*` to the app containers. Two env vars control how the gateway reaches them:
464
+
465
+ | Env var | Default | Description |
466
+ |---------|---------|-------------|
467
+ | `GATEWAY_BIND` | `0.0.0.0` | Gateway HTTP listen address. Must be `0.0.0.0` (default) when a **containerized** reverse proxy (Caddy, nginx in Docker) needs to reach the gateway. Set to `127.0.0.1` only if using a **host-network** proxy (Traefik on host) — loopback is not reachable across container boundaries. |
468
+ | `DOCKER_HOST` | _(system default)_ | Docker socket/TCP address. When set to `tcp://host:port` (e.g. DinD), the gateway automatically uses the host extracted from `DOCKER_HOST` to proxy to app containers instead of `127.0.0.1`. |
469
+
470
+ Example Caddyfile for apps behind Caddy in Docker:
471
+
472
+ ```caddy
473
+ handle /app* {
474
+ reverse_proxy dev-server:10850
475
+ }
476
+ ```
477
+
478
+ (`handle`, not `handle_path` — preserve the `/app` prefix so the gateway's router can match it.)
479
+
480
+ See **[API.md — App Store section](./API.md#app-store-api)** for the full reference including `app.yaml` schema, `gateway_api` host-script bridge, and agent injection.
481
+
482
+ ---
483
+
424
484
  ## File Structure
425
485
 
426
486
  ### Project
@@ -779,7 +839,7 @@ Once paired, the following bot commands are available in a private chat:
779
839
 
780
840
  ## Monitoring
781
841
 
782
- The gateway runs an HTTP server on port 10850 (set `PORT` env var to change):
842
+ The gateway runs an HTTP server on port 10850 (set `PORT` env var to change, `GATEWAY_BIND` to set the bind address):
783
843
 
784
844
  | Endpoint | Description |
785
845
  |----------|-------------|
@@ -0,0 +1,10 @@
1
+ export type CommandChannel = 'telegram' | 'discord' | 'api';
2
+ interface CommandDef {
3
+ channels: CommandChannel[];
4
+ /** word-boundary check: true (default) = /^\/cmd\b/, false = /^\/cmd(\s|$)/ */
5
+ wordBoundary?: boolean;
6
+ }
7
+ export declare const BUILTIN_COMMANDS: Record<string, CommandDef>;
8
+ export declare function isBuiltinCommand(content: string, channel: CommandChannel): boolean;
9
+ export {};
10
+ //# sourceMappingURL=builtin-commands.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"builtin-commands.d.ts","sourceRoot":"","sources":["../../src/agent/builtin-commands.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,cAAc,GAAG,UAAU,GAAG,SAAS,GAAG,KAAK,CAAC;AAE5D,UAAU,UAAU;IAClB,QAAQ,EAAE,cAAc,EAAE,CAAC;IAC3B,+EAA+E;IAC/E,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAcvD,CAAC;AAsBF,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,GAAG,OAAO,CAElF"}
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BUILTIN_COMMANDS = void 0;
4
+ exports.isBuiltinCommand = isBuiltinCommand;
5
+ exports.BUILTIN_COMMANDS = {
6
+ session: { channels: ['telegram', 'discord', 'api'] },
7
+ sessions: { channels: ['telegram', 'discord', 'api'] },
8
+ new: { channels: ['telegram', 'discord'], wordBoundary: false },
9
+ rename: { channels: ['telegram'], wordBoundary: false },
10
+ clear: { channels: ['telegram', 'api'] },
11
+ compact: { channels: ['telegram', 'api'] },
12
+ stop: { channels: ['telegram', 'api'], wordBoundary: false },
13
+ model: { channels: ['telegram', 'discord', 'api'] },
14
+ models: { channels: ['telegram'] },
15
+ restart: { channels: ['telegram', 'api'], wordBoundary: false },
16
+ start: { channels: ['telegram'] },
17
+ help: { channels: ['telegram'] },
18
+ status: { channels: ['telegram'] },
19
+ };
20
+ const _cache = new Map();
21
+ function buildRegex(channel) {
22
+ const parts = Object.entries(exports.BUILTIN_COMMANDS)
23
+ .filter(([, def]) => def.channels.includes(channel))
24
+ .map(([cmd, def]) => def.wordBoundary === false ? `^\/${cmd}(\\s|$)` : `^\/${cmd}\\b`);
25
+ return new RegExp(parts.join('|'));
26
+ }
27
+ function getRegex(channel) {
28
+ let re = _cache.get(channel);
29
+ if (!re) {
30
+ re = buildRegex(channel);
31
+ _cache.set(channel, re);
32
+ }
33
+ return re;
34
+ }
35
+ function isBuiltinCommand(content, channel) {
36
+ return getRegex(channel).test(content.trim());
37
+ }
38
+ //# sourceMappingURL=builtin-commands.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"builtin-commands.js","sourceRoot":"","sources":["../../src/agent/builtin-commands.ts"],"names":[],"mappings":";;;AA4CA,4CAEC;AAtCY,QAAA,gBAAgB,GAA+B;IAC1D,OAAO,EAAG,EAAE,QAAQ,EAAE,CAAC,UAAU,EAAE,SAAS,EAAE,KAAK,CAAC,EAAE;IACtD,QAAQ,EAAE,EAAE,QAAQ,EAAE,CAAC,UAAU,EAAE,SAAS,EAAE,KAAK,CAAC,EAAE;IACtD,GAAG,EAAO,EAAE,QAAQ,EAAE,CAAC,UAAU,EAAE,SAAS,CAAC,EAAE,YAAY,EAAE,KAAK,EAAE;IACpE,MAAM,EAAI,EAAE,QAAQ,EAAE,CAAC,UAAU,CAAC,EAAE,YAAY,EAAE,KAAK,EAAE;IACzD,KAAK,EAAK,EAAE,QAAQ,EAAE,CAAC,UAAU,EAAE,KAAK,CAAC,EAAE;IAC3C,OAAO,EAAG,EAAE,QAAQ,EAAE,CAAC,UAAU,EAAE,KAAK,CAAC,EAAE;IAC3C,IAAI,EAAM,EAAE,QAAQ,EAAE,CAAC,UAAU,EAAE,KAAK,CAAC,EAAE,YAAY,EAAE,KAAK,EAAE;IAChE,KAAK,EAAK,EAAE,QAAQ,EAAE,CAAC,UAAU,EAAE,SAAS,EAAE,KAAK,CAAC,EAAE;IACtD,MAAM,EAAI,EAAE,QAAQ,EAAE,CAAC,UAAU,CAAC,EAAE;IACpC,OAAO,EAAG,EAAE,QAAQ,EAAE,CAAC,UAAU,EAAE,KAAK,CAAC,EAAE,YAAY,EAAE,KAAK,EAAE;IAChE,KAAK,EAAK,EAAE,QAAQ,EAAE,CAAC,UAAU,CAAC,EAAE;IACpC,IAAI,EAAM,EAAE,QAAQ,EAAE,CAAC,UAAU,CAAC,EAAE;IACpC,MAAM,EAAI,EAAE,QAAQ,EAAE,CAAC,UAAU,CAAC,EAAE;CACrC,CAAC;AAEF,MAAM,MAAM,GAAG,IAAI,GAAG,EAA0B,CAAC;AAEjD,SAAS,UAAU,CAAC,OAAuB;IACzC,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,wBAAgB,CAAC;SAC3C,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;SACnD,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,EAAE,CAClB,GAAG,CAAC,YAAY,KAAK,KAAK,CAAC,CAAC,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC,MAAM,GAAG,KAAK,CACjE,CAAC;IACJ,OAAO,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AACrC,CAAC;AAED,SAAS,QAAQ,CAAC,OAAuB;IACvC,IAAI,EAAE,GAAG,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAC7B,IAAI,CAAC,EAAE,EAAE,CAAC;QACR,EAAE,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;QACzB,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IAC1B,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,SAAgB,gBAAgB,CAAC,OAAe,EAAE,OAAuB;IACvE,OAAO,QAAQ,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;AAChD,CAAC"}
@@ -5,7 +5,7 @@ import { HistoryDB } from '../history/db';
5
5
  export declare const MAX_IMAGE_SIZE_BYTES: number;
6
6
  export declare const DEFAULT_MODELS: ModelConfig[];
7
7
  export declare class AgentRunner extends EventEmitter {
8
- private readonly agentConfig;
8
+ private agentConfig;
9
9
  private readonly gatewayConfig;
10
10
  private readonly logger;
11
11
  private stopping;
@@ -59,10 +59,7 @@ export declare class AgentRunner extends EventEmitter {
59
59
  private static buildChannelXml;
60
60
  private getOrSpawnSession;
61
61
  private spawnSession;
62
- /**
63
- * Returns true if the message content is a session management command.
64
- */
65
- private isSessionCommand;
62
+ static isApiBuiltinCommand(content: string): boolean;
66
63
  /**
67
64
  * Dispatch a session management command to the appropriate handler.
68
65
  */
@@ -136,7 +133,12 @@ export declare class AgentRunner extends EventEmitter {
136
133
  private writeAutoForward;
137
134
  private startIdleCleaner;
138
135
  start(): Promise<void>;
136
+ updateAgentConfig(newConfig: AgentConfig): void;
137
+ getAgentConfig(): AgentConfig;
138
+ startTelegramReceiver(): void;
139
+ stopTelegramReceiver(): void;
139
140
  startDiscordReceiver(): void;
141
+ stopDiscordReceiver(): void;
140
142
  stop(): Promise<void>;
141
143
  private _startCleanupScheduler;
142
144
  restart(): Promise<void>;
@@ -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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"}
@@ -47,6 +47,7 @@ const receiver_1 = require("../telegram/receiver");
47
47
  const receiver_2 = require("../discord/receiver");
48
48
  const markdown_1 = require("../telegram/markdown");
49
49
  const skills_1 = require("../skills");
50
+ const builtin_commands_1 = require("./builtin-commands");
50
51
  const db_1 = require("../history/db");
51
52
  const media_store_1 = require("../history/media-store");
52
53
  const cleanup_1 = require("../history/cleanup");
@@ -96,7 +97,7 @@ function buildApiSystemNote(allowTools, imagePaths) {
96
97
  if (imagePaths?.length) {
97
98
  imageNote = ` The user attached ${imagePaths.length} image(s). Read them with the Read tool:\n${imagePaths.map(p => `- ${p}`).join('\n')}`;
98
99
  }
99
- return `[SYSTEM: This is an API request. ${memoryOverride} ${toolNote}${imageNote}]\n`;
100
+ return `<api-context>This is an API request. ${memoryOverride} ${toolNote}${imageNote}</api-context>\n`;
100
101
  }
101
102
  class AgentRunner extends events_1.EventEmitter {
102
103
  imageSize(chatId) { return this.imageSizePerChat.get(chatId) ?? 0; }
@@ -186,9 +187,9 @@ class AgentRunner extends events_1.EventEmitter {
186
187
  // Set channel early so all handlers (including session commands) have it
187
188
  const channelSource = (meta['source'] === 'discord' ? 'discord' : 'telegram');
188
189
  this.channelSourceMap.set(chatId, channelSource);
189
- // Check if this is a session management command
190
+ // Check if this is a built-in channel command
190
191
  const trimmedContent = content.trim();
191
- if (this.isSessionCommand(trimmedContent)) {
192
+ if ((0, builtin_commands_1.isBuiltinCommand)(trimmedContent, channelSource)) {
192
193
  this.handleSessionCommand(chatId, trimmedContent)
193
194
  .then(() => this.writeTypingDone(chatId))
194
195
  .catch((err) => {
@@ -802,11 +803,8 @@ class AgentRunner extends events_1.EventEmitter {
802
803
  });
803
804
  return proc;
804
805
  }
805
- /**
806
- * Returns true if the message content is a session management command.
807
- */
808
- isSessionCommand(content) {
809
- return /^\/sessions?\b|^\/new(\s|$)|^\/clear\b|^\/compact\b|^\/rename(\s|$)|^\/stop(\s|$)/.test(content);
806
+ static isApiBuiltinCommand(content) {
807
+ return (0, builtin_commands_1.isBuiltinCommand)(content, 'api');
810
808
  }
811
809
  /**
812
810
  * Dispatch a session management command to the appropriate handler.
@@ -1157,13 +1155,44 @@ class AgentRunner extends events_1.EventEmitter {
1157
1155
  this._startCleanupScheduler();
1158
1156
  this.logger.info('AgentRunner started', { agentId: this.agentConfig.id });
1159
1157
  }
1158
+ updateAgentConfig(newConfig) {
1159
+ this.agentConfig = newConfig;
1160
+ }
1161
+ getAgentConfig() {
1162
+ return { ...this.agentConfig };
1163
+ }
1164
+ startTelegramReceiver() {
1165
+ if (this.receiver?.isRunning())
1166
+ return;
1167
+ if (!this.agentConfig.telegram?.botToken)
1168
+ return;
1169
+ this.receiver = new receiver_1.TelegramReceiver(this.agentConfig, this.callbackPort, this.gatewayConfig.gateway.logDir);
1170
+ this.receiver.start();
1171
+ this.logger.info('TelegramReceiver hot-started', { agentId: this.agentConfig.id });
1172
+ }
1173
+ stopTelegramReceiver() {
1174
+ if (!this.receiver)
1175
+ return;
1176
+ this.receiver.stop();
1177
+ this.receiver = null;
1178
+ this.logger.info('TelegramReceiver stopped', { agentId: this.agentConfig.id });
1179
+ }
1160
1180
  startDiscordReceiver() {
1161
1181
  if (this.discordReceiver?.isRunning())
1162
1182
  return;
1183
+ if (!this.agentConfig.discord?.botToken)
1184
+ return;
1163
1185
  this.discordReceiver = new receiver_2.DiscordReceiver(this.agentConfig, this.callbackPort, this.gatewayConfig.gateway.logDir);
1164
1186
  this.discordReceiver.start();
1165
1187
  this.logger.info('DiscordReceiver hot-started', { agentId: this.agentConfig.id });
1166
1188
  }
1189
+ stopDiscordReceiver() {
1190
+ if (!this.discordReceiver)
1191
+ return;
1192
+ this.discordReceiver.stop();
1193
+ this.discordReceiver = null;
1194
+ this.logger.info('DiscordReceiver stopped', { agentId: this.agentConfig.id });
1195
+ }
1167
1196
  async stop() {
1168
1197
  this.stopping = true;
1169
1198
  if (this.idleCleanerTimer !== null) {
@@ -1216,9 +1245,8 @@ class AgentRunner extends events_1.EventEmitter {
1216
1245
  const err = Object.assign(new Error(`Session ${sessionId} already has a pending request`), { code: 'CONFLICT' });
1217
1246
  throw err;
1218
1247
  }
1219
- // Register session in api-{chatId} index.json on first use
1220
- const internalChatIdForSession = `api-${chatId}`;
1221
- await this.sessionStore.ensureApiSession(this.agentConfig.id, internalChatIdForSession, sessionId).catch((err) => {
1248
+ // Register session in api-{chatId} index.json on first use (store adds channel prefix internally)
1249
+ await this.sessionStore.ensureApiSession(this.agentConfig.id, chatId, sessionId).catch((err) => {
1222
1250
  this.logger.warn('Failed to register API session in index', { agentId: this.agentConfig.id, chatId, sessionId, error: err.message });
1223
1251
  });
1224
1252
  // Use model from request body if provided, otherwise use agent default
@@ -1378,9 +1406,8 @@ class AgentRunner extends events_1.EventEmitter {
1378
1406
  const err = Object.assign(new Error(`Session ${sessionId} already has a pending request`), { code: 'CONFLICT' });
1379
1407
  throw err;
1380
1408
  }
1381
- // Register session in api-{chatId} index.json on first use
1382
- const internalChatIdStream = `api-${chatId}`;
1383
- await this.sessionStore.ensureApiSession(this.agentConfig.id, internalChatIdStream, sessionId).catch((err) => {
1409
+ // Register session in api-{chatId} index.json on first use (store adds channel prefix internally)
1410
+ await this.sessionStore.ensureApiSession(this.agentConfig.id, chatId, sessionId).catch((err) => {
1384
1411
  this.logger.warn('Failed to register API session in index', { agentId: this.agentConfig.id, chatId, sessionId, error: err.message });
1385
1412
  });
1386
1413
  // Use model from request body if provided, otherwise use agent default
@@ -1593,7 +1620,8 @@ class AgentRunner extends events_1.EventEmitter {
1593
1620
  }
1594
1621
  async executeApiCommand(sessionId, chatId, command) {
1595
1622
  const agentId = this.agentConfig.id;
1596
- const internalChatId = `api-${chatId}`;
1623
+ const storeChatId = chatId; // sessionStore adds channel prefix internally
1624
+ const dbChatId = `api-${chatId}`; // historyDb uses full channel-chatId key
1597
1625
  if (command === '/model') {
1598
1626
  return { model: this.agentConfig.claude.model };
1599
1627
  }
@@ -1607,7 +1635,7 @@ class AgentRunner extends events_1.EventEmitter {
1607
1635
  return { restarting: true };
1608
1636
  }
1609
1637
  if (command === '/session') {
1610
- const index = await this.sessionStore.listSessions(agentId, internalChatId, 'api').catch(() => null);
1638
+ const index = await this.sessionStore.listSessions(agentId, storeChatId, 'api').catch(() => null);
1611
1639
  const meta = index?.sessions.find((s) => s.id === sessionId);
1612
1640
  const effectiveModel = this.agentConfig.claude.model;
1613
1641
  if (!meta)
@@ -1627,15 +1655,15 @@ class AgentRunner extends events_1.EventEmitter {
1627
1655
  }
1628
1656
  if (command === '/clear') {
1629
1657
  const ch = 'api';
1630
- await this.sessionStore.clearTelegramSessionHistory(agentId, internalChatId, sessionId, ch);
1631
- await this.sessionStore.updateSessionMeta(agentId, internalChatId, sessionId, {
1658
+ await this.sessionStore.clearTelegramSessionHistory(agentId, storeChatId, sessionId, ch);
1659
+ await this.sessionStore.updateSessionMeta(agentId, storeChatId, sessionId, {
1632
1660
  totalTokensUsed: 0,
1633
1661
  lastInputTokens: 0,
1634
1662
  archivedCount: 0,
1635
1663
  loadedAtSpawn: undefined,
1636
1664
  messageCountAtSpawn: undefined,
1637
1665
  }, ch);
1638
- const mediaPaths = this.historyDb.clearSession(internalChatId, sessionId);
1666
+ const mediaPaths = this.historyDb.clearSession(dbChatId, sessionId);
1639
1667
  media_store_1.MediaStore.deleteMediaFiles(this.agentsBaseDir, agentId, mediaPaths);
1640
1668
  this.restartProcess(sessionId).catch(() => { });
1641
1669
  return { success: true };
@@ -1647,8 +1675,8 @@ class AgentRunner extends events_1.EventEmitter {
1647
1675
  const modelConfig = availableModels.find((m) => m.id === compactEffectiveModel);
1648
1676
  const contextWindow = modelConfig?.contextWindow ?? 200000;
1649
1677
  const compactor = new compactor_1.SessionCompactor(this.sessionStore);
1650
- const result = await compactor.compact(agentId, internalChatId, sessionId, compactEffectiveModel, contextWindow, ch);
1651
- await this.sessionStore.updateSessionMeta(agentId, internalChatId, sessionId, {
1678
+ const result = await compactor.compact(agentId, storeChatId, sessionId, compactEffectiveModel, contextWindow, ch);
1679
+ await this.sessionStore.updateSessionMeta(agentId, storeChatId, sessionId, {
1652
1680
  loadedAtSpawn: undefined,
1653
1681
  archivedCount: undefined,
1654
1682
  messageCountAtSpawn: undefined,
@@ -1672,7 +1700,7 @@ class AgentRunner extends events_1.EventEmitter {
1672
1700
  }
1673
1701
  }
1674
1702
  async listApiSessions(chatId) {
1675
- return this.sessionStore.listSessions(this.agentConfig.id, `api-${chatId}`, 'api');
1703
+ return this.sessionStore.listSessions(this.agentConfig.id, chatId, 'api');
1676
1704
  }
1677
1705
  async createApiSession(chatId, prompt, name) {
1678
1706
  let sessionName = name;
@@ -1689,10 +1717,10 @@ class AgentRunner extends events_1.EventEmitter {
1689
1717
  sessionName = undefined;
1690
1718
  }
1691
1719
  }
1692
- return this.sessionStore.createTelegramSession(this.agentConfig.id, `api-${chatId}`, sessionName, 'api');
1720
+ return this.sessionStore.createTelegramSession(this.agentConfig.id, chatId, sessionName, 'api');
1693
1721
  }
1694
1722
  async getApiSessionInfo(chatId, sessionId) {
1695
- const index = await this.sessionStore.listSessions(this.agentConfig.id, `api-${chatId}`, 'api').catch(() => null);
1723
+ const index = await this.sessionStore.listSessions(this.agentConfig.id, chatId, 'api').catch(() => null);
1696
1724
  const meta = index?.sessions.find((s) => s.id === sessionId);
1697
1725
  if (!meta)
1698
1726
  return null;
@@ -1712,25 +1740,23 @@ class AgentRunner extends events_1.EventEmitter {
1712
1740
  }
1713
1741
  async updateApiSession(chatId, sessionId, updates) {
1714
1742
  if (updates.sessionName) {
1715
- const internalChatId = `api-${chatId}`;
1716
1743
  // Ensure session exists in the file index (may be missing for older sessions stored only in SQLite)
1717
- await this.sessionStore.ensureApiSession(this.agentConfig.id, internalChatId, sessionId).catch((err) => {
1744
+ await this.sessionStore.ensureApiSession(this.agentConfig.id, chatId, sessionId).catch((err) => {
1718
1745
  this.logger.warn('Failed to register API session in index', { agentId: this.agentConfig.id, chatId, sessionId, error: err.message });
1719
1746
  });
1720
- await this.sessionStore.updateSessionMeta(this.agentConfig.id, internalChatId, sessionId, { name: updates.sessionName }, 'api');
1747
+ await this.sessionStore.updateSessionMeta(this.agentConfig.id, chatId, sessionId, { name: updates.sessionName }, 'api');
1721
1748
  }
1722
1749
  return { sessionId, ...(updates.sessionName ? { sessionName: updates.sessionName } : {}) };
1723
1750
  }
1724
1751
  async deleteApiSession(chatId, sessionId) {
1725
- const internalChatId = `api-${chatId}`;
1726
- await this.sessionStore.deleteTelegramSession(this.agentConfig.id, internalChatId, sessionId, 'api').catch((err) => {
1752
+ await this.sessionStore.deleteTelegramSession(this.agentConfig.id, chatId, sessionId, 'api').catch((err) => {
1727
1753
  // Legacy sessions (stored only in SQLite, no file index entry) are treated as already deleted
1728
1754
  if (err instanceof store_1.SessionNotInIndexError)
1729
1755
  return;
1730
1756
  throw err;
1731
1757
  });
1732
1758
  // Purge from SQLite so the session no longer appears in listSessions()
1733
- const mediaPaths = this.historyDb.clearSession(internalChatId, sessionId);
1759
+ const mediaPaths = this.historyDb.clearSession(`api-${chatId}`, sessionId);
1734
1760
  media_store_1.MediaStore.deleteMediaFiles(this.agentsBaseDir, this.agentConfig.id, mediaPaths);
1735
1761
  }
1736
1762
  /**