MCPcopy Create free account
hub / github.com/QodeXcli/QodeX / onMessage

Method onMessage

src/bot/gateway.ts:80–128  ·  view source on GitHub ↗

Single entry point for every inbound event from any adapter.

(t: Transport, m: Incoming)

Source from the content-addressed store, hash-verified

78 }
79
80 private key(t: Transport, m: Incoming): string { return `${t.platform}:${m.chatId}`; }
81
82 /** The small control surface a command may drive for this conversation. */
83 private controlsFor(t: Transport, chatId: string, key: string): GatewayControls {
84 return {
85 isBusy: () => this.busy.has(key),
86 queueDepth: () => this.queue.get(key)?.length ?? 0,
87 abort: () => {
88 const ac = this.busy.get(key);
89 if (!ac) return false;
90 ac.abort();
91 getOperatorHub().cancelLane(botLane(key));
92 return true;
93 },
94 reset: async () => {
95 this.busy.get(key)?.abort();
96 this.queue.delete(key);
97 getOperatorHub().cancelLane(botLane(key));
98 await this.opts.agent.reset?.(key);
99 },
100 runTask: (txt) => this.runAndDrain(t, chatId, key, txt),
101 };
102 }
103
104 /** Run `text` as a turn, serialized per chat: if busy, queue it; else run + drain the queue. */
105 private async runAndDrain(t: Transport, chatId: string, key: string, text: string): Promise<void> {
106 if (this.busy.has(key)) {
107 const q = this.queue.get(key) ?? [];
108 q.push(text); this.queue.set(key, q);
109 await t.send(chatId, `⏳ Busy — queued (#${q.length}). \`/stop\` to cancel the current task.`);
110 return;
111 }
112 await this.runOne(t, chatId, key, text);
113 let next: string | undefined;
114 while ((next = this.queue.get(key)?.shift())) await this.runOne(t, chatId, key, next);
115 this.queue.delete(key);
116 }
117
118 /** Single entry point for every inbound event from any adapter. */
119 async onMessage(t: Transport, m: Incoming): Promise<void> {
120 const key = this.key(t, m);
121
122 // 1) Auth — closed by default. A coding agent must never run for an unlisted user.
123 if (!isAuthorized(t.platform, m.userId, this.opts.allow)) {
124 await t.send(m.chatId, '⛔ You are not on this QodeX bot’s allowlist.');
125 return;
126 }
127
128 // 2) Living-artifact card actions (Approve / Edit / Reject) — handled before permission asks.
129 if (m.callbackData?.startsWith('art:')) {
130 if (m.callbackId && t.ackCallback) await t.ackCallback(m.callbackId);
131 await this.handleCardAction(t, m.chatId, key, m.callbackData);

Callers 1

startMethod · 0.95

Calls 14

keyMethod · 0.95
handleCardActionMethod · 0.95
stripAskMethod · 0.95
resolveAskMethod · 0.95
controlsForMethod · 0.95
runAndDrainMethod · 0.95
isAuthorizedFunction · 0.85
findCommandFunction · 0.85
deleteMethod · 0.80
sendMethod · 0.65
ackCallbackMethod · 0.65
runMethod · 0.65

Tested by

no test coverage detected