@askexenow/exe-os 0.9.64 → 0.9.65
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/bin/cli.js +27 -6
- package/dist/bin/exe-boot.js +27 -6
- package/dist/bin/exe-link.js +27 -6
- package/dist/bin/setup.js +27 -6
- package/dist/hooks/summary-worker.js +27 -6
- package/dist/lib/cloud-sync.js +27 -6
- package/dist/lib/exe-daemon.js +90 -31
- package/dist/mcp/server.js +27 -6
- package/package.json +1 -1
package/dist/bin/cli.js
CHANGED
|
@@ -5671,31 +5671,43 @@ function logError(msg) {
|
|
|
5671
5671
|
} catch {
|
|
5672
5672
|
}
|
|
5673
5673
|
}
|
|
5674
|
+
function isTruthyEnv(value) {
|
|
5675
|
+
return /^(1|true|yes|on)$/i.test(value ?? "");
|
|
5676
|
+
}
|
|
5674
5677
|
function loadPgClient() {
|
|
5675
5678
|
if (_pgFailed) return null;
|
|
5676
|
-
const postgresUrl = process.env.DATABASE_URL;
|
|
5677
5679
|
const configPath = path14.join(EXE_AI_DIR, "config.json");
|
|
5678
5680
|
let cloudPostgresUrl;
|
|
5681
|
+
let configEnabled = false;
|
|
5679
5682
|
try {
|
|
5680
5683
|
if (existsSync14(configPath)) {
|
|
5681
5684
|
const cfg = JSON.parse(readFileSync10(configPath, "utf8"));
|
|
5682
5685
|
cloudPostgresUrl = cfg.cloud?.postgresUrl;
|
|
5683
|
-
|
|
5684
|
-
_pgFailed = true;
|
|
5685
|
-
return null;
|
|
5686
|
-
}
|
|
5686
|
+
configEnabled = cfg.cloud?.syncToPostgres === true;
|
|
5687
5687
|
}
|
|
5688
5688
|
} catch {
|
|
5689
5689
|
}
|
|
5690
|
-
const
|
|
5690
|
+
const envEnabled = isTruthyEnv(process.env.EXE_CLOUD_SYNC_TO_POSTGRES);
|
|
5691
|
+
if (!envEnabled && !configEnabled) {
|
|
5692
|
+
return null;
|
|
5693
|
+
}
|
|
5694
|
+
const url = process.env.DATABASE_URL || cloudPostgresUrl;
|
|
5691
5695
|
if (!url) {
|
|
5692
5696
|
_pgFailed = true;
|
|
5693
5697
|
return null;
|
|
5694
5698
|
}
|
|
5695
5699
|
if (!_pgPromise) {
|
|
5696
5700
|
_pgPromise = (async () => {
|
|
5701
|
+
if (!process.env.DATABASE_URL) process.env.DATABASE_URL = url;
|
|
5697
5702
|
const { createRequire: createRequire3 } = await import("module");
|
|
5698
5703
|
const { pathToFileURL: pathToFileURL3 } = await import("url");
|
|
5704
|
+
const explicitPath = process.env.EXE_OS_PRISMA_CLIENT_PATH;
|
|
5705
|
+
if (explicitPath) {
|
|
5706
|
+
const mod2 = await import(pathToFileURL3(explicitPath).href);
|
|
5707
|
+
const Ctor2 = mod2.PrismaClient ?? mod2.default?.PrismaClient;
|
|
5708
|
+
if (!Ctor2) throw new Error(`No PrismaClient at ${explicitPath}`);
|
|
5709
|
+
return new Ctor2();
|
|
5710
|
+
}
|
|
5699
5711
|
const exeDbRoot = process.env.EXE_DB_ROOT ?? path14.join(homedir2(), "exe-db");
|
|
5700
5712
|
const req = createRequire3(path14.join(exeDbRoot, "package.json"));
|
|
5701
5713
|
const entry = req.resolve("@prisma/client");
|
|
@@ -5892,6 +5904,15 @@ async function cloudSync(config) {
|
|
|
5892
5904
|
} catch {
|
|
5893
5905
|
throw new Error("[cloud-sync] Database not initialized. Call initStore() before cloudSync().");
|
|
5894
5906
|
}
|
|
5907
|
+
try {
|
|
5908
|
+
const relink = await client.execute("SELECT value FROM sync_meta WHERE key = 'cloud_relink_required' LIMIT 1");
|
|
5909
|
+
if (String(relink.rows[0]?.value ?? "") === "1") {
|
|
5910
|
+
throw new Error("[cloud-sync] Paused after key rotation. Re-link/reupload cloud sync with the new recovery phrase before syncing.");
|
|
5911
|
+
}
|
|
5912
|
+
} catch (err) {
|
|
5913
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
5914
|
+
if (msg.includes("Paused after key rotation")) throw err;
|
|
5915
|
+
}
|
|
5895
5916
|
try {
|
|
5896
5917
|
const { getRawClient: getRawClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
5897
5918
|
await getRawClient2().execute("PRAGMA wal_checkpoint(PASSIVE)");
|
package/dist/bin/exe-boot.js
CHANGED
|
@@ -9061,31 +9061,43 @@ function logError(msg) {
|
|
|
9061
9061
|
} catch {
|
|
9062
9062
|
}
|
|
9063
9063
|
}
|
|
9064
|
+
function isTruthyEnv(value) {
|
|
9065
|
+
return /^(1|true|yes|on)$/i.test(value ?? "");
|
|
9066
|
+
}
|
|
9064
9067
|
function loadPgClient() {
|
|
9065
9068
|
if (_pgFailed) return null;
|
|
9066
|
-
const postgresUrl = process.env.DATABASE_URL;
|
|
9067
9069
|
const configPath = path25.join(EXE_AI_DIR, "config.json");
|
|
9068
9070
|
let cloudPostgresUrl;
|
|
9071
|
+
let configEnabled = false;
|
|
9069
9072
|
try {
|
|
9070
9073
|
if (existsSync21(configPath)) {
|
|
9071
9074
|
const cfg = JSON.parse(readFileSync15(configPath, "utf8"));
|
|
9072
9075
|
cloudPostgresUrl = cfg.cloud?.postgresUrl;
|
|
9073
|
-
|
|
9074
|
-
_pgFailed = true;
|
|
9075
|
-
return null;
|
|
9076
|
-
}
|
|
9076
|
+
configEnabled = cfg.cloud?.syncToPostgres === true;
|
|
9077
9077
|
}
|
|
9078
9078
|
} catch {
|
|
9079
9079
|
}
|
|
9080
|
-
const
|
|
9080
|
+
const envEnabled = isTruthyEnv(process.env.EXE_CLOUD_SYNC_TO_POSTGRES);
|
|
9081
|
+
if (!envEnabled && !configEnabled) {
|
|
9082
|
+
return null;
|
|
9083
|
+
}
|
|
9084
|
+
const url = process.env.DATABASE_URL || cloudPostgresUrl;
|
|
9081
9085
|
if (!url) {
|
|
9082
9086
|
_pgFailed = true;
|
|
9083
9087
|
return null;
|
|
9084
9088
|
}
|
|
9085
9089
|
if (!_pgPromise) {
|
|
9086
9090
|
_pgPromise = (async () => {
|
|
9091
|
+
if (!process.env.DATABASE_URL) process.env.DATABASE_URL = url;
|
|
9087
9092
|
const { createRequire: createRequire3 } = await import("module");
|
|
9088
9093
|
const { pathToFileURL: pathToFileURL3 } = await import("url");
|
|
9094
|
+
const explicitPath = process.env.EXE_OS_PRISMA_CLIENT_PATH;
|
|
9095
|
+
if (explicitPath) {
|
|
9096
|
+
const mod2 = await import(pathToFileURL3(explicitPath).href);
|
|
9097
|
+
const Ctor2 = mod2.PrismaClient ?? mod2.default?.PrismaClient;
|
|
9098
|
+
if (!Ctor2) throw new Error(`No PrismaClient at ${explicitPath}`);
|
|
9099
|
+
return new Ctor2();
|
|
9100
|
+
}
|
|
9089
9101
|
const exeDbRoot = process.env.EXE_DB_ROOT ?? path25.join(homedir2(), "exe-db");
|
|
9090
9102
|
const req = createRequire3(path25.join(exeDbRoot, "package.json"));
|
|
9091
9103
|
const entry = req.resolve("@prisma/client");
|
|
@@ -9282,6 +9294,15 @@ async function cloudSync(config) {
|
|
|
9282
9294
|
} catch {
|
|
9283
9295
|
throw new Error("[cloud-sync] Database not initialized. Call initStore() before cloudSync().");
|
|
9284
9296
|
}
|
|
9297
|
+
try {
|
|
9298
|
+
const relink = await client.execute("SELECT value FROM sync_meta WHERE key = 'cloud_relink_required' LIMIT 1");
|
|
9299
|
+
if (String(relink.rows[0]?.value ?? "") === "1") {
|
|
9300
|
+
throw new Error("[cloud-sync] Paused after key rotation. Re-link/reupload cloud sync with the new recovery phrase before syncing.");
|
|
9301
|
+
}
|
|
9302
|
+
} catch (err) {
|
|
9303
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
9304
|
+
if (msg.includes("Paused after key rotation")) throw err;
|
|
9305
|
+
}
|
|
9285
9306
|
try {
|
|
9286
9307
|
const { getRawClient: getRawClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
9287
9308
|
await getRawClient2().execute("PRAGMA wal_checkpoint(PASSIVE)");
|
package/dist/bin/exe-link.js
CHANGED
|
@@ -3621,31 +3621,43 @@ function logError(msg) {
|
|
|
3621
3621
|
} catch {
|
|
3622
3622
|
}
|
|
3623
3623
|
}
|
|
3624
|
+
function isTruthyEnv(value) {
|
|
3625
|
+
return /^(1|true|yes|on)$/i.test(value ?? "");
|
|
3626
|
+
}
|
|
3624
3627
|
function loadPgClient() {
|
|
3625
3628
|
if (_pgFailed) return null;
|
|
3626
|
-
const postgresUrl = process.env.DATABASE_URL;
|
|
3627
3629
|
const configPath = path10.join(EXE_AI_DIR, "config.json");
|
|
3628
3630
|
let cloudPostgresUrl;
|
|
3631
|
+
let configEnabled = false;
|
|
3629
3632
|
try {
|
|
3630
3633
|
if (existsSync10(configPath)) {
|
|
3631
3634
|
const cfg = JSON.parse(readFileSync7(configPath, "utf8"));
|
|
3632
3635
|
cloudPostgresUrl = cfg.cloud?.postgresUrl;
|
|
3633
|
-
|
|
3634
|
-
_pgFailed = true;
|
|
3635
|
-
return null;
|
|
3636
|
-
}
|
|
3636
|
+
configEnabled = cfg.cloud?.syncToPostgres === true;
|
|
3637
3637
|
}
|
|
3638
3638
|
} catch {
|
|
3639
3639
|
}
|
|
3640
|
-
const
|
|
3640
|
+
const envEnabled = isTruthyEnv(process.env.EXE_CLOUD_SYNC_TO_POSTGRES);
|
|
3641
|
+
if (!envEnabled && !configEnabled) {
|
|
3642
|
+
return null;
|
|
3643
|
+
}
|
|
3644
|
+
const url = process.env.DATABASE_URL || cloudPostgresUrl;
|
|
3641
3645
|
if (!url) {
|
|
3642
3646
|
_pgFailed = true;
|
|
3643
3647
|
return null;
|
|
3644
3648
|
}
|
|
3645
3649
|
if (!_pgPromise) {
|
|
3646
3650
|
_pgPromise = (async () => {
|
|
3651
|
+
if (!process.env.DATABASE_URL) process.env.DATABASE_URL = url;
|
|
3647
3652
|
const { createRequire: createRequire3 } = await import("module");
|
|
3648
3653
|
const { pathToFileURL: pathToFileURL3 } = await import("url");
|
|
3654
|
+
const explicitPath = process.env.EXE_OS_PRISMA_CLIENT_PATH;
|
|
3655
|
+
if (explicitPath) {
|
|
3656
|
+
const mod2 = await import(pathToFileURL3(explicitPath).href);
|
|
3657
|
+
const Ctor2 = mod2.PrismaClient ?? mod2.default?.PrismaClient;
|
|
3658
|
+
if (!Ctor2) throw new Error(`No PrismaClient at ${explicitPath}`);
|
|
3659
|
+
return new Ctor2();
|
|
3660
|
+
}
|
|
3649
3661
|
const exeDbRoot = process.env.EXE_DB_ROOT ?? path10.join(homedir2(), "exe-db");
|
|
3650
3662
|
const req = createRequire3(path10.join(exeDbRoot, "package.json"));
|
|
3651
3663
|
const entry = req.resolve("@prisma/client");
|
|
@@ -3842,6 +3854,15 @@ async function cloudSync(config) {
|
|
|
3842
3854
|
} catch {
|
|
3843
3855
|
throw new Error("[cloud-sync] Database not initialized. Call initStore() before cloudSync().");
|
|
3844
3856
|
}
|
|
3857
|
+
try {
|
|
3858
|
+
const relink = await client.execute("SELECT value FROM sync_meta WHERE key = 'cloud_relink_required' LIMIT 1");
|
|
3859
|
+
if (String(relink.rows[0]?.value ?? "") === "1") {
|
|
3860
|
+
throw new Error("[cloud-sync] Paused after key rotation. Re-link/reupload cloud sync with the new recovery phrase before syncing.");
|
|
3861
|
+
}
|
|
3862
|
+
} catch (err) {
|
|
3863
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
3864
|
+
if (msg.includes("Paused after key rotation")) throw err;
|
|
3865
|
+
}
|
|
3845
3866
|
try {
|
|
3846
3867
|
const { getRawClient: getRawClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
3847
3868
|
await getRawClient2().execute("PRAGMA wal_checkpoint(PASSIVE)");
|
package/dist/bin/setup.js
CHANGED
|
@@ -4544,31 +4544,43 @@ function logError(msg) {
|
|
|
4544
4544
|
} catch {
|
|
4545
4545
|
}
|
|
4546
4546
|
}
|
|
4547
|
+
function isTruthyEnv(value) {
|
|
4548
|
+
return /^(1|true|yes|on)$/i.test(value ?? "");
|
|
4549
|
+
}
|
|
4547
4550
|
function loadPgClient() {
|
|
4548
4551
|
if (_pgFailed) return null;
|
|
4549
|
-
const postgresUrl = process.env.DATABASE_URL;
|
|
4550
4552
|
const configPath = path12.join(EXE_AI_DIR, "config.json");
|
|
4551
4553
|
let cloudPostgresUrl;
|
|
4554
|
+
let configEnabled = false;
|
|
4552
4555
|
try {
|
|
4553
4556
|
if (existsSync12(configPath)) {
|
|
4554
4557
|
const cfg = JSON.parse(readFileSync8(configPath, "utf8"));
|
|
4555
4558
|
cloudPostgresUrl = cfg.cloud?.postgresUrl;
|
|
4556
|
-
|
|
4557
|
-
_pgFailed = true;
|
|
4558
|
-
return null;
|
|
4559
|
-
}
|
|
4559
|
+
configEnabled = cfg.cloud?.syncToPostgres === true;
|
|
4560
4560
|
}
|
|
4561
4561
|
} catch {
|
|
4562
4562
|
}
|
|
4563
|
-
const
|
|
4563
|
+
const envEnabled = isTruthyEnv(process.env.EXE_CLOUD_SYNC_TO_POSTGRES);
|
|
4564
|
+
if (!envEnabled && !configEnabled) {
|
|
4565
|
+
return null;
|
|
4566
|
+
}
|
|
4567
|
+
const url = process.env.DATABASE_URL || cloudPostgresUrl;
|
|
4564
4568
|
if (!url) {
|
|
4565
4569
|
_pgFailed = true;
|
|
4566
4570
|
return null;
|
|
4567
4571
|
}
|
|
4568
4572
|
if (!_pgPromise) {
|
|
4569
4573
|
_pgPromise = (async () => {
|
|
4574
|
+
if (!process.env.DATABASE_URL) process.env.DATABASE_URL = url;
|
|
4570
4575
|
const { createRequire: createRequire3 } = await import("module");
|
|
4571
4576
|
const { pathToFileURL: pathToFileURL3 } = await import("url");
|
|
4577
|
+
const explicitPath = process.env.EXE_OS_PRISMA_CLIENT_PATH;
|
|
4578
|
+
if (explicitPath) {
|
|
4579
|
+
const mod2 = await import(pathToFileURL3(explicitPath).href);
|
|
4580
|
+
const Ctor2 = mod2.PrismaClient ?? mod2.default?.PrismaClient;
|
|
4581
|
+
if (!Ctor2) throw new Error(`No PrismaClient at ${explicitPath}`);
|
|
4582
|
+
return new Ctor2();
|
|
4583
|
+
}
|
|
4572
4584
|
const exeDbRoot = process.env.EXE_DB_ROOT ?? path12.join(homedir2(), "exe-db");
|
|
4573
4585
|
const req = createRequire3(path12.join(exeDbRoot, "package.json"));
|
|
4574
4586
|
const entry = req.resolve("@prisma/client");
|
|
@@ -4765,6 +4777,15 @@ async function cloudSync(config) {
|
|
|
4765
4777
|
} catch {
|
|
4766
4778
|
throw new Error("[cloud-sync] Database not initialized. Call initStore() before cloudSync().");
|
|
4767
4779
|
}
|
|
4780
|
+
try {
|
|
4781
|
+
const relink = await client.execute("SELECT value FROM sync_meta WHERE key = 'cloud_relink_required' LIMIT 1");
|
|
4782
|
+
if (String(relink.rows[0]?.value ?? "") === "1") {
|
|
4783
|
+
throw new Error("[cloud-sync] Paused after key rotation. Re-link/reupload cloud sync with the new recovery phrase before syncing.");
|
|
4784
|
+
}
|
|
4785
|
+
} catch (err) {
|
|
4786
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
4787
|
+
if (msg.includes("Paused after key rotation")) throw err;
|
|
4788
|
+
}
|
|
4768
4789
|
try {
|
|
4769
4790
|
const { getRawClient: getRawClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
4770
4791
|
await getRawClient2().execute("PRAGMA wal_checkpoint(PASSIVE)");
|
|
@@ -5679,31 +5679,43 @@ function logError(msg) {
|
|
|
5679
5679
|
} catch {
|
|
5680
5680
|
}
|
|
5681
5681
|
}
|
|
5682
|
+
function isTruthyEnv(value) {
|
|
5683
|
+
return /^(1|true|yes|on)$/i.test(value ?? "");
|
|
5684
|
+
}
|
|
5682
5685
|
function loadPgClient() {
|
|
5683
5686
|
if (_pgFailed) return null;
|
|
5684
|
-
const postgresUrl = process.env.DATABASE_URL;
|
|
5685
5687
|
const configPath = path20.join(EXE_AI_DIR, "config.json");
|
|
5686
5688
|
let cloudPostgresUrl;
|
|
5689
|
+
let configEnabled = false;
|
|
5687
5690
|
try {
|
|
5688
5691
|
if (existsSync19(configPath)) {
|
|
5689
5692
|
const cfg = JSON.parse(readFileSync13(configPath, "utf8"));
|
|
5690
5693
|
cloudPostgresUrl = cfg.cloud?.postgresUrl;
|
|
5691
|
-
|
|
5692
|
-
_pgFailed = true;
|
|
5693
|
-
return null;
|
|
5694
|
-
}
|
|
5694
|
+
configEnabled = cfg.cloud?.syncToPostgres === true;
|
|
5695
5695
|
}
|
|
5696
5696
|
} catch {
|
|
5697
5697
|
}
|
|
5698
|
-
const
|
|
5698
|
+
const envEnabled = isTruthyEnv(process.env.EXE_CLOUD_SYNC_TO_POSTGRES);
|
|
5699
|
+
if (!envEnabled && !configEnabled) {
|
|
5700
|
+
return null;
|
|
5701
|
+
}
|
|
5702
|
+
const url = process.env.DATABASE_URL || cloudPostgresUrl;
|
|
5699
5703
|
if (!url) {
|
|
5700
5704
|
_pgFailed = true;
|
|
5701
5705
|
return null;
|
|
5702
5706
|
}
|
|
5703
5707
|
if (!_pgPromise) {
|
|
5704
5708
|
_pgPromise = (async () => {
|
|
5709
|
+
if (!process.env.DATABASE_URL) process.env.DATABASE_URL = url;
|
|
5705
5710
|
const { createRequire: createRequire3 } = await import("module");
|
|
5706
5711
|
const { pathToFileURL: pathToFileURL3 } = await import("url");
|
|
5712
|
+
const explicitPath = process.env.EXE_OS_PRISMA_CLIENT_PATH;
|
|
5713
|
+
if (explicitPath) {
|
|
5714
|
+
const mod2 = await import(pathToFileURL3(explicitPath).href);
|
|
5715
|
+
const Ctor2 = mod2.PrismaClient ?? mod2.default?.PrismaClient;
|
|
5716
|
+
if (!Ctor2) throw new Error(`No PrismaClient at ${explicitPath}`);
|
|
5717
|
+
return new Ctor2();
|
|
5718
|
+
}
|
|
5707
5719
|
const exeDbRoot = process.env.EXE_DB_ROOT ?? path20.join(homedir2(), "exe-db");
|
|
5708
5720
|
const req = createRequire3(path20.join(exeDbRoot, "package.json"));
|
|
5709
5721
|
const entry = req.resolve("@prisma/client");
|
|
@@ -5900,6 +5912,15 @@ async function cloudSync(config) {
|
|
|
5900
5912
|
} catch {
|
|
5901
5913
|
throw new Error("[cloud-sync] Database not initialized. Call initStore() before cloudSync().");
|
|
5902
5914
|
}
|
|
5915
|
+
try {
|
|
5916
|
+
const relink = await client.execute("SELECT value FROM sync_meta WHERE key = 'cloud_relink_required' LIMIT 1");
|
|
5917
|
+
if (String(relink.rows[0]?.value ?? "") === "1") {
|
|
5918
|
+
throw new Error("[cloud-sync] Paused after key rotation. Re-link/reupload cloud sync with the new recovery phrase before syncing.");
|
|
5919
|
+
}
|
|
5920
|
+
} catch (err) {
|
|
5921
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
5922
|
+
if (msg.includes("Paused after key rotation")) throw err;
|
|
5923
|
+
}
|
|
5903
5924
|
try {
|
|
5904
5925
|
const { getRawClient: getRawClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
5905
5926
|
await getRawClient2().execute("PRAGMA wal_checkpoint(PASSIVE)");
|
package/dist/lib/cloud-sync.js
CHANGED
|
@@ -3421,31 +3421,43 @@ var ROSTER_LOCK_PATH = path10.join(EXE_AI_DIR, "roster-merge.lock");
|
|
|
3421
3421
|
var LOCK_STALE_MS = 3e4;
|
|
3422
3422
|
var _pgPromise = null;
|
|
3423
3423
|
var _pgFailed = false;
|
|
3424
|
+
function isTruthyEnv(value) {
|
|
3425
|
+
return /^(1|true|yes|on)$/i.test(value ?? "");
|
|
3426
|
+
}
|
|
3424
3427
|
function loadPgClient() {
|
|
3425
3428
|
if (_pgFailed) return null;
|
|
3426
|
-
const postgresUrl = process.env.DATABASE_URL;
|
|
3427
3429
|
const configPath = path10.join(EXE_AI_DIR, "config.json");
|
|
3428
3430
|
let cloudPostgresUrl;
|
|
3431
|
+
let configEnabled = false;
|
|
3429
3432
|
try {
|
|
3430
3433
|
if (existsSync10(configPath)) {
|
|
3431
3434
|
const cfg = JSON.parse(readFileSync7(configPath, "utf8"));
|
|
3432
3435
|
cloudPostgresUrl = cfg.cloud?.postgresUrl;
|
|
3433
|
-
|
|
3434
|
-
_pgFailed = true;
|
|
3435
|
-
return null;
|
|
3436
|
-
}
|
|
3436
|
+
configEnabled = cfg.cloud?.syncToPostgres === true;
|
|
3437
3437
|
}
|
|
3438
3438
|
} catch {
|
|
3439
3439
|
}
|
|
3440
|
-
const
|
|
3440
|
+
const envEnabled = isTruthyEnv(process.env.EXE_CLOUD_SYNC_TO_POSTGRES);
|
|
3441
|
+
if (!envEnabled && !configEnabled) {
|
|
3442
|
+
return null;
|
|
3443
|
+
}
|
|
3444
|
+
const url = process.env.DATABASE_URL || cloudPostgresUrl;
|
|
3441
3445
|
if (!url) {
|
|
3442
3446
|
_pgFailed = true;
|
|
3443
3447
|
return null;
|
|
3444
3448
|
}
|
|
3445
3449
|
if (!_pgPromise) {
|
|
3446
3450
|
_pgPromise = (async () => {
|
|
3451
|
+
if (!process.env.DATABASE_URL) process.env.DATABASE_URL = url;
|
|
3447
3452
|
const { createRequire: createRequire3 } = await import("module");
|
|
3448
3453
|
const { pathToFileURL: pathToFileURL3 } = await import("url");
|
|
3454
|
+
const explicitPath = process.env.EXE_OS_PRISMA_CLIENT_PATH;
|
|
3455
|
+
if (explicitPath) {
|
|
3456
|
+
const mod2 = await import(pathToFileURL3(explicitPath).href);
|
|
3457
|
+
const Ctor2 = mod2.PrismaClient ?? mod2.default?.PrismaClient;
|
|
3458
|
+
if (!Ctor2) throw new Error(`No PrismaClient at ${explicitPath}`);
|
|
3459
|
+
return new Ctor2();
|
|
3460
|
+
}
|
|
3449
3461
|
const exeDbRoot = process.env.EXE_DB_ROOT ?? path10.join(homedir2(), "exe-db");
|
|
3450
3462
|
const req = createRequire3(path10.join(exeDbRoot, "package.json"));
|
|
3451
3463
|
const entry = req.resolve("@prisma/client");
|
|
@@ -3642,6 +3654,15 @@ async function cloudSync(config) {
|
|
|
3642
3654
|
} catch {
|
|
3643
3655
|
throw new Error("[cloud-sync] Database not initialized. Call initStore() before cloudSync().");
|
|
3644
3656
|
}
|
|
3657
|
+
try {
|
|
3658
|
+
const relink = await client.execute("SELECT value FROM sync_meta WHERE key = 'cloud_relink_required' LIMIT 1");
|
|
3659
|
+
if (String(relink.rows[0]?.value ?? "") === "1") {
|
|
3660
|
+
throw new Error("[cloud-sync] Paused after key rotation. Re-link/reupload cloud sync with the new recovery phrase before syncing.");
|
|
3661
|
+
}
|
|
3662
|
+
} catch (err) {
|
|
3663
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
3664
|
+
if (msg.includes("Paused after key rotation")) throw err;
|
|
3665
|
+
}
|
|
3645
3666
|
try {
|
|
3646
3667
|
const { getRawClient: getRawClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
3647
3668
|
await getRawClient2().execute("PRAGMA wal_checkpoint(PASSIVE)");
|
package/dist/lib/exe-daemon.js
CHANGED
|
@@ -3498,10 +3498,12 @@ var init_memory_write_governor = __esm({
|
|
|
3498
3498
|
// src/lib/projection-worker.ts
|
|
3499
3499
|
var projection_worker_exports = {};
|
|
3500
3500
|
__export(projection_worker_exports, {
|
|
3501
|
+
computeProjectionBackoffMs: () => computeProjectionBackoffMs,
|
|
3501
3502
|
processProjectionBatch: () => processProjectionBatch,
|
|
3502
3503
|
projectionHandlersForTests: () => projectionHandlersForTests,
|
|
3503
3504
|
resetProjectionWorkerForTests: () => resetProjectionWorkerForTests,
|
|
3504
3505
|
setProjectionWorkerPrismaClientForTests: () => setProjectionWorkerPrismaClientForTests,
|
|
3506
|
+
shouldStartProjectionWorker: () => shouldStartProjectionWorker,
|
|
3505
3507
|
startProjectionWorker: () => startProjectionWorker,
|
|
3506
3508
|
stopProjectionWorker: () => stopProjectionWorker
|
|
3507
3509
|
});
|
|
@@ -3540,8 +3542,12 @@ function resetProjectionWorkerForTests() {
|
|
|
3540
3542
|
clearTimeout(pollTimer);
|
|
3541
3543
|
pollTimer = null;
|
|
3542
3544
|
}
|
|
3545
|
+
consecutivePollErrors = 0;
|
|
3543
3546
|
prismaPromise = null;
|
|
3544
3547
|
}
|
|
3548
|
+
function isTruthyEnv(value) {
|
|
3549
|
+
return /^(1|true|yes|on)$/i.test(value ?? "");
|
|
3550
|
+
}
|
|
3545
3551
|
async function processBatch() {
|
|
3546
3552
|
const prisma = await loadPrisma();
|
|
3547
3553
|
const events = await prisma.$queryRawUnsafe(
|
|
@@ -3583,36 +3589,65 @@ async function processBatch() {
|
|
|
3583
3589
|
}
|
|
3584
3590
|
return processed;
|
|
3585
3591
|
}
|
|
3592
|
+
async function shouldStartProjectionWorker() {
|
|
3593
|
+
try {
|
|
3594
|
+
const config2 = await loadConfig();
|
|
3595
|
+
const envEnabled = isTruthyEnv(process.env.EXE_CLOUD_SYNC_TO_POSTGRES);
|
|
3596
|
+
if (!envEnabled && config2.cloud?.syncToPostgres !== true) {
|
|
3597
|
+
return { start: false, reason: "cloud.syncToPostgres is not enabled" };
|
|
3598
|
+
}
|
|
3599
|
+
} catch (err) {
|
|
3600
|
+
return { start: false, reason: `config unavailable: ${err instanceof Error ? err.message : String(err)}` };
|
|
3601
|
+
}
|
|
3602
|
+
if (!process.env.DATABASE_URL) {
|
|
3603
|
+
return { start: false, reason: "DATABASE_URL is not set" };
|
|
3604
|
+
}
|
|
3605
|
+
const exeDbRoot = process.env.EXE_DB_ROOT ?? path8.join(os5.homedir(), "exe-db");
|
|
3606
|
+
if (!existsSync8(path8.join(exeDbRoot, "package.json")) && !process.env.EXE_OS_PRISMA_CLIENT_PATH) {
|
|
3607
|
+
return { start: false, reason: "exe-db Prisma client not found" };
|
|
3608
|
+
}
|
|
3609
|
+
return { start: true };
|
|
3610
|
+
}
|
|
3611
|
+
function computeProjectionBackoffMs(errorCount) {
|
|
3612
|
+
if (errorCount <= 0) return POLL_INTERVAL_MS;
|
|
3613
|
+
return Math.min(POLL_INTERVAL_MS * 2 ** Math.min(errorCount, 5), MAX_POLL_BACKOFF_MS);
|
|
3614
|
+
}
|
|
3586
3615
|
function startProjectionWorker() {
|
|
3587
3616
|
if (running) return;
|
|
3588
|
-
|
|
3589
|
-
const
|
|
3590
|
-
if (!
|
|
3591
|
-
process.stderr.write(
|
|
3617
|
+
void (async () => {
|
|
3618
|
+
const decision = await shouldStartProjectionWorker();
|
|
3619
|
+
if (!decision.start) {
|
|
3620
|
+
process.stderr.write(`[projection-worker] Skipped \u2014 ${decision.reason}.
|
|
3621
|
+
`);
|
|
3592
3622
|
return;
|
|
3593
3623
|
}
|
|
3594
|
-
|
|
3595
|
-
|
|
3596
|
-
|
|
3597
|
-
|
|
3598
|
-
|
|
3599
|
-
|
|
3600
|
-
|
|
3601
|
-
|
|
3602
|
-
|
|
3624
|
+
running = true;
|
|
3625
|
+
consecutivePollErrors = 0;
|
|
3626
|
+
process.stderr.write("[projection-worker] Starting...\n");
|
|
3627
|
+
const tick = async () => {
|
|
3628
|
+
if (!running) return;
|
|
3629
|
+
let nextDelay = POLL_INTERVAL_MS;
|
|
3630
|
+
try {
|
|
3631
|
+
const count = await processBatch();
|
|
3632
|
+
consecutivePollErrors = 0;
|
|
3633
|
+
if (count > 0) {
|
|
3634
|
+
process.stderr.write(`[projection-worker] Processed ${count} events.
|
|
3603
3635
|
`);
|
|
3604
|
-
|
|
3605
|
-
|
|
3606
|
-
|
|
3607
|
-
|
|
3636
|
+
}
|
|
3637
|
+
} catch (err) {
|
|
3638
|
+
consecutivePollErrors++;
|
|
3639
|
+
nextDelay = computeProjectionBackoffMs(consecutivePollErrors);
|
|
3640
|
+
process.stderr.write(
|
|
3641
|
+
`[projection-worker] Poll error (${consecutivePollErrors}; next retry ${Math.round(nextDelay / 1e3)}s): ${err instanceof Error ? err.message : String(err)}
|
|
3608
3642
|
`
|
|
3609
|
-
|
|
3610
|
-
|
|
3611
|
-
|
|
3612
|
-
|
|
3613
|
-
|
|
3614
|
-
|
|
3615
|
-
|
|
3643
|
+
);
|
|
3644
|
+
}
|
|
3645
|
+
if (running) {
|
|
3646
|
+
pollTimer = setTimeout(tick, nextDelay);
|
|
3647
|
+
}
|
|
3648
|
+
};
|
|
3649
|
+
void tick();
|
|
3650
|
+
})();
|
|
3616
3651
|
}
|
|
3617
3652
|
function stopProjectionWorker() {
|
|
3618
3653
|
running = false;
|
|
@@ -3625,10 +3660,11 @@ function stopProjectionWorker() {
|
|
|
3625
3660
|
async function processProjectionBatch() {
|
|
3626
3661
|
return processBatch();
|
|
3627
3662
|
}
|
|
3628
|
-
var prismaPromise, projectionHandlers, projectionHandlersForTests, defaultHandler, BATCH_SIZE, POLL_INTERVAL_MS, running, pollTimer;
|
|
3663
|
+
var prismaPromise, projectionHandlers, projectionHandlersForTests, defaultHandler, BATCH_SIZE, POLL_INTERVAL_MS, MAX_POLL_BACKOFF_MS, running, pollTimer, consecutivePollErrors;
|
|
3629
3664
|
var init_projection_worker = __esm({
|
|
3630
3665
|
"src/lib/projection-worker.ts"() {
|
|
3631
3666
|
"use strict";
|
|
3667
|
+
init_config();
|
|
3632
3668
|
prismaPromise = null;
|
|
3633
3669
|
projectionHandlers = {
|
|
3634
3670
|
async whatsapp(event, prisma) {
|
|
@@ -3739,8 +3775,10 @@ var init_projection_worker = __esm({
|
|
|
3739
3775
|
};
|
|
3740
3776
|
BATCH_SIZE = 50;
|
|
3741
3777
|
POLL_INTERVAL_MS = 1e4;
|
|
3778
|
+
MAX_POLL_BACKOFF_MS = 5 * 6e4;
|
|
3742
3779
|
running = false;
|
|
3743
3780
|
pollTimer = null;
|
|
3781
|
+
consecutivePollErrors = 0;
|
|
3744
3782
|
}
|
|
3745
3783
|
});
|
|
3746
3784
|
|
|
@@ -22173,31 +22211,43 @@ function logError(msg) {
|
|
|
22173
22211
|
} catch {
|
|
22174
22212
|
}
|
|
22175
22213
|
}
|
|
22214
|
+
function isTruthyEnv2(value) {
|
|
22215
|
+
return /^(1|true|yes|on)$/i.test(value ?? "");
|
|
22216
|
+
}
|
|
22176
22217
|
function loadPgClient() {
|
|
22177
22218
|
if (_pgFailed) return null;
|
|
22178
|
-
const postgresUrl = process.env.DATABASE_URL;
|
|
22179
22219
|
const configPath = path38.join(EXE_AI_DIR, "config.json");
|
|
22180
22220
|
let cloudPostgresUrl;
|
|
22221
|
+
let configEnabled = false;
|
|
22181
22222
|
try {
|
|
22182
22223
|
if (existsSync33(configPath)) {
|
|
22183
22224
|
const cfg = JSON.parse(readFileSync25(configPath, "utf8"));
|
|
22184
22225
|
cloudPostgresUrl = cfg.cloud?.postgresUrl;
|
|
22185
|
-
|
|
22186
|
-
_pgFailed = true;
|
|
22187
|
-
return null;
|
|
22188
|
-
}
|
|
22226
|
+
configEnabled = cfg.cloud?.syncToPostgres === true;
|
|
22189
22227
|
}
|
|
22190
22228
|
} catch {
|
|
22191
22229
|
}
|
|
22192
|
-
const
|
|
22230
|
+
const envEnabled = isTruthyEnv2(process.env.EXE_CLOUD_SYNC_TO_POSTGRES);
|
|
22231
|
+
if (!envEnabled && !configEnabled) {
|
|
22232
|
+
return null;
|
|
22233
|
+
}
|
|
22234
|
+
const url = process.env.DATABASE_URL || cloudPostgresUrl;
|
|
22193
22235
|
if (!url) {
|
|
22194
22236
|
_pgFailed = true;
|
|
22195
22237
|
return null;
|
|
22196
22238
|
}
|
|
22197
22239
|
if (!_pgPromise) {
|
|
22198
22240
|
_pgPromise = (async () => {
|
|
22241
|
+
if (!process.env.DATABASE_URL) process.env.DATABASE_URL = url;
|
|
22199
22242
|
const { createRequire: createRequire7 } = await import("module");
|
|
22200
22243
|
const { pathToFileURL: pathToFileURL7 } = await import("url");
|
|
22244
|
+
const explicitPath = process.env.EXE_OS_PRISMA_CLIENT_PATH;
|
|
22245
|
+
if (explicitPath) {
|
|
22246
|
+
const mod2 = await import(pathToFileURL7(explicitPath).href);
|
|
22247
|
+
const Ctor2 = mod2.PrismaClient ?? mod2.default?.PrismaClient;
|
|
22248
|
+
if (!Ctor2) throw new Error(`No PrismaClient at ${explicitPath}`);
|
|
22249
|
+
return new Ctor2();
|
|
22250
|
+
}
|
|
22201
22251
|
const exeDbRoot = process.env.EXE_DB_ROOT ?? path38.join(homedir6(), "exe-db");
|
|
22202
22252
|
const req = createRequire7(path38.join(exeDbRoot, "package.json"));
|
|
22203
22253
|
const entry = req.resolve("@prisma/client");
|
|
@@ -22394,6 +22444,15 @@ async function cloudSync(config2) {
|
|
|
22394
22444
|
} catch {
|
|
22395
22445
|
throw new Error("[cloud-sync] Database not initialized. Call initStore() before cloudSync().");
|
|
22396
22446
|
}
|
|
22447
|
+
try {
|
|
22448
|
+
const relink = await client.execute("SELECT value FROM sync_meta WHERE key = 'cloud_relink_required' LIMIT 1");
|
|
22449
|
+
if (String(relink.rows[0]?.value ?? "") === "1") {
|
|
22450
|
+
throw new Error("[cloud-sync] Paused after key rotation. Re-link/reupload cloud sync with the new recovery phrase before syncing.");
|
|
22451
|
+
}
|
|
22452
|
+
} catch (err) {
|
|
22453
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
22454
|
+
if (msg.includes("Paused after key rotation")) throw err;
|
|
22455
|
+
}
|
|
22397
22456
|
try {
|
|
22398
22457
|
const { getRawClient: getRawClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
22399
22458
|
await getRawClient2().execute("PRAGMA wal_checkpoint(PASSIVE)");
|
package/dist/mcp/server.js
CHANGED
|
@@ -19775,31 +19775,43 @@ var ROSTER_LOCK_PATH = path34.join(EXE_AI_DIR, "roster-merge.lock");
|
|
|
19775
19775
|
var LOCK_STALE_MS = 3e4;
|
|
19776
19776
|
var _pgPromise = null;
|
|
19777
19777
|
var _pgFailed = false;
|
|
19778
|
+
function isTruthyEnv(value) {
|
|
19779
|
+
return /^(1|true|yes|on)$/i.test(value ?? "");
|
|
19780
|
+
}
|
|
19778
19781
|
function loadPgClient() {
|
|
19779
19782
|
if (_pgFailed) return null;
|
|
19780
|
-
const postgresUrl = process.env.DATABASE_URL;
|
|
19781
19783
|
const configPath = path34.join(EXE_AI_DIR, "config.json");
|
|
19782
19784
|
let cloudPostgresUrl;
|
|
19785
|
+
let configEnabled = false;
|
|
19783
19786
|
try {
|
|
19784
19787
|
if (existsSync29(configPath)) {
|
|
19785
19788
|
const cfg = JSON.parse(readFileSync22(configPath, "utf8"));
|
|
19786
19789
|
cloudPostgresUrl = cfg.cloud?.postgresUrl;
|
|
19787
|
-
|
|
19788
|
-
_pgFailed = true;
|
|
19789
|
-
return null;
|
|
19790
|
-
}
|
|
19790
|
+
configEnabled = cfg.cloud?.syncToPostgres === true;
|
|
19791
19791
|
}
|
|
19792
19792
|
} catch {
|
|
19793
19793
|
}
|
|
19794
|
-
const
|
|
19794
|
+
const envEnabled = isTruthyEnv(process.env.EXE_CLOUD_SYNC_TO_POSTGRES);
|
|
19795
|
+
if (!envEnabled && !configEnabled) {
|
|
19796
|
+
return null;
|
|
19797
|
+
}
|
|
19798
|
+
const url = process.env.DATABASE_URL || cloudPostgresUrl;
|
|
19795
19799
|
if (!url) {
|
|
19796
19800
|
_pgFailed = true;
|
|
19797
19801
|
return null;
|
|
19798
19802
|
}
|
|
19799
19803
|
if (!_pgPromise) {
|
|
19800
19804
|
_pgPromise = (async () => {
|
|
19805
|
+
if (!process.env.DATABASE_URL) process.env.DATABASE_URL = url;
|
|
19801
19806
|
const { createRequire: createRequire6 } = await import("module");
|
|
19802
19807
|
const { pathToFileURL: pathToFileURL6 } = await import("url");
|
|
19808
|
+
const explicitPath = process.env.EXE_OS_PRISMA_CLIENT_PATH;
|
|
19809
|
+
if (explicitPath) {
|
|
19810
|
+
const mod2 = await import(pathToFileURL6(explicitPath).href);
|
|
19811
|
+
const Ctor2 = mod2.PrismaClient ?? mod2.default?.PrismaClient;
|
|
19812
|
+
if (!Ctor2) throw new Error(`No PrismaClient at ${explicitPath}`);
|
|
19813
|
+
return new Ctor2();
|
|
19814
|
+
}
|
|
19803
19815
|
const exeDbRoot = process.env.EXE_DB_ROOT ?? path34.join(homedir6(), "exe-db");
|
|
19804
19816
|
const req = createRequire6(path34.join(exeDbRoot, "package.json"));
|
|
19805
19817
|
const entry = req.resolve("@prisma/client");
|
|
@@ -19996,6 +20008,15 @@ async function cloudSync(config2) {
|
|
|
19996
20008
|
} catch {
|
|
19997
20009
|
throw new Error("[cloud-sync] Database not initialized. Call initStore() before cloudSync().");
|
|
19998
20010
|
}
|
|
20011
|
+
try {
|
|
20012
|
+
const relink = await client.execute("SELECT value FROM sync_meta WHERE key = 'cloud_relink_required' LIMIT 1");
|
|
20013
|
+
if (String(relink.rows[0]?.value ?? "") === "1") {
|
|
20014
|
+
throw new Error("[cloud-sync] Paused after key rotation. Re-link/reupload cloud sync with the new recovery phrase before syncing.");
|
|
20015
|
+
}
|
|
20016
|
+
} catch (err) {
|
|
20017
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
20018
|
+
if (msg.includes("Paused after key rotation")) throw err;
|
|
20019
|
+
}
|
|
19999
20020
|
try {
|
|
20000
20021
|
const { getRawClient: getRawClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
20001
20022
|
await getRawClient2().execute("PRAGMA wal_checkpoint(PASSIVE)");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@askexenow/exe-os",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.65",
|
|
4
4
|
"description": "AI employee operating system — persistent memory, task management, and multi-agent coordination for Claude Code.",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE",
|
|
6
6
|
"type": "module",
|