@automagik/omni 2.260430.16 → 2.260501.2
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/commands/doctor.d.ts +19 -0
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/index.js +362 -122
- package/dist/lib/canonical-pgserve.d.ts +55 -0
- package/dist/lib/canonical-pgserve.d.ts.map +1 -1
- package/dist/server/index.js +129 -29
- package/package.json +10 -10
|
@@ -38,6 +38,7 @@
|
|
|
38
38
|
*/
|
|
39
39
|
import { Command } from 'commander';
|
|
40
40
|
import { type Config, type ServerConfig } from '../config.js';
|
|
41
|
+
import { type EmbeddedDumpResult } from '../lib/canonical-pgserve.js';
|
|
41
42
|
/** Severity levels reported by each check. */
|
|
42
43
|
export type CheckLevel = 'OK' | 'WARN' | 'FAIL';
|
|
43
44
|
/** Identifier used in tests and --json output. */
|
|
@@ -141,6 +142,24 @@ export interface DoctorDeps {
|
|
|
141
142
|
* failure. Stubbed in tests.
|
|
142
143
|
*/
|
|
143
144
|
setupCanonicalPgserve: () => Promise<string | null>;
|
|
145
|
+
/**
|
|
146
|
+
* `pg_dump` the embedded omni DB → gzip → snapshot file. Called BEFORE
|
|
147
|
+
* the caller stops omni-api so the embedded pgserve is still live for
|
|
148
|
+
* pg_dump to connect. Returns a status so the caller can decide whether
|
|
149
|
+
* to attempt a restore later. Stubbed in tests.
|
|
150
|
+
*/
|
|
151
|
+
dumpEmbeddedDb: (currentDatabaseUrl: string) => Promise<EmbeddedDumpResult>;
|
|
152
|
+
/**
|
|
153
|
+
* Pipe a dumped snapshot into the canonical pgserve via `psql`. Called
|
|
154
|
+
* AFTER `pgserve install` has brought canonical online. No-op when the
|
|
155
|
+
* dump status was anything but `dumped`. Stubbed in tests.
|
|
156
|
+
*/
|
|
157
|
+
restoreSnapshotToCanonical: (dump: EmbeddedDumpResult, canonicalDatabaseUrl: string) => Promise<{
|
|
158
|
+
status: 'restored' | 'skipped';
|
|
159
|
+
snapshotPath?: string;
|
|
160
|
+
}>;
|
|
161
|
+
/** Resolve canonical pgserve's on-disk data dir for operator-facing logs. */
|
|
162
|
+
getCanonicalPgserveDataDir: () => string;
|
|
144
163
|
/**
|
|
145
164
|
* Persist a partial server config (merges with existing). Stubbed in
|
|
146
165
|
* tests so the canonical-pgserve fix can be validated without writing
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAMH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EACL,KAAK,MAAM,EACX,KAAK,YAAY,EAKlB,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -21292,7 +21292,7 @@ var require_node_transport = __commonJS((exports) => {
|
|
|
21292
21292
|
var util_1 = require_util();
|
|
21293
21293
|
var tls_1 = __require("tls");
|
|
21294
21294
|
var { resolve: resolve2 } = __require("path");
|
|
21295
|
-
var { readFile, existsSync:
|
|
21295
|
+
var { readFile, existsSync: existsSync10 } = __require("fs");
|
|
21296
21296
|
var dns = __require("dns");
|
|
21297
21297
|
var VERSION2 = "2.29.3";
|
|
21298
21298
|
var LANG = "nats.js";
|
|
@@ -21408,7 +21408,7 @@ var require_node_transport = __commonJS((exports) => {
|
|
|
21408
21408
|
const d = (0, nats_base_client_1.deferred)();
|
|
21409
21409
|
try {
|
|
21410
21410
|
fn = resolve2(fn);
|
|
21411
|
-
if (!
|
|
21411
|
+
if (!existsSync10(fn)) {
|
|
21412
21412
|
d.reject(new Error(`${fn} doesn't exist`));
|
|
21413
21413
|
}
|
|
21414
21414
|
readFile(fn, (err, data2) => {
|
|
@@ -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();
|
|
@@ -27201,11 +27204,11 @@ var init_dead_letter = __esm(() => {
|
|
|
27201
27204
|
});
|
|
27202
27205
|
|
|
27203
27206
|
// ../core/src/events/payload-store.ts
|
|
27204
|
-
import { gunzipSync, gzipSync } from "zlib";
|
|
27207
|
+
import { gunzipSync as gunzipSync2, gzipSync as gzipSync2 } from "zlib";
|
|
27205
27208
|
function compressPayload(payload) {
|
|
27206
27209
|
const jsonString = JSON.stringify(payload);
|
|
27207
27210
|
const originalSize = Buffer.byteLength(jsonString, "utf8");
|
|
27208
|
-
const compressed =
|
|
27211
|
+
const compressed = gzipSync2(jsonString);
|
|
27209
27212
|
const base64 = compressed.toString("base64");
|
|
27210
27213
|
const compressedSize = compressed.length;
|
|
27211
27214
|
return {
|
|
@@ -27217,7 +27220,7 @@ function compressPayload(payload) {
|
|
|
27217
27220
|
}
|
|
27218
27221
|
function decompressPayload(compressedBase64) {
|
|
27219
27222
|
const buffer2 = Buffer.from(compressedBase64, "base64");
|
|
27220
|
-
const decompressed =
|
|
27223
|
+
const decompressed = gunzipSync2(buffer2);
|
|
27221
27224
|
const jsonString = decompressed.toString("utf8");
|
|
27222
27225
|
return JSON.parse(jsonString);
|
|
27223
27226
|
}
|
|
@@ -30755,7 +30758,7 @@ var require_pushgateway = __commonJS((exports, module) => {
|
|
|
30755
30758
|
var url = __require("url");
|
|
30756
30759
|
var http = __require("http");
|
|
30757
30760
|
var https = __require("https");
|
|
30758
|
-
var { gzipSync:
|
|
30761
|
+
var { gzipSync: gzipSync3 } = __require("zlib");
|
|
30759
30762
|
var { globalRegistry } = require_registry();
|
|
30760
30763
|
|
|
30761
30764
|
class Pushgateway {
|
|
@@ -30829,7 +30832,7 @@ var require_pushgateway = __commonJS((exports, module) => {
|
|
|
30829
30832
|
if (method !== "DELETE") {
|
|
30830
30833
|
this.registry.metrics().then((metrics) => {
|
|
30831
30834
|
if (options.headers && options.headers["Content-Encoding"] === "gzip") {
|
|
30832
|
-
metrics =
|
|
30835
|
+
metrics = gzipSync3(metrics);
|
|
30833
30836
|
}
|
|
30834
30837
|
req.write(metrics);
|
|
30835
30838
|
req.end();
|
|
@@ -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
|
-
|
|
34235
|
-
|
|
34236
|
-
|
|
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
|
-
|
|
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
|
-
|
|
34272
|
-
|
|
34273
|
-
|
|
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) {
|
|
@@ -52103,8 +52201,8 @@ var init_a2a_provider = __esm(() => {
|
|
|
52103
52201
|
|
|
52104
52202
|
// ../core/src/providers/nats-genie-provider.ts
|
|
52105
52203
|
import { mkdir, writeFile } from "fs/promises";
|
|
52106
|
-
import { homedir as
|
|
52107
|
-
import { join as
|
|
52204
|
+
import { homedir as homedir8 } from "os";
|
|
52205
|
+
import { join as join13 } from "path";
|
|
52108
52206
|
|
|
52109
52207
|
class NatsGenieProvider {
|
|
52110
52208
|
id;
|
|
@@ -52294,10 +52392,10 @@ class NatsGenieProvider {
|
|
|
52294
52392
|
}
|
|
52295
52393
|
async writeDeadLetter(payload, error2) {
|
|
52296
52394
|
try {
|
|
52297
|
-
const dlDir =
|
|
52395
|
+
const dlDir = join13(homedir8(), ".omni", "dead-letters");
|
|
52298
52396
|
await mkdir(dlDir, { recursive: true });
|
|
52299
52397
|
const filename = `nats-genie-${Date.now()}-${payload.chatId}.json`;
|
|
52300
|
-
await writeFile(
|
|
52398
|
+
await writeFile(join13(dlDir, filename), JSON.stringify({
|
|
52301
52399
|
payload,
|
|
52302
52400
|
error: error2 instanceof Error ? error2.message : String(error2),
|
|
52303
52401
|
timestamp: new Date().toISOString()
|
|
@@ -54160,7 +54258,7 @@ var init_sql = __esm(() => {
|
|
|
54160
54258
|
return new SQL([new StringChunk(str)]);
|
|
54161
54259
|
}
|
|
54162
54260
|
sql2.raw = raw2;
|
|
54163
|
-
function
|
|
54261
|
+
function join14(chunks, separator) {
|
|
54164
54262
|
const result = [];
|
|
54165
54263
|
for (const [i2, chunk] of chunks.entries()) {
|
|
54166
54264
|
if (i2 > 0 && separator !== undefined) {
|
|
@@ -54170,7 +54268,7 @@ var init_sql = __esm(() => {
|
|
|
54170
54268
|
}
|
|
54171
54269
|
return new SQL(result);
|
|
54172
54270
|
}
|
|
54173
|
-
sql2.join =
|
|
54271
|
+
sql2.join = join14;
|
|
54174
54272
|
function identifier(value) {
|
|
54175
54273
|
return new Name(value);
|
|
54176
54274
|
}
|
|
@@ -57397,7 +57495,7 @@ var init_select2 = __esm(() => {
|
|
|
57397
57495
|
return (table2, on) => {
|
|
57398
57496
|
const baseTableName = this.tableName;
|
|
57399
57497
|
const tableName = getTableLikeName(table2);
|
|
57400
|
-
if (typeof tableName === "string" && this.config.joins?.some((
|
|
57498
|
+
if (typeof tableName === "string" && this.config.joins?.some((join14) => join14.alias === tableName)) {
|
|
57401
57499
|
throw new Error(`Alias "${tableName}" is already used in this query`);
|
|
57402
57500
|
}
|
|
57403
57501
|
if (!this.isPartialSelect) {
|
|
@@ -57908,7 +58006,7 @@ var init_update = __esm(() => {
|
|
|
57908
58006
|
createJoin(joinType) {
|
|
57909
58007
|
return (table2, on) => {
|
|
57910
58008
|
const tableName = getTableLikeName(table2);
|
|
57911
|
-
if (typeof tableName === "string" && this.config.joins.some((
|
|
58009
|
+
if (typeof tableName === "string" && this.config.joins.some((join14) => join14.alias === tableName)) {
|
|
57912
58010
|
throw new Error(`Alias "${tableName}" is already used in this query`);
|
|
57913
58011
|
}
|
|
57914
58012
|
if (typeof on === "function") {
|
|
@@ -57958,10 +58056,10 @@ var init_update = __esm(() => {
|
|
|
57958
58056
|
const fromFields = this.getTableLikeFields(this.config.from);
|
|
57959
58057
|
fields[tableName] = fromFields;
|
|
57960
58058
|
}
|
|
57961
|
-
for (const
|
|
57962
|
-
const tableName2 = getTableLikeName(
|
|
57963
|
-
if (typeof tableName2 === "string" && !is(
|
|
57964
|
-
const fromFields = this.getTableLikeFields(
|
|
58059
|
+
for (const join14 of this.config.joins) {
|
|
58060
|
+
const tableName2 = getTableLikeName(join14.table);
|
|
58061
|
+
if (typeof tableName2 === "string" && !is(join14.table, SQL)) {
|
|
58062
|
+
const fromFields = this.getTableLikeFields(join14.table);
|
|
57965
58063
|
fields[tableName2] = fromFields;
|
|
57966
58064
|
}
|
|
57967
58065
|
}
|
|
@@ -78097,7 +78195,7 @@ var require_path = __commonJS((exports) => {
|
|
|
78097
78195
|
function isAbsolute(path) {
|
|
78098
78196
|
return path.charAt(0) === "/";
|
|
78099
78197
|
}
|
|
78100
|
-
function
|
|
78198
|
+
function join16(...args) {
|
|
78101
78199
|
return normalizePath(args.join("/"));
|
|
78102
78200
|
}
|
|
78103
78201
|
function dirname6(path) {
|
|
@@ -78122,7 +78220,7 @@ var require_path = __commonJS((exports) => {
|
|
|
78122
78220
|
exports.basename = basename6;
|
|
78123
78221
|
exports.dirname = dirname6;
|
|
78124
78222
|
exports.isAbsolute = isAbsolute;
|
|
78125
|
-
exports.join =
|
|
78223
|
+
exports.join = join16;
|
|
78126
78224
|
exports.normalizePath = normalizePath;
|
|
78127
78225
|
exports.relative = relative;
|
|
78128
78226
|
exports.resolve = resolve4;
|
|
@@ -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.
|
|
114180
|
+
version: "2.260501.2",
|
|
114083
114181
|
description: "LLM-optimized CLI for Omni",
|
|
114084
114182
|
type: "module",
|
|
114085
114183
|
bin: {
|
|
@@ -117619,9 +117717,9 @@ function createDeadLettersCommand() {
|
|
|
117619
117717
|
}
|
|
117620
117718
|
|
|
117621
117719
|
// src/commands/doctor.ts
|
|
117622
|
-
import { existsSync as
|
|
117623
|
-
import { homedir as
|
|
117624
|
-
import { join as
|
|
117720
|
+
import { existsSync as existsSync7, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
|
|
117721
|
+
import { homedir as homedir6 } from "os";
|
|
117722
|
+
import { join as join10, resolve } from "path";
|
|
117625
117723
|
init_config();
|
|
117626
117724
|
|
|
117627
117725
|
// src/health.ts
|
|
@@ -118732,6 +118830,11 @@ WantedBy=multi-user.target
|
|
|
118732
118830
|
// src/lib/canonical-pgserve.ts
|
|
118733
118831
|
init_config();
|
|
118734
118832
|
init_output();
|
|
118833
|
+
import { spawnSync } from "child_process";
|
|
118834
|
+
import { existsSync as existsSync6, mkdirSync as mkdirSync4, readFileSync as readFileSync4, renameSync, statSync, writeFileSync as writeFileSync5 } from "fs";
|
|
118835
|
+
import { homedir as homedir5 } from "os";
|
|
118836
|
+
import { join as join8 } from "path";
|
|
118837
|
+
import { gunzipSync, gzipSync } from "zlib";
|
|
118735
118838
|
var PGSERVE_REQUIRED_VERSION = "^2.1.0";
|
|
118736
118839
|
async function isPgserveInstalled() {
|
|
118737
118840
|
try {
|
|
@@ -118825,30 +118928,148 @@ async function resolveCanonicalPgservePreference(isReinstall, cfg) {
|
|
|
118825
118928
|
raw("");
|
|
118826
118929
|
return true;
|
|
118827
118930
|
}
|
|
118931
|
+
var OMNI_EMBEDDED_PGSERVE_DATA_DIR = join8(homedir5(), ".omni", "data", "pgserve");
|
|
118932
|
+
var PGSERVE_DEFAULT_DATA_DIR = join8(homedir5(), ".pgserve", "data");
|
|
118933
|
+
var PGSERVE_CONFIG_PATH = join8(homedir5(), ".pgserve", "config.json");
|
|
118934
|
+
var OMNI_BACKUPS_DIR = join8(homedir5(), ".omni", "backups");
|
|
118935
|
+
function getEmbeddedPgserveDataDir() {
|
|
118936
|
+
return OMNI_EMBEDDED_PGSERVE_DATA_DIR;
|
|
118937
|
+
}
|
|
118938
|
+
function getCanonicalPgserveDataDir() {
|
|
118939
|
+
if (!existsSync6(PGSERVE_CONFIG_PATH))
|
|
118940
|
+
return PGSERVE_DEFAULT_DATA_DIR;
|
|
118941
|
+
try {
|
|
118942
|
+
const raw2 = readFileSync4(PGSERVE_CONFIG_PATH, "utf8");
|
|
118943
|
+
const parsed = JSON.parse(raw2);
|
|
118944
|
+
return typeof parsed.dataDir === "string" && parsed.dataDir.length > 0 ? parsed.dataDir : PGSERVE_DEFAULT_DATA_DIR;
|
|
118945
|
+
} catch {
|
|
118946
|
+
return PGSERVE_DEFAULT_DATA_DIR;
|
|
118947
|
+
}
|
|
118948
|
+
}
|
|
118949
|
+
function looksLikePgDataDir(path) {
|
|
118950
|
+
return existsSync6(join8(path, "PG_VERSION")) && existsSync6(join8(path, "base"));
|
|
118951
|
+
}
|
|
118952
|
+
function getSnapshotPath(timestamp = new Date) {
|
|
118953
|
+
const ts = timestamp.toISOString().replace(/[:.]/g, "-");
|
|
118954
|
+
return join8(OMNI_BACKUPS_DIR, `embedded-migration-${ts}.sql.gz`);
|
|
118955
|
+
}
|
|
118956
|
+
function commandIsAvailable(cmd) {
|
|
118957
|
+
try {
|
|
118958
|
+
const result = spawnSync(cmd, ["--version"], { stdio: ["ignore", "pipe", "pipe"], timeout: 3000 });
|
|
118959
|
+
return result.status === 0;
|
|
118960
|
+
} catch {
|
|
118961
|
+
return false;
|
|
118962
|
+
}
|
|
118963
|
+
}
|
|
118964
|
+
function pgEnvFromUrl(url) {
|
|
118965
|
+
const parsed = new URL(url);
|
|
118966
|
+
const env2 = {
|
|
118967
|
+
PGHOST: parsed.hostname,
|
|
118968
|
+
PGUSER: decodeURIComponent(parsed.username || "postgres"),
|
|
118969
|
+
PGDATABASE: parsed.pathname.replace(/^\//, "") || "omni"
|
|
118970
|
+
};
|
|
118971
|
+
if (parsed.port)
|
|
118972
|
+
env2.PGPORT = parsed.port;
|
|
118973
|
+
if (parsed.password)
|
|
118974
|
+
env2.PGPASSWORD = decodeURIComponent(parsed.password);
|
|
118975
|
+
return env2;
|
|
118976
|
+
}
|
|
118977
|
+
async function dumpEmbeddedDb(currentDatabaseUrl) {
|
|
118978
|
+
const embeddedDir = getEmbeddedPgserveDataDir();
|
|
118979
|
+
if (!existsSync6(embeddedDir)) {
|
|
118980
|
+
return { status: "no-embedded-data", embeddedDir };
|
|
118981
|
+
}
|
|
118982
|
+
if (!looksLikePgDataDir(embeddedDir)) {
|
|
118983
|
+
warn(`Embedded pgserve dir at ${embeddedDir} is missing PG_VERSION or base/ \u2014 does not look like a Postgres data dir. Skipping dump; canonical will start empty.`);
|
|
118984
|
+
return { status: "embedded-data-invalid", embeddedDir };
|
|
118985
|
+
}
|
|
118986
|
+
if (!commandIsAvailable("pg_dump")) {
|
|
118987
|
+
throw new Error("pg_dump not found in PATH \u2014 install postgresql-client (apt install postgresql-client / brew install postgresql) and retry");
|
|
118988
|
+
}
|
|
118989
|
+
const snapshotPath = getSnapshotPath();
|
|
118990
|
+
mkdirSync4(OMNI_BACKUPS_DIR, { recursive: true, mode: 448 });
|
|
118991
|
+
raw(" Dumping embedded database via pg_dump...");
|
|
118992
|
+
raw(` source data dir: ${embeddedDir}`);
|
|
118993
|
+
raw(` snapshot: ${snapshotPath}`);
|
|
118994
|
+
const result = spawnSync("pg_dump", ["--no-owner", "--no-acl", "--clean", "--if-exists"], {
|
|
118995
|
+
env: { ...process.env, ...pgEnvFromUrl(currentDatabaseUrl) },
|
|
118996
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
118997
|
+
timeout: 600000,
|
|
118998
|
+
maxBuffer: 1024 * 1024 * 1024 * 4
|
|
118999
|
+
});
|
|
119000
|
+
if (result.status !== 0) {
|
|
119001
|
+
const stderr = result.stderr?.toString().trim() || "unknown error";
|
|
119002
|
+
throw new Error(`pg_dump failed (exit ${result.status}): ${stderr}`);
|
|
119003
|
+
}
|
|
119004
|
+
const compressed = gzipSync(result.stdout);
|
|
119005
|
+
const tmpPath = `${snapshotPath}.tmp`;
|
|
119006
|
+
writeFileSync5(tmpPath, compressed, { mode: 384 });
|
|
119007
|
+
renameSync(tmpPath, snapshotPath);
|
|
119008
|
+
const bytes = statSync(snapshotPath).size;
|
|
119009
|
+
raw(` snapshot size: ${formatBytes(bytes)}`);
|
|
119010
|
+
await Promise.resolve();
|
|
119011
|
+
return { status: "dumped", embeddedDir, snapshotPath, bytes };
|
|
119012
|
+
}
|
|
119013
|
+
async function restoreSnapshotToCanonical(dump, canonicalDatabaseUrl) {
|
|
119014
|
+
if (dump.status !== "dumped") {
|
|
119015
|
+
return { status: "skipped" };
|
|
119016
|
+
}
|
|
119017
|
+
if (!commandIsAvailable("psql")) {
|
|
119018
|
+
throw new Error("psql not found in PATH \u2014 install postgresql-client (apt install postgresql-client / brew install postgresql) and retry");
|
|
119019
|
+
}
|
|
119020
|
+
raw(" Restoring snapshot into canonical pgserve via psql...");
|
|
119021
|
+
raw(` snapshot: ${dump.snapshotPath}`);
|
|
119022
|
+
raw(` canonical data dir: ${getCanonicalPgserveDataDir()}`);
|
|
119023
|
+
raw(` canonical URL: ${canonicalDatabaseUrl}`);
|
|
119024
|
+
const compressed = readFileSync4(dump.snapshotPath);
|
|
119025
|
+
const sql = gunzipSync(compressed);
|
|
119026
|
+
const result = spawnSync("psql", ["-v", "ON_ERROR_STOP=1"], {
|
|
119027
|
+
env: { ...process.env, ...pgEnvFromUrl(canonicalDatabaseUrl) },
|
|
119028
|
+
input: sql,
|
|
119029
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
119030
|
+
timeout: 600000,
|
|
119031
|
+
maxBuffer: 1024 * 1024 * 1024 * 4
|
|
119032
|
+
});
|
|
119033
|
+
if (result.status !== 0) {
|
|
119034
|
+
const stderr = result.stderr?.toString().trim() || "unknown error";
|
|
119035
|
+
throw new Error(`psql restore failed (exit ${result.status}): ${stderr}`);
|
|
119036
|
+
}
|
|
119037
|
+
await Promise.resolve();
|
|
119038
|
+
return { status: "restored", snapshotPath: dump.snapshotPath };
|
|
119039
|
+
}
|
|
119040
|
+
function formatBytes(n) {
|
|
119041
|
+
if (n < 1024)
|
|
119042
|
+
return `${n} B`;
|
|
119043
|
+
if (n < 1024 * 1024)
|
|
119044
|
+
return `${(n / 1024).toFixed(1)} KB`;
|
|
119045
|
+
if (n < 1024 * 1024 * 1024)
|
|
119046
|
+
return `${(n / 1024 / 1024).toFixed(1)} MB`;
|
|
119047
|
+
return `${(n / 1024 / 1024 / 1024).toFixed(2)} GB`;
|
|
119048
|
+
}
|
|
118828
119049
|
|
|
118829
119050
|
// src/commands/doctor.ts
|
|
118830
119051
|
init_output();
|
|
118831
119052
|
|
|
118832
119053
|
// src/server-bundle.ts
|
|
118833
119054
|
init_output();
|
|
118834
|
-
import { dirname as dirname2, join as
|
|
119055
|
+
import { dirname as dirname2, join as join9 } from "path";
|
|
118835
119056
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
118836
119057
|
function getServerBundlePath() {
|
|
118837
119058
|
try {
|
|
118838
119059
|
const thisFile = fileURLToPath2(import.meta.url);
|
|
118839
119060
|
const distDir = dirname2(thisFile);
|
|
118840
|
-
return
|
|
119061
|
+
return join9(distDir, "server", "index.js");
|
|
118841
119062
|
} catch {
|
|
118842
|
-
return
|
|
119063
|
+
return join9(process.cwd(), "dist", "server", "index.js");
|
|
118843
119064
|
}
|
|
118844
119065
|
}
|
|
118845
119066
|
function getServerLauncherPath() {
|
|
118846
119067
|
try {
|
|
118847
119068
|
const thisFile = fileURLToPath2(import.meta.url);
|
|
118848
119069
|
const distDir = dirname2(thisFile);
|
|
118849
|
-
return
|
|
119070
|
+
return join9(distDir, "..", "bin", "omni-server");
|
|
118850
119071
|
} catch {
|
|
118851
|
-
return
|
|
119072
|
+
return join9(process.cwd(), "bin", "omni-server");
|
|
118852
119073
|
}
|
|
118853
119074
|
}
|
|
118854
119075
|
function bundleNotFoundError(bundlePath) {
|
|
@@ -118913,10 +119134,10 @@ function productionDeps() {
|
|
|
118913
119134
|
}
|
|
118914
119135
|
},
|
|
118915
119136
|
findOrphanedDataDirs: () => {
|
|
118916
|
-
const roots = [process.cwd(),
|
|
119137
|
+
const roots = [process.cwd(), join10(homedir6(), "workspace"), join10(homedir6(), "repos")];
|
|
118917
119138
|
const found = [];
|
|
118918
119139
|
for (const root of roots) {
|
|
118919
|
-
if (!
|
|
119140
|
+
if (!existsSync7(root))
|
|
118920
119141
|
continue;
|
|
118921
119142
|
try {
|
|
118922
119143
|
scanForOrphans(root, found, 0);
|
|
@@ -118982,6 +119203,9 @@ function productionDeps() {
|
|
|
118982
119203
|
},
|
|
118983
119204
|
cliHasSigningKey: () => loadSigningContext() !== null,
|
|
118984
119205
|
setupCanonicalPgserve,
|
|
119206
|
+
dumpEmbeddedDb,
|
|
119207
|
+
restoreSnapshotToCanonical,
|
|
119208
|
+
getCanonicalPgserveDataDir,
|
|
118985
119209
|
saveServerConfig
|
|
118986
119210
|
};
|
|
118987
119211
|
}
|
|
@@ -118997,10 +119221,10 @@ function scanForOrphans(dir, acc, depth, maxDepth = 4) {
|
|
|
118997
119221
|
for (const name of entries) {
|
|
118998
119222
|
if (name === "node_modules" || name === ".git")
|
|
118999
119223
|
continue;
|
|
119000
|
-
const full =
|
|
119224
|
+
const full = join10(dir, name);
|
|
119001
119225
|
let stats;
|
|
119002
119226
|
try {
|
|
119003
|
-
stats =
|
|
119227
|
+
stats = statSync2(full);
|
|
119004
119228
|
} catch {
|
|
119005
119229
|
continue;
|
|
119006
119230
|
}
|
|
@@ -119253,12 +119477,26 @@ async function fixCliKeyValid(deps) {
|
|
|
119253
119477
|
}
|
|
119254
119478
|
async function fixPgserveCanonical(deps) {
|
|
119255
119479
|
const { serverConfig, cliConfig } = deps.loadState();
|
|
119480
|
+
let dumpResult;
|
|
119481
|
+
try {
|
|
119482
|
+
dumpResult = await deps.dumpEmbeddedDb(serverConfig.databaseUrl);
|
|
119483
|
+
} catch (err) {
|
|
119484
|
+
throw new Error(`pg_dump of embedded omni DB failed (${err instanceof Error ? err.message : String(err)}); omni-api still running on embedded \u2014 install postgresql-client (apt install postgresql-client) if pg_dump is missing, then retry`);
|
|
119485
|
+
}
|
|
119256
119486
|
await deps.runPm2(["stop", PM2_PROCESSES.api]);
|
|
119257
119487
|
const url = await deps.setupCanonicalPgserve();
|
|
119258
119488
|
if (!url) {
|
|
119259
119489
|
await deps.runPm2(["start", PM2_PROCESSES.api]);
|
|
119260
119490
|
throw new Error("canonical pgserve setup failed (pgserve binary unavailable or install failed) \u2014 install manually: bun add -g pgserve@^2.1.0");
|
|
119261
119491
|
}
|
|
119492
|
+
let restoreOutcome;
|
|
119493
|
+
try {
|
|
119494
|
+
restoreOutcome = await deps.restoreSnapshotToCanonical(dumpResult, url);
|
|
119495
|
+
} catch (err) {
|
|
119496
|
+
await deps.runPm2(["start", PM2_PROCESSES.api]);
|
|
119497
|
+
const snapshotHint = dumpResult.status === "dumped" ? ` snapshot preserved at ${dumpResult.snapshotPath}` : "";
|
|
119498
|
+
throw new Error(`psql restore into canonical pgserve failed (${err instanceof Error ? err.message : String(err)}); omni-api restarted on embedded \u2014${snapshotHint} retry by replaying the dump manually or re-running \`omni doctor --fix\``);
|
|
119499
|
+
}
|
|
119262
119500
|
deps.saveServerConfig({ databaseUrl: url, useCanonicalPgserve: true });
|
|
119263
119501
|
const env2 = buildRuntimeEnv({ ...serverConfig, databaseUrl: url, useCanonicalPgserve: true }, cliConfig);
|
|
119264
119502
|
await deps.runPm2(["delete", PM2_PROCESSES.api], env2);
|
|
@@ -119272,7 +119510,9 @@ async function fixPgserveCanonical(deps) {
|
|
|
119272
119510
|
if (startCode !== 0) {
|
|
119273
119511
|
throw new Error(`pm2 start ${PM2_PROCESSES.api} exited ${startCode} after canonical migration`);
|
|
119274
119512
|
}
|
|
119275
|
-
|
|
119513
|
+
const canonicalDir = deps.getCanonicalPgserveDataDir();
|
|
119514
|
+
const dataNote = dumpResult.status === "dumped" && restoreOutcome.status === "restored" ? `restored ${dumpResult.snapshotPath} into ${canonicalDir} (omni-api \u2192 ${url})` : dumpResult.status === "no-embedded-data" ? `no embedded data to migrate; canonical started empty at ${canonicalDir} (omni-api \u2192 ${url})` : `embedded data dir invalid; canonical started empty at ${canonicalDir} (omni-api \u2192 ${url})`;
|
|
119515
|
+
return `migrated to canonical pgserve@^2.1.0; ${dataNote}`;
|
|
119276
119516
|
}
|
|
119277
119517
|
function fixOrphanedDataDirs(deps) {
|
|
119278
119518
|
const found = deps.findOrphanedDataDirs();
|
|
@@ -119472,7 +119712,7 @@ Safety:
|
|
|
119472
119712
|
}
|
|
119473
119713
|
|
|
119474
119714
|
// src/commands/done.ts
|
|
119475
|
-
import { existsSync as
|
|
119715
|
+
import { existsSync as existsSync8, readFileSync as readFileSync5 } from "fs";
|
|
119476
119716
|
import { basename, extname } from "path";
|
|
119477
119717
|
|
|
119478
119718
|
// src/context.ts
|
|
@@ -119581,12 +119821,12 @@ async function handleReact(client, ctx, emoji) {
|
|
|
119581
119821
|
await closeTurn(client, "react", `Reacted ${emoji} + turn closed`);
|
|
119582
119822
|
}
|
|
119583
119823
|
async function handleMedia(client, ctx, mediaPath, caption) {
|
|
119584
|
-
if (!
|
|
119824
|
+
if (!existsSync8(mediaPath)) {
|
|
119585
119825
|
return error(`File not found: ${mediaPath}`);
|
|
119586
119826
|
}
|
|
119587
119827
|
try {
|
|
119588
119828
|
const mediaType = getMediaType(mediaPath);
|
|
119589
|
-
const buffer =
|
|
119829
|
+
const buffer = readFileSync5(mediaPath);
|
|
119590
119830
|
const base64 = buffer.toString("base64");
|
|
119591
119831
|
const filename = basename(mediaPath);
|
|
119592
119832
|
await client.messages.sendMedia({
|
|
@@ -120018,7 +120258,7 @@ function createEventsCommand() {
|
|
|
120018
120258
|
}
|
|
120019
120259
|
|
|
120020
120260
|
// src/commands/film.ts
|
|
120021
|
-
import { writeFileSync as
|
|
120261
|
+
import { writeFileSync as writeFileSync6 } from "fs";
|
|
120022
120262
|
import { resolve as resolvePath } from "path";
|
|
120023
120263
|
init_output();
|
|
120024
120264
|
function createFilmCommand() {
|
|
@@ -120082,7 +120322,7 @@ function createFilmCommand() {
|
|
|
120082
120322
|
const videoBuffer = Buffer.from(result.videoBase64, "base64");
|
|
120083
120323
|
if (options.output) {
|
|
120084
120324
|
const outPath = resolvePath(options.output);
|
|
120085
|
-
|
|
120325
|
+
writeFileSync6(outPath, videoBuffer);
|
|
120086
120326
|
success("Video saved", { path: outPath, sizeBytes: videoBuffer.length });
|
|
120087
120327
|
return;
|
|
120088
120328
|
}
|
|
@@ -120106,7 +120346,7 @@ function createFilmCommand() {
|
|
|
120106
120346
|
}
|
|
120107
120347
|
|
|
120108
120348
|
// src/commands/follow-up.ts
|
|
120109
|
-
import { readFileSync as
|
|
120349
|
+
import { readFileSync as readFileSync6 } from "fs";
|
|
120110
120350
|
init_output();
|
|
120111
120351
|
var VALID_SCOPES = ["agents", "instances", "chats"];
|
|
120112
120352
|
function assertScope(scope) {
|
|
@@ -120124,9 +120364,9 @@ async function resolveScopedId(scope, id) {
|
|
|
120124
120364
|
function readJsonArg(raw2) {
|
|
120125
120365
|
let body = raw2;
|
|
120126
120366
|
if (body === "-") {
|
|
120127
|
-
body =
|
|
120367
|
+
body = readFileSync6(0, "utf8");
|
|
120128
120368
|
} else if (body.startsWith("@")) {
|
|
120129
|
-
body =
|
|
120369
|
+
body = readFileSync6(body.slice(1), "utf8");
|
|
120130
120370
|
}
|
|
120131
120371
|
try {
|
|
120132
120372
|
return JSON.parse(body);
|
|
@@ -120278,8 +120518,8 @@ function createHistoryCommand() {
|
|
|
120278
120518
|
}
|
|
120279
120519
|
|
|
120280
120520
|
// src/commands/imagine.ts
|
|
120281
|
-
import { writeFileSync as
|
|
120282
|
-
import { basename as basename2, dirname as dirname3, extname as extname2, join as
|
|
120521
|
+
import { writeFileSync as writeFileSync7 } from "fs";
|
|
120522
|
+
import { basename as basename2, dirname as dirname3, extname as extname2, join as join11 } from "path";
|
|
120283
120523
|
init_output();
|
|
120284
120524
|
var ALLOWED_ASPECT_RATIOS = ["1:1", "4:3", "3:4", "16:9", "9:16", "3:2", "2:3"];
|
|
120285
120525
|
function extensionForMime(mimeType) {
|
|
@@ -120294,9 +120534,9 @@ function buildOutputPath(outputBase, index, total, mimeType) {
|
|
|
120294
120534
|
const ext = extname2(outputBase) || extensionForMime(mimeType);
|
|
120295
120535
|
const stem = basename2(outputBase, extname2(outputBase));
|
|
120296
120536
|
if (total <= 1) {
|
|
120297
|
-
return
|
|
120537
|
+
return join11(dir, `${stem}${ext}`);
|
|
120298
120538
|
}
|
|
120299
|
-
return
|
|
120539
|
+
return join11(dir, `${stem}-${index + 1}${ext}`);
|
|
120300
120540
|
}
|
|
120301
120541
|
function parseAspectRatio(value) {
|
|
120302
120542
|
if (!value)
|
|
@@ -120369,7 +120609,7 @@ function createImagineCommand() {
|
|
|
120369
120609
|
continue;
|
|
120370
120610
|
const path = buildOutputPath(options.output, i, result.images.length, image.mimeType);
|
|
120371
120611
|
try {
|
|
120372
|
-
|
|
120612
|
+
writeFileSync7(path, Buffer.from(image.base64, "base64"));
|
|
120373
120613
|
savedPaths.push(path);
|
|
120374
120614
|
} catch (err) {
|
|
120375
120615
|
const message = err instanceof Error ? err.message : "Unknown error";
|
|
@@ -120414,12 +120654,12 @@ function createImagineCommand() {
|
|
|
120414
120654
|
}
|
|
120415
120655
|
|
|
120416
120656
|
// src/commands/install.ts
|
|
120417
|
-
import { existsSync as
|
|
120418
|
-
import { homedir as
|
|
120419
|
-
import { join as
|
|
120657
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync5 } from "fs";
|
|
120658
|
+
import { homedir as homedir7 } from "os";
|
|
120659
|
+
import { join as join12 } from "path";
|
|
120420
120660
|
init_config();
|
|
120421
120661
|
init_output();
|
|
120422
|
-
var DEFAULT_DATA_DIR2 =
|
|
120662
|
+
var DEFAULT_DATA_DIR2 = join12(homedir7(), ".omni", "data");
|
|
120423
120663
|
function computeDefaultDatabaseUrl() {
|
|
120424
120664
|
return buildEmbeddedDatabaseUrl();
|
|
120425
120665
|
}
|
|
@@ -120518,13 +120758,13 @@ async function startServices(cfg, forceCleanup, forceSystemd, useCanonicalPgserv
|
|
|
120518
120758
|
return false;
|
|
120519
120759
|
}
|
|
120520
120760
|
const bundlePath = getServerBundlePath();
|
|
120521
|
-
if (!
|
|
120761
|
+
if (!existsSync9(bundlePath)) {
|
|
120522
120762
|
warn(`Server bundle not found at: ${bundlePath}
|
|
120523
120763
|
Install @automagik/omni from npm: bun add -g @automagik/omni
|
|
120524
120764
|
Or build locally: make cli-build-full`);
|
|
120525
120765
|
return false;
|
|
120526
120766
|
}
|
|
120527
|
-
|
|
120767
|
+
mkdirSync5(getPm2LogDir(), { recursive: true });
|
|
120528
120768
|
await installPm2Logrotate();
|
|
120529
120769
|
const runtimeEnv = buildInstallRuntimeEnv(cfg, forceCleanup, useCanonicalPgserve);
|
|
120530
120770
|
await runPm2(["delete", PM2_PROCESSES.api]);
|
|
@@ -120542,10 +120782,10 @@ async function startServices(cfg, forceCleanup, forceSystemd, useCanonicalPgserv
|
|
|
120542
120782
|
return false;
|
|
120543
120783
|
}
|
|
120544
120784
|
apiSpinner.succeed(`${PM2_PROCESSES.api} started`);
|
|
120545
|
-
if (
|
|
120785
|
+
if (existsSync9(NATS_BINARY_PATH)) {
|
|
120546
120786
|
const natsSpinner = ora(`Starting ${PM2_PROCESSES.nats}...`).start();
|
|
120547
|
-
const natsDataDir =
|
|
120548
|
-
|
|
120787
|
+
const natsDataDir = join12(cfg.dataDir, "nats");
|
|
120788
|
+
mkdirSync5(natsDataDir, { recursive: true });
|
|
120549
120789
|
const natsArgs = buildPm2StartArgs({
|
|
120550
120790
|
kind: "nats",
|
|
120551
120791
|
script: NATS_BINARY_PATH,
|
|
@@ -122221,7 +122461,7 @@ function createLogsCommand() {
|
|
|
122221
122461
|
}
|
|
122222
122462
|
|
|
122223
122463
|
// src/commands/media.ts
|
|
122224
|
-
import { createWriteStream as createWriteStream2, existsSync as
|
|
122464
|
+
import { createWriteStream as createWriteStream2, existsSync as existsSync11, mkdirSync as mkdirSync7, statSync as statSync4 } from "fs";
|
|
122225
122465
|
import { basename as basename4, dirname as dirname4, resolve as resolve2 } from "path";
|
|
122226
122466
|
import { Readable } from "stream";
|
|
122227
122467
|
import { pipeline } from "stream/promises";
|
|
@@ -122284,14 +122524,14 @@ function resolveOutputPath(outputPath, result) {
|
|
|
122284
122524
|
const resolved = resolve2(outputPath);
|
|
122285
122525
|
if (isDirHint)
|
|
122286
122526
|
return resolve2(resolved, filename);
|
|
122287
|
-
if (
|
|
122527
|
+
if (existsSync11(resolved) && statSync4(resolved).isDirectory())
|
|
122288
122528
|
return resolve2(resolved, filename);
|
|
122289
122529
|
return resolved;
|
|
122290
122530
|
}
|
|
122291
122531
|
async function downloadToFile(url, apiKey, destinationPath) {
|
|
122292
122532
|
const destDir = dirname4(destinationPath);
|
|
122293
|
-
if (!
|
|
122294
|
-
|
|
122533
|
+
if (!existsSync11(destDir))
|
|
122534
|
+
mkdirSync7(destDir, { recursive: true });
|
|
122295
122535
|
const resp = await fetch(url, {
|
|
122296
122536
|
method: "GET",
|
|
122297
122537
|
headers: apiKey ? { "x-api-key": apiKey } : undefined
|
|
@@ -123244,8 +123484,8 @@ init_output();
|
|
|
123244
123484
|
init_src();
|
|
123245
123485
|
import { execFileSync as execFileSync2, execSync } from "child_process";
|
|
123246
123486
|
import * as nodeCrypto2 from "crypto";
|
|
123247
|
-
import { existsSync as
|
|
123248
|
-
import { homedir as
|
|
123487
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync8, readFileSync as readFileSync8, writeFileSync as writeFileSync8 } from "fs";
|
|
123488
|
+
import { homedir as homedir9 } from "os";
|
|
123249
123489
|
import { dirname as dirname5, resolve as resolve3 } from "path";
|
|
123250
123490
|
import { createInterface as createInterface2 } from "readline";
|
|
123251
123491
|
init_config();
|
|
@@ -123472,19 +123712,19 @@ async function pairDevice(gatewayUrl, gatewayToken, keypair, spinner) {
|
|
|
123472
123712
|
ws.close(1000, "pairing complete");
|
|
123473
123713
|
}
|
|
123474
123714
|
}
|
|
123475
|
-
var OPENCLAW_CONFIG_PATH = resolve3(
|
|
123715
|
+
var OPENCLAW_CONFIG_PATH = resolve3(homedir9(), ".openclaw", "openclaw.json");
|
|
123476
123716
|
var PLUGIN_MARKER = "plugin-openclaw/omni.ts";
|
|
123477
123717
|
function readOpenClawConfig(configPath) {
|
|
123478
|
-
if (!
|
|
123718
|
+
if (!existsSync12(configPath))
|
|
123479
123719
|
return {};
|
|
123480
|
-
const raw2 =
|
|
123720
|
+
const raw2 = readFileSync8(configPath, "utf-8").trim();
|
|
123481
123721
|
if (!raw2)
|
|
123482
123722
|
return {};
|
|
123483
123723
|
return JSON.parse(raw2);
|
|
123484
123724
|
}
|
|
123485
123725
|
function writeOpenClawConfig(configPath, config2) {
|
|
123486
|
-
|
|
123487
|
-
|
|
123726
|
+
mkdirSync8(dirname5(configPath), { recursive: true, mode: 448 });
|
|
123727
|
+
writeFileSync8(configPath, `${JSON.stringify(config2, null, 2)}
|
|
123488
123728
|
`, { mode: 384 });
|
|
123489
123729
|
}
|
|
123490
123730
|
function isPluginRegistered(config2, marker, pluginPath) {
|
|
@@ -123516,10 +123756,10 @@ function isValidUuid2(value) {
|
|
|
123516
123756
|
}
|
|
123517
123757
|
function resolvePluginPath(explicit) {
|
|
123518
123758
|
if (explicit) {
|
|
123519
|
-
return
|
|
123759
|
+
return existsSync12(explicit) ? resolve3(explicit) : null;
|
|
123520
123760
|
}
|
|
123521
123761
|
const cwdCandidate = resolve3(process.cwd(), "packages/plugin-openclaw/omni.ts");
|
|
123522
|
-
return
|
|
123762
|
+
return existsSync12(cwdCandidate) ? cwdCandidate : null;
|
|
123523
123763
|
}
|
|
123524
123764
|
function registerPlugin(config2, pluginPath, configPath) {
|
|
123525
123765
|
if (hasOpenClawCli()) {
|
|
@@ -124408,7 +124648,7 @@ function createSayCommand() {
|
|
|
124408
124648
|
}
|
|
124409
124649
|
|
|
124410
124650
|
// src/commands/see.ts
|
|
124411
|
-
import { existsSync as
|
|
124651
|
+
import { existsSync as existsSync13, readFileSync as readFileSync9, statSync as statSync5 } from "fs";
|
|
124412
124652
|
import { extname as extname4 } from "path";
|
|
124413
124653
|
init_output();
|
|
124414
124654
|
var MIME_BY_EXT = {
|
|
@@ -124440,10 +124680,10 @@ function parseMaxTokens(value) {
|
|
|
124440
124680
|
return n3;
|
|
124441
124681
|
}
|
|
124442
124682
|
function loadMedia(file) {
|
|
124443
|
-
if (!
|
|
124683
|
+
if (!existsSync13(file)) {
|
|
124444
124684
|
error(`File not found: ${file}`);
|
|
124445
124685
|
}
|
|
124446
|
-
const stat =
|
|
124686
|
+
const stat = statSync5(file);
|
|
124447
124687
|
if (!stat.isFile()) {
|
|
124448
124688
|
error(`Not a regular file: ${file}`);
|
|
124449
124689
|
}
|
|
@@ -124451,7 +124691,7 @@ function loadMedia(file) {
|
|
|
124451
124691
|
error(`File is empty: ${file}`);
|
|
124452
124692
|
}
|
|
124453
124693
|
try {
|
|
124454
|
-
return { buffer:
|
|
124694
|
+
return { buffer: readFileSync9(file), mimeType: guessMimeType(file) };
|
|
124455
124695
|
} catch (err2) {
|
|
124456
124696
|
const message2 = err2 instanceof Error ? err2.message : "Unknown error";
|
|
124457
124697
|
return error(`Failed to read ${file}: ${message2}`);
|
|
@@ -124526,7 +124766,7 @@ function createSeeCommand() {
|
|
|
124526
124766
|
}
|
|
124527
124767
|
|
|
124528
124768
|
// src/commands/send.ts
|
|
124529
|
-
import { existsSync as
|
|
124769
|
+
import { existsSync as existsSync14, readFileSync as readFileSync10 } from "fs";
|
|
124530
124770
|
import { basename as basename5, extname as extname5 } from "path";
|
|
124531
124771
|
init_source();
|
|
124532
124772
|
init_config();
|
|
@@ -124546,7 +124786,7 @@ function getMediaType2(path) {
|
|
|
124546
124786
|
return "document";
|
|
124547
124787
|
}
|
|
124548
124788
|
function readFileAsBase64(path) {
|
|
124549
|
-
const buffer3 =
|
|
124789
|
+
const buffer3 = readFileSync10(path);
|
|
124550
124790
|
return buffer3.toString("base64");
|
|
124551
124791
|
}
|
|
124552
124792
|
var messageSenders = {
|
|
@@ -124567,7 +124807,7 @@ var messageSenders = {
|
|
|
124567
124807
|
const { to, media } = options3;
|
|
124568
124808
|
if (!to || !media)
|
|
124569
124809
|
return;
|
|
124570
|
-
if (!
|
|
124810
|
+
if (!existsSync14(media)) {
|
|
124571
124811
|
error(`File not found: ${media}`);
|
|
124572
124812
|
return;
|
|
124573
124813
|
}
|
|
@@ -125099,9 +125339,9 @@ function pickFilename(mimeType, provider) {
|
|
|
125099
125339
|
}
|
|
125100
125340
|
|
|
125101
125341
|
// src/commands/start.ts
|
|
125102
|
-
import { existsSync as
|
|
125103
|
-
import { homedir as
|
|
125104
|
-
import { join as
|
|
125342
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync9 } from "fs";
|
|
125343
|
+
import { homedir as homedir10 } from "os";
|
|
125344
|
+
import { join as join14 } from "path";
|
|
125105
125345
|
init_config();
|
|
125106
125346
|
init_output();
|
|
125107
125347
|
var START_HEALTH_TIMEOUT_MS = 1e4;
|
|
@@ -125110,12 +125350,12 @@ async function runStart() {
|
|
|
125110
125350
|
pm2NotFoundError();
|
|
125111
125351
|
}
|
|
125112
125352
|
const bundlePath = getServerBundlePath();
|
|
125113
|
-
if (!
|
|
125353
|
+
if (!existsSync15(bundlePath)) {
|
|
125114
125354
|
bundleNotFoundError(bundlePath);
|
|
125115
125355
|
}
|
|
125116
125356
|
const serverConfig = loadServerConfig();
|
|
125117
125357
|
const apiPort = serverConfig.port;
|
|
125118
|
-
|
|
125358
|
+
mkdirSync9(getPm2LogDir(), { recursive: true });
|
|
125119
125359
|
info(`Starting ${PM2_PROCESSES.api} (port ${apiPort})...`);
|
|
125120
125360
|
const cliConfig = loadConfig();
|
|
125121
125361
|
const env2 = buildRuntimeEnv(serverConfig, cliConfig);
|
|
@@ -125131,11 +125371,11 @@ async function runStart() {
|
|
|
125131
125371
|
error(`Failed to start ${PM2_PROCESSES.api} (pm2 exit code ${apiCode})`, undefined, 1);
|
|
125132
125372
|
return;
|
|
125133
125373
|
}
|
|
125134
|
-
const natsPath =
|
|
125135
|
-
if (
|
|
125374
|
+
const natsPath = join14(homedir10(), ".omni", "nats-server");
|
|
125375
|
+
if (existsSync15(natsPath)) {
|
|
125136
125376
|
info(`Starting ${PM2_PROCESSES.nats}...`);
|
|
125137
|
-
const natsDataDir =
|
|
125138
|
-
|
|
125377
|
+
const natsDataDir = join14(serverConfig.dataDir, "nats");
|
|
125378
|
+
mkdirSync9(natsDataDir, { recursive: true });
|
|
125139
125379
|
const natsArgs = buildPm2StartArgs({
|
|
125140
125380
|
kind: "nats",
|
|
125141
125381
|
script: natsPath,
|
|
@@ -126142,9 +126382,9 @@ function createVoiceCommand() {
|
|
|
126142
126382
|
const startTime = Date.now();
|
|
126143
126383
|
let saveDir = "";
|
|
126144
126384
|
if (opts.save) {
|
|
126145
|
-
const { mkdirSync:
|
|
126385
|
+
const { mkdirSync: mkdirSync10 } = await import("fs");
|
|
126146
126386
|
saveDir = opts.save;
|
|
126147
|
-
|
|
126387
|
+
mkdirSync10(saveDir, { recursive: true });
|
|
126148
126388
|
info(`Saving audio to: ${saveDir}`);
|
|
126149
126389
|
}
|
|
126150
126390
|
ws.onopen = () => {
|
|
@@ -126368,17 +126608,17 @@ init_config();
|
|
|
126368
126608
|
init_output();
|
|
126369
126609
|
|
|
126370
126610
|
// src/manifest-pin.ts
|
|
126371
|
-
import { existsSync as
|
|
126372
|
-
import { homedir as
|
|
126373
|
-
import { join as
|
|
126611
|
+
import { existsSync as existsSync16, readFileSync as readFileSync11, renameSync as renameSync3, writeFileSync as writeFileSync9 } from "fs";
|
|
126612
|
+
import { homedir as homedir11 } from "os";
|
|
126613
|
+
import { join as join15 } from "path";
|
|
126374
126614
|
var PACKAGE_NAME2 = "@automagik/omni";
|
|
126375
|
-
var BUN_GLOBAL_MANIFEST =
|
|
126615
|
+
var BUN_GLOBAL_MANIFEST = join15(homedir11(), ".bun", "install", "global", "package.json");
|
|
126376
126616
|
function pinManifestEntry(manifestPath, exactVersion) {
|
|
126377
|
-
if (!
|
|
126617
|
+
if (!existsSync16(manifestPath))
|
|
126378
126618
|
return false;
|
|
126379
126619
|
let manifest;
|
|
126380
126620
|
try {
|
|
126381
|
-
manifest = JSON.parse(
|
|
126621
|
+
manifest = JSON.parse(readFileSync11(manifestPath, "utf-8"));
|
|
126382
126622
|
} catch {
|
|
126383
126623
|
return false;
|
|
126384
126624
|
}
|
|
@@ -126404,9 +126644,9 @@ function pinManifestEntry(manifestPath, exactVersion) {
|
|
|
126404
126644
|
return false;
|
|
126405
126645
|
const tmp = `${manifestPath}.tmp.${process.pid}`;
|
|
126406
126646
|
try {
|
|
126407
|
-
|
|
126647
|
+
writeFileSync9(tmp, `${JSON.stringify(manifest, null, 2)}
|
|
126408
126648
|
`, { mode: 420 });
|
|
126409
|
-
|
|
126649
|
+
renameSync3(tmp, manifestPath);
|
|
126410
126650
|
} catch {
|
|
126411
126651
|
return false;
|
|
126412
126652
|
}
|
|
@@ -47,4 +47,59 @@ export declare function setupCanonicalPgserve(): Promise<string | null>;
|
|
|
47
47
|
export declare function resolveCanonicalPgservePreference(isReinstall: boolean, cfg: {
|
|
48
48
|
databaseUrl: string;
|
|
49
49
|
}): Promise<boolean>;
|
|
50
|
+
/**
|
|
51
|
+
* Resolve the canonical pgserve data dir from `~/.pgserve/config.json`.
|
|
52
|
+
* pgserve writes `{dataDir, port, registeredAt}` during `pgserve install`.
|
|
53
|
+
* Falls back to `~/.pgserve/data` (pgserve's documented default) when the
|
|
54
|
+
* config file doesn't exist yet.
|
|
55
|
+
*
|
|
56
|
+
* Surfaced in operator output so the migration's destination is explicit:
|
|
57
|
+
* the operator can `du -sh` and `ls` that path post-migration to verify
|
|
58
|
+
* the cluster is on disk where they expect.
|
|
59
|
+
*/
|
|
60
|
+
export declare function getCanonicalPgserveDataDir(): string;
|
|
61
|
+
/**
|
|
62
|
+
* Outcome of the dump step. Caller decides whether to proceed with restore.
|
|
63
|
+
*/
|
|
64
|
+
export type EmbeddedDumpResult = {
|
|
65
|
+
status: 'no-embedded-data';
|
|
66
|
+
embeddedDir: string;
|
|
67
|
+
} | {
|
|
68
|
+
status: 'embedded-data-invalid';
|
|
69
|
+
embeddedDir: string;
|
|
70
|
+
} | {
|
|
71
|
+
status: 'dumped';
|
|
72
|
+
embeddedDir: string;
|
|
73
|
+
snapshotPath: string;
|
|
74
|
+
bytes: number;
|
|
75
|
+
};
|
|
76
|
+
/**
|
|
77
|
+
* Dump the embedded `omni` database to a gzipped SQL snapshot. Called BEFORE
|
|
78
|
+
* the caller stops omni-api — embedded pgserve must still be live so pg_dump
|
|
79
|
+
* can connect.
|
|
80
|
+
*
|
|
81
|
+
* Returns:
|
|
82
|
+
* - `no-embedded-data` when there's no embedded data dir (fresh install
|
|
83
|
+
* case — caller proceeds with an empty canonical).
|
|
84
|
+
* - `embedded-data-invalid` when the dir exists but isn't a Postgres data
|
|
85
|
+
* dir (corrupt / partial init — caller warns + proceeds empty).
|
|
86
|
+
* - `dumped` with snapshot path + size on success.
|
|
87
|
+
*
|
|
88
|
+
* Throws when pg_dump is missing from PATH or exits non-zero. Caller is
|
|
89
|
+
* responsible for catching and rolling back omni-api to embedded.
|
|
90
|
+
*/
|
|
91
|
+
export declare function dumpEmbeddedDb(currentDatabaseUrl: string): Promise<EmbeddedDumpResult>;
|
|
92
|
+
/**
|
|
93
|
+
* Restore a dumped snapshot into the canonical pgserve. Called AFTER the
|
|
94
|
+
* caller has run `pgserve install` and confirmed canonical is reachable
|
|
95
|
+
* at the URL. No-op when the snapshot status was anything but `dumped`.
|
|
96
|
+
*
|
|
97
|
+
* Uses `psql ON_ERROR_STOP=1` so a partial failure surfaces a non-zero exit
|
|
98
|
+
* instead of leaving the canonical DB half-restored. Throws on any psql
|
|
99
|
+
* error — caller rolls back to embedded.
|
|
100
|
+
*/
|
|
101
|
+
export declare function restoreSnapshotToCanonical(dump: EmbeddedDumpResult, canonicalDatabaseUrl: string): Promise<{
|
|
102
|
+
status: 'restored' | 'skipped';
|
|
103
|
+
snapshotPath?: string;
|
|
104
|
+
}>;
|
|
50
105
|
//# sourceMappingURL=canonical-pgserve.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"canonical-pgserve.d.ts","sourceRoot":"","sources":["../../src/lib/canonical-pgserve.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;
|
|
1
|
+
{"version":3,"file":"canonical-pgserve.d.ts","sourceRoot":"","sources":["../../src/lib/canonical-pgserve.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AA2IH;;;;;;GAMG;AACH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CASpE;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,iCAAiC,CACrD,WAAW,EAAE,OAAO,EACpB,GAAG,EAAE;IAAE,WAAW,EAAE,MAAM,CAAA;CAAE,GAC3B,OAAO,CAAC,OAAO,CAAC,CA6BlB;AAwDD;;;;;;;;;GASG;AACH,wBAAgB,0BAA0B,IAAI,MAAM,CASnD;AAuCD;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAC1B;IAAE,MAAM,EAAE,kBAAkB,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GACnD;IAAE,MAAM,EAAE,uBAAuB,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GACxD;IAAE,MAAM,EAAE,QAAQ,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnF;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,cAAc,CAAC,kBAAkB,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC,CA6D5F;AAED;;;;;;;;GAQG;AACH,wBAAsB,0BAA0B,CAC9C,IAAI,EAAE,kBAAkB,EACxB,oBAAoB,EAAE,MAAM,GAC3B,OAAO,CAAC;IAAE,MAAM,EAAE,UAAU,GAAG,SAAS,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAoCpE"}
|
package/dist/server/index.js
CHANGED
|
@@ -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
|
-
|
|
28398
|
-
|
|
28399
|
-
|
|
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
|
-
|
|
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
|
-
|
|
28435
|
-
|
|
28436
|
-
|
|
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.
|
|
224657
|
+
version: "2.260501.2",
|
|
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
|
|
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.
|
|
3
|
+
"version": "2.260501.2",
|
|
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.
|
|
55
|
-
"@omni/channel-discord": "2.
|
|
56
|
-
"@omni/channel-gupshup": "2.
|
|
57
|
-
"@omni/channel-sdk": "2.
|
|
58
|
-
"@omni/channel-slack": "2.
|
|
59
|
-
"@omni/channel-telegram": "2.
|
|
60
|
-
"@omni/channel-whatsapp": "2.
|
|
61
|
-
"@omni/core": "2.
|
|
62
|
-
"@omni/sdk": "2.
|
|
54
|
+
"@omni/api": "2.260501.1",
|
|
55
|
+
"@omni/channel-discord": "2.260501.1",
|
|
56
|
+
"@omni/channel-gupshup": "2.260501.1",
|
|
57
|
+
"@omni/channel-sdk": "2.260501.1",
|
|
58
|
+
"@omni/channel-slack": "2.260501.1",
|
|
59
|
+
"@omni/channel-telegram": "2.260501.1",
|
|
60
|
+
"@omni/channel-whatsapp": "2.260501.1",
|
|
61
|
+
"@omni/core": "2.260501.1",
|
|
62
|
+
"@omni/sdk": "2.260501.1",
|
|
63
63
|
"@types/node": "^22.10.3",
|
|
64
64
|
"@types/qrcode-terminal": "^0.12.2",
|
|
65
65
|
"typescript": "^5.7.3"
|