@inceptionstack/roundhouse 0.5.9 → 0.5.10

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inceptionstack/roundhouse",
3
- "version": "0.5.9",
3
+ "version": "0.5.10",
4
4
  "type": "module",
5
5
  "description": "Multi-platform chat gateway that routes messages through a configured AI agent",
6
6
  "license": "MIT",
@@ -20,6 +20,7 @@ export class CronRunner {
20
20
  constructor(
21
21
  private store: CronStore,
22
22
  private agentConfig?: GatewayConfig["agent"],
23
+ private notifyFn?: (text: string) => Promise<void>,
23
24
  ) {}
24
25
 
25
26
  async runJob(
@@ -127,6 +128,10 @@ export class CronRunner {
127
128
  }
128
129
 
129
130
  private async notify(job: CronJobConfig, record: CronRunRecord): Promise<void> {
131
+ // Apply onlyOn filter if configured (for both routes)
132
+ const tg = job.notify?.telegram;
133
+ if (tg?.onlyOn && !shouldNotify(tg.onlyOn, record.status)) return;
134
+
130
135
  const icon = runStatusIcon(record.status);
131
136
  const dur = `${(record.durationMs / 1000).toFixed(1)}s`;
132
137
  const header = `${icon} Cron: ${job.id}\nStatus: ${record.status} (${dur})`;
@@ -141,18 +146,25 @@ export class CronRunner {
141
146
  }
142
147
 
143
148
  // Route 1: Explicit Telegram chat IDs configured on the job
144
- const tg = job.notify?.telegram;
145
149
  if (tg?.chatIds?.length) {
146
- if (!shouldNotify(tg.onlyOn, record.status)) return;
147
150
  await sendTelegramToMany(tg.chatIds, body);
148
151
  return;
149
152
  }
150
153
 
151
- // Route 2: Broadcast via IPC to all active transports (default)
154
+ // Route 2: Direct callback from gateway (no loopback socket)
155
+ if (this.notifyFn) {
156
+ try {
157
+ await this.notifyFn(body);
158
+ } catch (err) {
159
+ console.warn(`[cron] ${job.id} notify callback failed:`, (err as Error).message);
160
+ }
161
+ return;
162
+ }
163
+
164
+ // Route 3: Fallback to IPC (for CLI-triggered runs outside gateway)
152
165
  try {
153
166
  await sendIpc({ type: "notify", text: body });
154
167
  } catch {
155
- // Gateway not running or IPC unavailable — log and continue
156
168
  console.warn(`[cron] ${job.id} IPC notify failed (gateway not running?)`);
157
169
  }
158
170
  }
@@ -41,9 +41,9 @@ export class CronSchedulerService {
41
41
  private lastHeartbeatAt = 0; // 0 = fires on first tick after startup (intentional catch-up)
42
42
  private tickMs: number;
43
43
 
44
- constructor(private opts?: { tickMs?: number; agentConfig?: GatewayConfig["agent"]; notifyChatIds?: number[] }) {
44
+ constructor(private opts?: { tickMs?: number; agentConfig?: GatewayConfig["agent"]; notifyChatIds?: number[]; notifyFn?: (text: string) => Promise<void> }) {
45
45
  this.store = new CronStore();
46
- this.runner = new CronRunner(this.store, this.opts?.agentConfig);
46
+ this.runner = new CronRunner(this.store, this.opts?.agentConfig, this.opts?.notifyFn);
47
47
  this.queue = new PQueue({ concurrency: 1 });
48
48
  this.tickMs = this.opts?.tickMs ?? TICK_MS;
49
49
  }
@@ -325,6 +325,12 @@ export class Gateway {
325
325
  this.cronScheduler = new CronSchedulerService({
326
326
  agentConfig: this.config.agent,
327
327
  notifyChatIds: this.config.chat.notifyChatIds,
328
+ notifyFn: async (text: string) => {
329
+ const chatIds = this.config.chat.notifyChatIds;
330
+ if (chatIds?.length && this.transport) {
331
+ await this.transport.notify(chatIds, text);
332
+ }
333
+ },
328
334
  });
329
335
  try {
330
336
  await this.cronScheduler.start();