@automagik/omni 2.260430.16 → 2.260501.1

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/dist/index.js CHANGED
@@ -26733,6 +26733,9 @@ function createSubscription(options) {
26733
26733
  return {
26734
26734
  id: subscriptionId,
26735
26735
  pattern,
26736
+ isAlive() {
26737
+ return isActive;
26738
+ },
26736
26739
  async unsubscribe() {
26737
26740
  isActive = false;
26738
26741
  abortController.abort();
@@ -34208,13 +34211,16 @@ var init_debounce = __esm(() => {
34208
34211
  // ../core/src/automations/engine.ts
34209
34212
  class AutomationEngine {
34210
34213
  config;
34211
- subscriptions = [];
34214
+ subscriptions = new Map;
34212
34215
  instanceQueues = new Map;
34213
34216
  debounceManagers = new Map;
34214
34217
  automations = [];
34215
34218
  eventBus = null;
34216
34219
  deps;
34217
34220
  logger = null;
34221
+ reconcileTimer = null;
34222
+ reconcileEnabled = false;
34223
+ reconcilePromise = null;
34218
34224
  constructor(config2) {
34219
34225
  this.config = config2;
34220
34226
  this.deps = {
@@ -34231,33 +34237,17 @@ class AutomationEngine {
34231
34237
  callAgent: deps.callAgent
34232
34238
  };
34233
34239
  this.automations = automations.filter((a) => a.enabled);
34234
- const triggerTypes = new Set(this.automations.map((a) => a.triggerEventType));
34235
- for (const eventType of triggerTypes) {
34236
- const durable = `automation-engine-${eventType.replace(/[^a-zA-Z0-9_-]/g, "-")}`;
34237
- const subscription = await eventBus.subscribePattern(`${eventType}.>`, async (event) => {
34238
- await this.handleEvent(event);
34239
- }, {
34240
- durable,
34241
- queue: "automation-engine",
34242
- startFrom: "new",
34243
- maxRetries: 3,
34244
- retryDelayMs: 1000
34245
- });
34246
- this.subscriptions.push(subscription);
34247
- logger4.info(`Subscribed to ${eventType}.*`, { durable });
34248
- }
34249
- for (const automation of this.automations) {
34250
- if (automation.debounce && automation.debounce.mode !== "none") {
34251
- this.setupDebounceManager(automation);
34252
- }
34253
- }
34240
+ await this.reconcileSubscriptions();
34241
+ this.rebuildDebounceManagers();
34242
+ this.startReconcileTimer();
34254
34243
  logger4.info(`Automation engine started with ${this.automations.length} automations`);
34255
34244
  }
34256
34245
  async stop() {
34257
- for (const subscription of this.subscriptions) {
34246
+ this.stopReconcileTimer();
34247
+ for (const subscription of this.subscriptions.values()) {
34258
34248
  await subscription.unsubscribe();
34259
34249
  }
34260
- this.subscriptions = [];
34250
+ this.subscriptions.clear();
34261
34251
  for (const manager of this.debounceManagers.values()) {
34262
34252
  manager.flushAll();
34263
34253
  }
@@ -34268,9 +34258,117 @@ class AutomationEngine {
34268
34258
  this.logger = logger5;
34269
34259
  }
34270
34260
  async reload(automations) {
34271
- await this.stop();
34272
- if (this.eventBus) {
34273
- await this.start(this.eventBus, automations, this.deps);
34261
+ if (!this.eventBus) {
34262
+ this.automations = automations.filter((a) => a.enabled);
34263
+ return;
34264
+ }
34265
+ this.automations = automations.filter((a) => a.enabled);
34266
+ await this.reconcileSubscriptions();
34267
+ this.rebuildDebounceManagers();
34268
+ }
34269
+ async reconcile() {
34270
+ if (!this.eventBus)
34271
+ return;
34272
+ await this.reconcileSubscriptions();
34273
+ }
34274
+ async reconcileSubscriptions() {
34275
+ if (!this.eventBus)
34276
+ return;
34277
+ if (this.reconcilePromise)
34278
+ return this.reconcilePromise;
34279
+ this.reconcilePromise = this.doReconcileSubscriptions().finally(() => {
34280
+ this.reconcilePromise = null;
34281
+ });
34282
+ return this.reconcilePromise;
34283
+ }
34284
+ async doReconcileSubscriptions() {
34285
+ if (!this.eventBus)
34286
+ return;
34287
+ const expectedTriggers = new Set(this.automations.map((a) => a.triggerEventType));
34288
+ for (const [eventType, subscription] of this.subscriptions) {
34289
+ if (!expectedTriggers.has(eventType)) {
34290
+ await subscription.unsubscribe().catch((err2) => {
34291
+ logger4.warn("Failed to unsubscribe orphan trigger", { eventType, error: String(err2) });
34292
+ });
34293
+ this.subscriptions.delete(eventType);
34294
+ logger4.info(`Unsubscribed from ${eventType}.* (no enabled automations)`);
34295
+ }
34296
+ }
34297
+ for (const eventType of expectedTriggers) {
34298
+ const existing = this.subscriptions.get(eventType);
34299
+ if (existing && this.isSubscriptionAlive(existing)) {
34300
+ continue;
34301
+ }
34302
+ if (existing) {
34303
+ await existing.unsubscribe().catch(() => {});
34304
+ this.subscriptions.delete(eventType);
34305
+ logger4.warn("Replacing dead subscription", { eventType });
34306
+ }
34307
+ const subscription = await this.subscribeForTrigger(eventType);
34308
+ this.subscriptions.set(eventType, subscription);
34309
+ }
34310
+ }
34311
+ async subscribeForTrigger(eventType) {
34312
+ if (!this.eventBus) {
34313
+ throw new Error("Event bus not initialized");
34314
+ }
34315
+ const durable = `automation-engine-${eventType.replace(/[^a-zA-Z0-9_-]/g, "-")}`;
34316
+ const subscription = await this.eventBus.subscribePattern(`${eventType}.>`, async (event) => {
34317
+ await this.handleEvent(event);
34318
+ }, {
34319
+ durable,
34320
+ queue: "automation-engine",
34321
+ startFrom: "new",
34322
+ maxRetries: 3,
34323
+ retryDelayMs: 1000
34324
+ });
34325
+ logger4.info(`Subscribed to ${eventType}.*`, { durable });
34326
+ return subscription;
34327
+ }
34328
+ isSubscriptionAlive(subscription) {
34329
+ return subscription.isAlive ? subscription.isAlive() : true;
34330
+ }
34331
+ rebuildDebounceManagers() {
34332
+ const enabledIds = new Set(this.automations.map((a) => a.id));
34333
+ for (const id of this.debounceManagers.keys()) {
34334
+ if (!enabledIds.has(id)) {
34335
+ this.debounceManagers.get(id)?.flushAll();
34336
+ this.debounceManagers.delete(id);
34337
+ }
34338
+ }
34339
+ for (const automation of this.automations) {
34340
+ if (automation.debounce && automation.debounce.mode !== "none" && !this.debounceManagers.has(automation.id)) {
34341
+ this.setupDebounceManager(automation);
34342
+ }
34343
+ }
34344
+ }
34345
+ startReconcileTimer() {
34346
+ this.stopReconcileTimer();
34347
+ const intervalMs = this.config.reconcileIntervalMs ?? 30000;
34348
+ if (intervalMs <= 0)
34349
+ return;
34350
+ this.reconcileEnabled = true;
34351
+ this.scheduleNextReconcile(intervalMs);
34352
+ }
34353
+ scheduleNextReconcile(intervalMs) {
34354
+ if (!this.reconcileEnabled)
34355
+ return;
34356
+ this.reconcileTimer = setTimeout(() => {
34357
+ this.reconcileSubscriptions().catch((err2) => {
34358
+ logger4.error("Reconciler tick failed", { error: String(err2) });
34359
+ }).finally(() => {
34360
+ this.scheduleNextReconcile(intervalMs);
34361
+ });
34362
+ }, intervalMs);
34363
+ if (typeof this.reconcileTimer === "object" && this.reconcileTimer && "unref" in this.reconcileTimer) {
34364
+ this.reconcileTimer.unref();
34365
+ }
34366
+ }
34367
+ stopReconcileTimer() {
34368
+ this.reconcileEnabled = false;
34369
+ if (this.reconcileTimer) {
34370
+ clearTimeout(this.reconcileTimer);
34371
+ this.reconcileTimer = null;
34274
34372
  }
34275
34373
  }
34276
34374
  async handleEvent(event) {
@@ -114079,7 +114177,7 @@ import { fileURLToPath } from "url";
114079
114177
  // package.json
114080
114178
  var package_default = {
114081
114179
  name: "@automagik/omni",
114082
- version: "2.260430.16",
114180
+ version: "2.260501.1",
114083
114181
  description: "LLM-optimized CLI for Omni",
114084
114182
  type: "module",
114085
114183
  bin: {
@@ -21136,6 +21136,9 @@ function createSubscription(options) {
21136
21136
  return {
21137
21137
  id: subscriptionId,
21138
21138
  pattern,
21139
+ isAlive() {
21140
+ return isActive;
21141
+ },
21139
21142
  async unsubscribe() {
21140
21143
  isActive = false;
21141
21144
  abortController.abort();
@@ -28371,13 +28374,16 @@ var init_debounce = __esm(() => {
28371
28374
  // ../core/src/automations/engine.ts
28372
28375
  class AutomationEngine {
28373
28376
  config;
28374
- subscriptions = [];
28377
+ subscriptions = new Map;
28375
28378
  instanceQueues = new Map;
28376
28379
  debounceManagers = new Map;
28377
28380
  automations = [];
28378
28381
  eventBus = null;
28379
28382
  deps;
28380
28383
  logger = null;
28384
+ reconcileTimer = null;
28385
+ reconcileEnabled = false;
28386
+ reconcilePromise = null;
28381
28387
  constructor(config2) {
28382
28388
  this.config = config2;
28383
28389
  this.deps = {
@@ -28394,33 +28400,17 @@ class AutomationEngine {
28394
28400
  callAgent: deps.callAgent
28395
28401
  };
28396
28402
  this.automations = automations.filter((a) => a.enabled);
28397
- const triggerTypes = new Set(this.automations.map((a) => a.triggerEventType));
28398
- for (const eventType of triggerTypes) {
28399
- const durable = `automation-engine-${eventType.replace(/[^a-zA-Z0-9_-]/g, "-")}`;
28400
- const subscription = await eventBus.subscribePattern(`${eventType}.>`, async (event) => {
28401
- await this.handleEvent(event);
28402
- }, {
28403
- durable,
28404
- queue: "automation-engine",
28405
- startFrom: "new",
28406
- maxRetries: 3,
28407
- retryDelayMs: 1000
28408
- });
28409
- this.subscriptions.push(subscription);
28410
- logger4.info(`Subscribed to ${eventType}.*`, { durable });
28411
- }
28412
- for (const automation of this.automations) {
28413
- if (automation.debounce && automation.debounce.mode !== "none") {
28414
- this.setupDebounceManager(automation);
28415
- }
28416
- }
28403
+ await this.reconcileSubscriptions();
28404
+ this.rebuildDebounceManagers();
28405
+ this.startReconcileTimer();
28417
28406
  logger4.info(`Automation engine started with ${this.automations.length} automations`);
28418
28407
  }
28419
28408
  async stop() {
28420
- for (const subscription of this.subscriptions) {
28409
+ this.stopReconcileTimer();
28410
+ for (const subscription of this.subscriptions.values()) {
28421
28411
  await subscription.unsubscribe();
28422
28412
  }
28423
- this.subscriptions = [];
28413
+ this.subscriptions.clear();
28424
28414
  for (const manager of this.debounceManagers.values()) {
28425
28415
  manager.flushAll();
28426
28416
  }
@@ -28431,9 +28421,117 @@ class AutomationEngine {
28431
28421
  this.logger = logger5;
28432
28422
  }
28433
28423
  async reload(automations) {
28434
- await this.stop();
28435
- if (this.eventBus) {
28436
- await this.start(this.eventBus, automations, this.deps);
28424
+ if (!this.eventBus) {
28425
+ this.automations = automations.filter((a) => a.enabled);
28426
+ return;
28427
+ }
28428
+ this.automations = automations.filter((a) => a.enabled);
28429
+ await this.reconcileSubscriptions();
28430
+ this.rebuildDebounceManagers();
28431
+ }
28432
+ async reconcile() {
28433
+ if (!this.eventBus)
28434
+ return;
28435
+ await this.reconcileSubscriptions();
28436
+ }
28437
+ async reconcileSubscriptions() {
28438
+ if (!this.eventBus)
28439
+ return;
28440
+ if (this.reconcilePromise)
28441
+ return this.reconcilePromise;
28442
+ this.reconcilePromise = this.doReconcileSubscriptions().finally(() => {
28443
+ this.reconcilePromise = null;
28444
+ });
28445
+ return this.reconcilePromise;
28446
+ }
28447
+ async doReconcileSubscriptions() {
28448
+ if (!this.eventBus)
28449
+ return;
28450
+ const expectedTriggers = new Set(this.automations.map((a) => a.triggerEventType));
28451
+ for (const [eventType, subscription] of this.subscriptions) {
28452
+ if (!expectedTriggers.has(eventType)) {
28453
+ await subscription.unsubscribe().catch((err) => {
28454
+ logger4.warn("Failed to unsubscribe orphan trigger", { eventType, error: String(err) });
28455
+ });
28456
+ this.subscriptions.delete(eventType);
28457
+ logger4.info(`Unsubscribed from ${eventType}.* (no enabled automations)`);
28458
+ }
28459
+ }
28460
+ for (const eventType of expectedTriggers) {
28461
+ const existing = this.subscriptions.get(eventType);
28462
+ if (existing && this.isSubscriptionAlive(existing)) {
28463
+ continue;
28464
+ }
28465
+ if (existing) {
28466
+ await existing.unsubscribe().catch(() => {});
28467
+ this.subscriptions.delete(eventType);
28468
+ logger4.warn("Replacing dead subscription", { eventType });
28469
+ }
28470
+ const subscription = await this.subscribeForTrigger(eventType);
28471
+ this.subscriptions.set(eventType, subscription);
28472
+ }
28473
+ }
28474
+ async subscribeForTrigger(eventType) {
28475
+ if (!this.eventBus) {
28476
+ throw new Error("Event bus not initialized");
28477
+ }
28478
+ const durable = `automation-engine-${eventType.replace(/[^a-zA-Z0-9_-]/g, "-")}`;
28479
+ const subscription = await this.eventBus.subscribePattern(`${eventType}.>`, async (event) => {
28480
+ await this.handleEvent(event);
28481
+ }, {
28482
+ durable,
28483
+ queue: "automation-engine",
28484
+ startFrom: "new",
28485
+ maxRetries: 3,
28486
+ retryDelayMs: 1000
28487
+ });
28488
+ logger4.info(`Subscribed to ${eventType}.*`, { durable });
28489
+ return subscription;
28490
+ }
28491
+ isSubscriptionAlive(subscription) {
28492
+ return subscription.isAlive ? subscription.isAlive() : true;
28493
+ }
28494
+ rebuildDebounceManagers() {
28495
+ const enabledIds = new Set(this.automations.map((a) => a.id));
28496
+ for (const id of this.debounceManagers.keys()) {
28497
+ if (!enabledIds.has(id)) {
28498
+ this.debounceManagers.get(id)?.flushAll();
28499
+ this.debounceManagers.delete(id);
28500
+ }
28501
+ }
28502
+ for (const automation of this.automations) {
28503
+ if (automation.debounce && automation.debounce.mode !== "none" && !this.debounceManagers.has(automation.id)) {
28504
+ this.setupDebounceManager(automation);
28505
+ }
28506
+ }
28507
+ }
28508
+ startReconcileTimer() {
28509
+ this.stopReconcileTimer();
28510
+ const intervalMs = this.config.reconcileIntervalMs ?? 30000;
28511
+ if (intervalMs <= 0)
28512
+ return;
28513
+ this.reconcileEnabled = true;
28514
+ this.scheduleNextReconcile(intervalMs);
28515
+ }
28516
+ scheduleNextReconcile(intervalMs) {
28517
+ if (!this.reconcileEnabled)
28518
+ return;
28519
+ this.reconcileTimer = setTimeout(() => {
28520
+ this.reconcileSubscriptions().catch((err) => {
28521
+ logger4.error("Reconciler tick failed", { error: String(err) });
28522
+ }).finally(() => {
28523
+ this.scheduleNextReconcile(intervalMs);
28524
+ });
28525
+ }, intervalMs);
28526
+ if (typeof this.reconcileTimer === "object" && this.reconcileTimer && "unref" in this.reconcileTimer) {
28527
+ this.reconcileTimer.unref();
28528
+ }
28529
+ }
28530
+ stopReconcileTimer() {
28531
+ this.reconcileEnabled = false;
28532
+ if (this.reconcileTimer) {
28533
+ clearTimeout(this.reconcileTimer);
28534
+ this.reconcileTimer = null;
28437
28535
  }
28438
28536
  }
28439
28537
  async handleEvent(event) {
@@ -224556,7 +224654,7 @@ var init_sentry_scrub = __esm(() => {
224556
224654
  var require_package8 = __commonJS((exports, module) => {
224557
224655
  module.exports = {
224558
224656
  name: "@omni/api",
224559
- version: "2.260430.16",
224657
+ version: "2.260501.1",
224560
224658
  type: "module",
224561
224659
  exports: {
224562
224660
  ".": {
@@ -283438,11 +283536,12 @@ class FollowUpLifecycleService {
283438
283536
  if (lastInboundCustomerMessageAt) {
283439
283537
  set.lastInboundCustomerMessageAt = lastInboundCustomerMessageAt;
283440
283538
  }
283441
- const result = await this.db.update(chatFollowUpState).set(set).where(and2(eq(chatFollowUpState.chatId, chatId), eq(chatFollowUpState.instanceId, instanceId), isNull2(chatFollowUpState.disarmReason))).returning({ id: chatFollowUpState.id });
283539
+ const reasonGuard = TERMINAL_DISARM_REASONS.has(reason) ? or2(isNull2(chatFollowUpState.disarmReason), notInArray(chatFollowUpState.disarmReason, TERMINAL_OVERRIDE_PROTECTED)) : isNull2(chatFollowUpState.disarmReason);
283540
+ const result = await this.db.update(chatFollowUpState).set(set).where(and2(eq(chatFollowUpState.chatId, chatId), eq(chatFollowUpState.instanceId, instanceId), reasonGuard)).returning({ id: chatFollowUpState.id });
283442
283541
  return { disarmed: result.length > 0 };
283443
283542
  }
283444
283543
  }
283445
- var log85, TERMINAL_DISARM_REASONS;
283544
+ var log85, TERMINAL_DISARM_REASONS, TERMINAL_OVERRIDE_PROTECTED;
283446
283545
  var init_follow_up_lifecycle = __esm(() => {
283447
283546
  init_src();
283448
283547
  init_src5();
@@ -283454,6 +283553,7 @@ var init_follow_up_lifecycle = __esm(() => {
283454
283553
  "archived",
283455
283554
  "window_expired"
283456
283555
  ]);
283556
+ TERMINAL_OVERRIDE_PROTECTED = [...TERMINAL_DISARM_REASONS, "contact_closed"];
283457
283557
  });
283458
283558
 
283459
283559
  // ../api/src/services/follow-up-sweeper.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@automagik/omni",
3
- "version": "2.260430.16",
3
+ "version": "2.260501.1",
4
4
  "description": "LLM-optimized CLI for Omni",
5
5
  "type": "module",
6
6
  "bin": {
@@ -51,15 +51,15 @@
51
51
  "qrcode-terminal": "^0.12.0"
52
52
  },
53
53
  "devDependencies": {
54
- "@omni/api": "2.260430.15",
55
- "@omni/channel-discord": "2.260430.15",
56
- "@omni/channel-gupshup": "2.260430.15",
57
- "@omni/channel-sdk": "2.260430.15",
58
- "@omni/channel-slack": "2.260430.15",
59
- "@omni/channel-telegram": "2.260430.15",
60
- "@omni/channel-whatsapp": "2.260430.15",
61
- "@omni/core": "2.260430.15",
62
- "@omni/sdk": "2.260430.15",
54
+ "@omni/api": "2.260430.16",
55
+ "@omni/channel-discord": "2.260430.16",
56
+ "@omni/channel-gupshup": "2.260430.16",
57
+ "@omni/channel-sdk": "2.260430.16",
58
+ "@omni/channel-slack": "2.260430.16",
59
+ "@omni/channel-telegram": "2.260430.16",
60
+ "@omni/channel-whatsapp": "2.260430.16",
61
+ "@omni/core": "2.260430.16",
62
+ "@omni/sdk": "2.260430.16",
63
63
  "@types/node": "^22.10.3",
64
64
  "@types/qrcode-terminal": "^0.12.2",
65
65
  "typescript": "^5.7.3"