thepopebot 1.2.76-beta.39 → 1.2.76-beta.40

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.
package/api/CLAUDE.md CHANGED
@@ -36,9 +36,9 @@ Mutation server actions in `lib/chat/actions.js` use `requireAdmin()` for settin
36
36
  | GET | `/api/agent-job-list-secrets` | `agent_job_api_key` only | List agent job secret keys (no values); returns `{secrets: [{key, isSet, updatedAt, secretType}]}` |
37
37
  | GET | `/api/agent-jobs/status` | `x-api-key` | Agent job status (query: `?agent_job_id=`) |
38
38
  | GET | `/api/users` | `x-api-key` | List users with verified DM channels: `{users: [{id, email, first_name, last_name, nickname, role, channels: ['telegram', ...]}]}`. Used by the `agent-job-dm` skill. |
39
- | POST | `/api/send-dm` | `x-api-key` | Dispatch a system message. Body: `{ user_id?, message, payload? }`. With `user_id`: write 1 row + push to that user's default channel. Without: fan out 1 row per admin where `subscribedToSystemMessages=1`, each pushed to their default channel. Returns `{ok, recipients}`. |
39
+ | POST | `/api/send-dm` | `x-api-key` | Dispatch a message. Body: `{ user_id?, message, payload?, system_message? }`. With `user_id`: write 1 row + push to that user's default channel. Without: fan out 1 row per admin where `subscribedToSystemMessages=1`, each pushed to their default channel. `system_message: true` (default false) marks it as a system notification — channels with `systemMessagesEnabled=0` skip the push (inbox row still written). Returns `{ok, recipients}`. |
40
40
  | POST | `/api/telegram/webhook` | Telegram webhook secret | Telegram message handler (per-user routing via `user_channels`; verifies via `/verify <code>`, dispatches `/session` commands) |
41
- | POST | `/api/github/webhook` | GitHub webhook secret | GitHub event handler. PR-merge events read `user_id` from `agent-job.config.json` and dispatch the completion message via `dispatchSystemMessage` (per-user when set; broadcast to subscribed admins when absent). |
41
+ | POST | `/api/github/webhook` | GitHub webhook secret | GitHub event handler. PR-merge events read `user_id` from `agent-job.config.json` and dispatch the completion message via `dispatchMessage` (per-user when set; broadcast to subscribed admins when absent). Agent-job completions are broadcasts, not system messages — they always push regardless of per-channel `systemMessagesEnabled`. |
42
42
  | POST | `/api/cluster/:clusterId/role/:roleId/webhook` | `x-api-key` | Trigger cluster role execution |
43
43
  | GET/POST | `/api/oauth/callback` | `state` token | OAuth provider redirect target. Exchanges `code` for tokens, persists via `setAgentJobSecret(name, stored, 'oauth')`. |
44
44
 
package/api/index.js CHANGED
@@ -182,14 +182,18 @@ async function handleListUsers() {
182
182
  /**
183
183
  * Push a stored message to the recipient's default channel.
184
184
  * On success: stamp `deliveredAt`. On failure: log; row stays undelivered.
185
+ * When `systemMessage` is true, channels with `systemMessagesEnabled=0` are skipped
186
+ * (the inbox row stays — only the channel push is muted).
185
187
  * Best-effort, async — caller does not await.
186
188
  */
187
- async function pushToDefaultChannel(row) {
189
+ async function pushToDefaultChannel(row, { systemMessage = false } = {}) {
188
190
  try {
189
191
  const verified = getVerifiedChannels(row.userId);
190
192
  if (verified.length === 0) return; // No channel — row remains in inbox only
191
193
  const target = verified[0]; // Ordered by verifiedAt ASC; first verified is default
192
194
 
195
+ if (systemMessage && target.systemMessagesEnabled === 0) return;
196
+
193
197
  if (target.channel === 'telegram') {
194
198
  const botToken = getTelegramBotToken();
195
199
  if (!botToken) {
@@ -206,17 +210,19 @@ async function pushToDefaultChannel(row) {
206
210
  }
207
211
 
208
212
  /**
209
- * Dispatch a system message: store + deliver.
213
+ * Dispatch a message: store + deliver.
210
214
  * - userId set → 1 row to that user, pushed to their default channel.
211
215
  * - userId absent → fan-out: 1 row per admin where subscribedToSystemMessages=1, each pushed.
216
+ * `systemMessage` (default false) marks the message as a system notification (e.g. github webhook);
217
+ * channels with `systemMessagesEnabled=0` will not receive the push, but the inbox row is always written.
212
218
  * Returns the count of rows written.
213
219
  */
214
- function dispatchSystemMessage({ userId, content, payload }) {
220
+ function dispatchMessage({ userId, content, payload, systemMessage = false }) {
215
221
  const recipients = userId ? [userId] : getSubscribedAdminIds();
216
222
  const rows = recipients.map((uid) => createSystemMessage(uid, content, payload));
217
223
  // Fire-and-forget delivery; deliveredAt updated per row when each push lands.
218
224
  for (const row of rows) {
219
- pushToDefaultChannel(row);
225
+ pushToDefaultChannel(row, { systemMessage });
220
226
  }
221
227
  return rows.length;
222
228
  }
@@ -229,7 +235,7 @@ async function handleSendDm(request) {
229
235
  return Response.json({ error: 'Invalid JSON body' }, { status: 400 });
230
236
  }
231
237
 
232
- const { user_id, message, payload } = body;
238
+ const { user_id, message, payload, system_message } = body;
233
239
  if (!message || typeof message !== 'string') {
234
240
  return Response.json({ error: 'Missing message' }, { status: 400 });
235
241
  }
@@ -239,7 +245,12 @@ async function handleSendDm(request) {
239
245
  if (!user) return Response.json({ error: 'User not found' }, { status: 404 });
240
246
  }
241
247
 
242
- const count = dispatchSystemMessage({ userId: user_id || null, content: message, payload });
248
+ const count = dispatchMessage({
249
+ userId: user_id || null,
250
+ content: message,
251
+ payload,
252
+ systemMessage: system_message === true,
253
+ });
243
254
  return Response.json({ ok: true, recipients: count });
244
255
  }
245
256
 
@@ -366,7 +377,7 @@ async function handleGithubWebhook(request) {
366
377
 
367
378
  const message = await summarizeAgentJob(results);
368
379
  const recipientUserId = payload.user_id || null;
369
- const count = dispatchSystemMessage({
380
+ const count = dispatchMessage({
370
381
  userId: recipientUserId,
371
382
  content: message,
372
383
  payload,
@@ -0,0 +1 @@
1
+ ALTER TABLE `user_channels` ADD `system_messages_enabled` integer DEFAULT 1 NOT NULL;