@askexenow/exe-os 0.8.32 → 0.8.36
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/backfill-conversations.js +332 -348
- package/dist/bin/backfill-responses.js +72 -12
- package/dist/bin/backfill-vectors.js +72 -12
- package/dist/bin/cleanup-stale-review-tasks.js +63 -3
- package/dist/bin/cli.js +1518 -1122
- package/dist/bin/exe-agent.js +4 -4
- package/dist/bin/exe-assign.js +80 -18
- package/dist/bin/exe-boot.js +408 -89
- package/dist/bin/exe-call.js +83 -24
- package/dist/bin/exe-dispatch.js +18 -10
- package/dist/bin/exe-doctor.js +63 -3
- package/dist/bin/exe-export-behaviors.js +64 -3
- package/dist/bin/exe-forget.js +69 -4
- package/dist/bin/exe-gateway.js +121 -36
- package/dist/bin/exe-heartbeat.js +77 -13
- package/dist/bin/exe-kill.js +64 -3
- package/dist/bin/exe-launch-agent.js +162 -35
- package/dist/bin/exe-link.js +946 -0
- package/dist/bin/exe-new-employee.js +121 -36
- package/dist/bin/exe-pending-messages.js +72 -7
- package/dist/bin/exe-pending-notifications.js +63 -3
- package/dist/bin/exe-pending-reviews.js +75 -10
- package/dist/bin/exe-rename.js +1287 -0
- package/dist/bin/exe-review.js +64 -4
- package/dist/bin/exe-search.js +79 -13
- package/dist/bin/exe-session-cleanup.js +91 -26
- package/dist/bin/exe-status.js +64 -4
- package/dist/bin/exe-team.js +64 -4
- package/dist/bin/git-sweep.js +71 -4
- package/dist/bin/graph-backfill.js +64 -3
- package/dist/bin/graph-export.js +64 -3
- package/dist/bin/install.js +3 -3
- package/dist/bin/scan-tasks.js +71 -4
- package/dist/bin/setup.js +156 -38
- package/dist/bin/shard-migrate.js +64 -3
- package/dist/bin/wiki-sync.js +64 -3
- package/dist/gateway/index.js +122 -37
- package/dist/hooks/bug-report-worker.js +209 -23
- package/dist/hooks/commit-complete.js +71 -4
- package/dist/hooks/error-recall.js +79 -13
- package/dist/hooks/ingest-worker.js +129 -43
- package/dist/hooks/instructions-loaded.js +71 -4
- package/dist/hooks/notification.js +71 -4
- package/dist/hooks/post-compact.js +71 -4
- package/dist/hooks/pre-compact.js +71 -4
- package/dist/hooks/pre-tool-use.js +413 -194
- package/dist/hooks/prompt-ingest-worker.js +82 -22
- package/dist/hooks/prompt-submit.js +103 -37
- package/dist/hooks/response-ingest-worker.js +87 -22
- package/dist/hooks/session-end.js +71 -4
- package/dist/hooks/session-start.js +79 -13
- package/dist/hooks/stop.js +71 -4
- package/dist/hooks/subagent-stop.js +71 -4
- package/dist/hooks/summary-worker.js +303 -50
- package/dist/index.js +134 -46
- package/dist/lib/cloud-sync.js +209 -15
- package/dist/lib/consolidation.js +4 -4
- package/dist/lib/database.js +64 -2
- package/dist/lib/device-registry.js +70 -3
- package/dist/lib/employee-templates.js +48 -22
- package/dist/lib/employees.js +34 -1
- package/dist/lib/exe-daemon.js +136 -53
- package/dist/lib/hybrid-search.js +79 -13
- package/dist/lib/identity-templates.js +57 -6
- package/dist/lib/identity.js +3 -3
- package/dist/lib/messaging.js +22 -14
- package/dist/lib/reminders.js +3 -3
- package/dist/lib/schedules.js +63 -3
- package/dist/lib/skill-learning.js +3 -3
- package/dist/lib/status-brief.js +63 -5
- package/dist/lib/store.js +64 -3
- package/dist/lib/task-router.js +4 -2
- package/dist/lib/tasks.js +48 -21
- package/dist/lib/tmux-routing.js +47 -20
- package/dist/mcp/server.js +727 -58
- package/dist/mcp/tools/complete-reminder.js +3 -3
- package/dist/mcp/tools/create-reminder.js +3 -3
- package/dist/mcp/tools/create-task.js +151 -24
- package/dist/mcp/tools/deactivate-behavior.js +3 -3
- package/dist/mcp/tools/list-reminders.js +3 -3
- package/dist/mcp/tools/list-tasks.js +17 -8
- package/dist/mcp/tools/send-message.js +24 -16
- package/dist/mcp/tools/update-task.js +25 -16
- package/dist/runtime/index.js +112 -24
- package/dist/tui/App.js +139 -36
- package/package.json +6 -2
- package/src/commands/exe/rename.md +12 -0
|
@@ -262,7 +262,7 @@ function listShards() {
|
|
|
262
262
|
}
|
|
263
263
|
async function ensureShardSchema(client) {
|
|
264
264
|
await client.execute("PRAGMA journal_mode = WAL");
|
|
265
|
-
await client.execute("PRAGMA busy_timeout =
|
|
265
|
+
await client.execute("PRAGMA busy_timeout = 30000");
|
|
266
266
|
try {
|
|
267
267
|
await client.execute("PRAGMA libsql_vector_search_ef = 128");
|
|
268
268
|
} catch {
|
|
@@ -459,12 +459,65 @@ var EMBEDDING_DIM = 1024;
|
|
|
459
459
|
|
|
460
460
|
// src/lib/database.ts
|
|
461
461
|
import { createClient } from "@libsql/client";
|
|
462
|
+
|
|
463
|
+
// src/lib/db-retry.ts
|
|
464
|
+
var MAX_RETRIES = 3;
|
|
465
|
+
var BASE_DELAY_MS = 200;
|
|
466
|
+
var MAX_JITTER_MS = 300;
|
|
467
|
+
function isBusyError(err) {
|
|
468
|
+
if (err instanceof Error) {
|
|
469
|
+
const msg = err.message.toLowerCase();
|
|
470
|
+
return msg.includes("sqlite_busy") || msg.includes("database is locked");
|
|
471
|
+
}
|
|
472
|
+
return false;
|
|
473
|
+
}
|
|
474
|
+
function delay(ms) {
|
|
475
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
476
|
+
}
|
|
477
|
+
async function retryOnBusy(fn, label) {
|
|
478
|
+
let lastError;
|
|
479
|
+
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
480
|
+
try {
|
|
481
|
+
return await fn();
|
|
482
|
+
} catch (err) {
|
|
483
|
+
lastError = err;
|
|
484
|
+
if (!isBusyError(err) || attempt === MAX_RETRIES) {
|
|
485
|
+
throw err;
|
|
486
|
+
}
|
|
487
|
+
const backoff = BASE_DELAY_MS * Math.pow(2, attempt);
|
|
488
|
+
const jitter = Math.floor(Math.random() * MAX_JITTER_MS);
|
|
489
|
+
process.stderr.write(
|
|
490
|
+
`[exe-os] SQLITE_BUSY ${label} retry ${attempt + 1}/${MAX_RETRIES} \u2014 waiting ${backoff + jitter}ms
|
|
491
|
+
`
|
|
492
|
+
);
|
|
493
|
+
await delay(backoff + jitter);
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
throw lastError;
|
|
497
|
+
}
|
|
498
|
+
function wrapWithRetry(client) {
|
|
499
|
+
return new Proxy(client, {
|
|
500
|
+
get(target, prop, receiver) {
|
|
501
|
+
if (prop === "execute") {
|
|
502
|
+
return (sql) => retryOnBusy(() => target.execute(sql), "execute");
|
|
503
|
+
}
|
|
504
|
+
if (prop === "batch") {
|
|
505
|
+
return (stmts) => retryOnBusy(() => target.batch(stmts), "batch");
|
|
506
|
+
}
|
|
507
|
+
return Reflect.get(target, prop, receiver);
|
|
508
|
+
}
|
|
509
|
+
});
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
// src/lib/database.ts
|
|
462
513
|
var _client = null;
|
|
514
|
+
var _resilientClient = null;
|
|
463
515
|
var initTurso = initDatabase;
|
|
464
516
|
async function initDatabase(config) {
|
|
465
517
|
if (_client) {
|
|
466
518
|
_client.close();
|
|
467
519
|
_client = null;
|
|
520
|
+
_resilientClient = null;
|
|
468
521
|
}
|
|
469
522
|
const opts = {
|
|
470
523
|
url: `file:${config.dbPath}`
|
|
@@ -473,17 +526,24 @@ async function initDatabase(config) {
|
|
|
473
526
|
opts.encryptionKey = config.encryptionKey;
|
|
474
527
|
}
|
|
475
528
|
_client = createClient(opts);
|
|
529
|
+
_resilientClient = wrapWithRetry(_client);
|
|
476
530
|
}
|
|
477
531
|
function getClient() {
|
|
532
|
+
if (!_resilientClient) {
|
|
533
|
+
throw new Error("Database client not initialized. Call initDatabase() first.");
|
|
534
|
+
}
|
|
535
|
+
return _resilientClient;
|
|
536
|
+
}
|
|
537
|
+
function getRawClient() {
|
|
478
538
|
if (!_client) {
|
|
479
539
|
throw new Error("Database client not initialized. Call initDatabase() first.");
|
|
480
540
|
}
|
|
481
541
|
return _client;
|
|
482
542
|
}
|
|
483
543
|
async function ensureSchema() {
|
|
484
|
-
const client =
|
|
544
|
+
const client = getRawClient();
|
|
485
545
|
await client.execute("PRAGMA journal_mode = WAL");
|
|
486
|
-
await client.execute("PRAGMA busy_timeout =
|
|
546
|
+
await client.execute("PRAGMA busy_timeout = 30000");
|
|
487
547
|
try {
|
|
488
548
|
await client.execute("PRAGMA libsql_vector_search_ef = 128");
|
|
489
549
|
} catch {
|
|
@@ -1732,11 +1792,11 @@ async function connectEmbedDaemon() {
|
|
|
1732
1792
|
}
|
|
1733
1793
|
}
|
|
1734
1794
|
const start = Date.now();
|
|
1735
|
-
let
|
|
1795
|
+
let delay2 = 100;
|
|
1736
1796
|
while (Date.now() - start < CONNECT_TIMEOUT_MS) {
|
|
1737
|
-
await new Promise((r) => setTimeout(r,
|
|
1797
|
+
await new Promise((r) => setTimeout(r, delay2));
|
|
1738
1798
|
if (await connectToSocket()) return true;
|
|
1739
|
-
|
|
1799
|
+
delay2 = Math.min(delay2 * 2, 3e3);
|
|
1740
1800
|
}
|
|
1741
1801
|
return false;
|
|
1742
1802
|
}
|
|
@@ -1828,11 +1888,11 @@ async function embedViaClient(text, priority = "high") {
|
|
|
1828
1888
|
`);
|
|
1829
1889
|
killAndRespawnDaemon();
|
|
1830
1890
|
const start = Date.now();
|
|
1831
|
-
let
|
|
1891
|
+
let delay2 = 200;
|
|
1832
1892
|
while (Date.now() - start < CONNECT_TIMEOUT_MS) {
|
|
1833
|
-
await new Promise((r) => setTimeout(r,
|
|
1893
|
+
await new Promise((r) => setTimeout(r, delay2));
|
|
1834
1894
|
if (await connectToSocket()) break;
|
|
1835
|
-
|
|
1895
|
+
delay2 = Math.min(delay2 * 2, 3e3);
|
|
1836
1896
|
}
|
|
1837
1897
|
if (!_connected) return null;
|
|
1838
1898
|
}
|
|
@@ -1844,11 +1904,11 @@ async function embedViaClient(text, priority = "high") {
|
|
|
1844
1904
|
`);
|
|
1845
1905
|
killAndRespawnDaemon();
|
|
1846
1906
|
const start = Date.now();
|
|
1847
|
-
let
|
|
1907
|
+
let delay2 = 200;
|
|
1848
1908
|
while (Date.now() - start < CONNECT_TIMEOUT_MS) {
|
|
1849
|
-
await new Promise((r) => setTimeout(r,
|
|
1909
|
+
await new Promise((r) => setTimeout(r, delay2));
|
|
1850
1910
|
if (await connectToSocket()) break;
|
|
1851
|
-
|
|
1911
|
+
delay2 = Math.min(delay2 * 2, 3e3);
|
|
1852
1912
|
}
|
|
1853
1913
|
if (!_connected) return null;
|
|
1854
1914
|
const retry = await sendRequest([text], priority);
|
|
@@ -262,7 +262,7 @@ function listShards() {
|
|
|
262
262
|
}
|
|
263
263
|
async function ensureShardSchema(client) {
|
|
264
264
|
await client.execute("PRAGMA journal_mode = WAL");
|
|
265
|
-
await client.execute("PRAGMA busy_timeout =
|
|
265
|
+
await client.execute("PRAGMA busy_timeout = 30000");
|
|
266
266
|
try {
|
|
267
267
|
await client.execute("PRAGMA libsql_vector_search_ef = 128");
|
|
268
268
|
} catch {
|
|
@@ -448,12 +448,65 @@ var init_shard_manager = __esm({
|
|
|
448
448
|
|
|
449
449
|
// src/lib/database.ts
|
|
450
450
|
import { createClient } from "@libsql/client";
|
|
451
|
+
|
|
452
|
+
// src/lib/db-retry.ts
|
|
453
|
+
var MAX_RETRIES = 3;
|
|
454
|
+
var BASE_DELAY_MS = 200;
|
|
455
|
+
var MAX_JITTER_MS = 300;
|
|
456
|
+
function isBusyError(err) {
|
|
457
|
+
if (err instanceof Error) {
|
|
458
|
+
const msg = err.message.toLowerCase();
|
|
459
|
+
return msg.includes("sqlite_busy") || msg.includes("database is locked");
|
|
460
|
+
}
|
|
461
|
+
return false;
|
|
462
|
+
}
|
|
463
|
+
function delay(ms) {
|
|
464
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
465
|
+
}
|
|
466
|
+
async function retryOnBusy(fn, label) {
|
|
467
|
+
let lastError;
|
|
468
|
+
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
469
|
+
try {
|
|
470
|
+
return await fn();
|
|
471
|
+
} catch (err) {
|
|
472
|
+
lastError = err;
|
|
473
|
+
if (!isBusyError(err) || attempt === MAX_RETRIES) {
|
|
474
|
+
throw err;
|
|
475
|
+
}
|
|
476
|
+
const backoff = BASE_DELAY_MS * Math.pow(2, attempt);
|
|
477
|
+
const jitter = Math.floor(Math.random() * MAX_JITTER_MS);
|
|
478
|
+
process.stderr.write(
|
|
479
|
+
`[exe-os] SQLITE_BUSY ${label} retry ${attempt + 1}/${MAX_RETRIES} \u2014 waiting ${backoff + jitter}ms
|
|
480
|
+
`
|
|
481
|
+
);
|
|
482
|
+
await delay(backoff + jitter);
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
throw lastError;
|
|
486
|
+
}
|
|
487
|
+
function wrapWithRetry(client) {
|
|
488
|
+
return new Proxy(client, {
|
|
489
|
+
get(target, prop, receiver) {
|
|
490
|
+
if (prop === "execute") {
|
|
491
|
+
return (sql) => retryOnBusy(() => target.execute(sql), "execute");
|
|
492
|
+
}
|
|
493
|
+
if (prop === "batch") {
|
|
494
|
+
return (stmts) => retryOnBusy(() => target.batch(stmts), "batch");
|
|
495
|
+
}
|
|
496
|
+
return Reflect.get(target, prop, receiver);
|
|
497
|
+
}
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
// src/lib/database.ts
|
|
451
502
|
var _client = null;
|
|
503
|
+
var _resilientClient = null;
|
|
452
504
|
var initTurso = initDatabase;
|
|
453
505
|
async function initDatabase(config) {
|
|
454
506
|
if (_client) {
|
|
455
507
|
_client.close();
|
|
456
508
|
_client = null;
|
|
509
|
+
_resilientClient = null;
|
|
457
510
|
}
|
|
458
511
|
const opts = {
|
|
459
512
|
url: `file:${config.dbPath}`
|
|
@@ -462,17 +515,24 @@ async function initDatabase(config) {
|
|
|
462
515
|
opts.encryptionKey = config.encryptionKey;
|
|
463
516
|
}
|
|
464
517
|
_client = createClient(opts);
|
|
518
|
+
_resilientClient = wrapWithRetry(_client);
|
|
465
519
|
}
|
|
466
520
|
function getClient() {
|
|
521
|
+
if (!_resilientClient) {
|
|
522
|
+
throw new Error("Database client not initialized. Call initDatabase() first.");
|
|
523
|
+
}
|
|
524
|
+
return _resilientClient;
|
|
525
|
+
}
|
|
526
|
+
function getRawClient() {
|
|
467
527
|
if (!_client) {
|
|
468
528
|
throw new Error("Database client not initialized. Call initDatabase() first.");
|
|
469
529
|
}
|
|
470
530
|
return _client;
|
|
471
531
|
}
|
|
472
532
|
async function ensureSchema() {
|
|
473
|
-
const client =
|
|
533
|
+
const client = getRawClient();
|
|
474
534
|
await client.execute("PRAGMA journal_mode = WAL");
|
|
475
|
-
await client.execute("PRAGMA busy_timeout =
|
|
535
|
+
await client.execute("PRAGMA busy_timeout = 30000");
|
|
476
536
|
try {
|
|
477
537
|
await client.execute("PRAGMA libsql_vector_search_ef = 128");
|
|
478
538
|
} catch {
|
|
@@ -1546,11 +1606,11 @@ async function connectEmbedDaemon() {
|
|
|
1546
1606
|
}
|
|
1547
1607
|
}
|
|
1548
1608
|
const start = Date.now();
|
|
1549
|
-
let
|
|
1609
|
+
let delay2 = 100;
|
|
1550
1610
|
while (Date.now() - start < CONNECT_TIMEOUT_MS) {
|
|
1551
|
-
await new Promise((r) => setTimeout(r,
|
|
1611
|
+
await new Promise((r) => setTimeout(r, delay2));
|
|
1552
1612
|
if (await connectToSocket()) return true;
|
|
1553
|
-
|
|
1613
|
+
delay2 = Math.min(delay2 * 2, 3e3);
|
|
1554
1614
|
}
|
|
1555
1615
|
return false;
|
|
1556
1616
|
}
|
|
@@ -1642,11 +1702,11 @@ async function embedViaClient(text, priority = "high") {
|
|
|
1642
1702
|
`);
|
|
1643
1703
|
killAndRespawnDaemon();
|
|
1644
1704
|
const start = Date.now();
|
|
1645
|
-
let
|
|
1705
|
+
let delay2 = 200;
|
|
1646
1706
|
while (Date.now() - start < CONNECT_TIMEOUT_MS) {
|
|
1647
|
-
await new Promise((r) => setTimeout(r,
|
|
1707
|
+
await new Promise((r) => setTimeout(r, delay2));
|
|
1648
1708
|
if (await connectToSocket()) break;
|
|
1649
|
-
|
|
1709
|
+
delay2 = Math.min(delay2 * 2, 3e3);
|
|
1650
1710
|
}
|
|
1651
1711
|
if (!_connected) return null;
|
|
1652
1712
|
}
|
|
@@ -1658,11 +1718,11 @@ async function embedViaClient(text, priority = "high") {
|
|
|
1658
1718
|
`);
|
|
1659
1719
|
killAndRespawnDaemon();
|
|
1660
1720
|
const start = Date.now();
|
|
1661
|
-
let
|
|
1721
|
+
let delay2 = 200;
|
|
1662
1722
|
while (Date.now() - start < CONNECT_TIMEOUT_MS) {
|
|
1663
|
-
await new Promise((r) => setTimeout(r,
|
|
1723
|
+
await new Promise((r) => setTimeout(r, delay2));
|
|
1664
1724
|
if (await connectToSocket()) break;
|
|
1665
|
-
|
|
1725
|
+
delay2 = Math.min(delay2 * 2, 3e3);
|
|
1666
1726
|
}
|
|
1667
1727
|
if (!_connected) return null;
|
|
1668
1728
|
const retry = await sendRequest([text], priority);
|
|
@@ -262,7 +262,7 @@ function listShards() {
|
|
|
262
262
|
}
|
|
263
263
|
async function ensureShardSchema(client) {
|
|
264
264
|
await client.execute("PRAGMA journal_mode = WAL");
|
|
265
|
-
await client.execute("PRAGMA busy_timeout =
|
|
265
|
+
await client.execute("PRAGMA busy_timeout = 30000");
|
|
266
266
|
try {
|
|
267
267
|
await client.execute("PRAGMA libsql_vector_search_ef = 128");
|
|
268
268
|
} catch {
|
|
@@ -448,12 +448,65 @@ var init_shard_manager = __esm({
|
|
|
448
448
|
|
|
449
449
|
// src/lib/database.ts
|
|
450
450
|
import { createClient } from "@libsql/client";
|
|
451
|
+
|
|
452
|
+
// src/lib/db-retry.ts
|
|
453
|
+
var MAX_RETRIES = 3;
|
|
454
|
+
var BASE_DELAY_MS = 200;
|
|
455
|
+
var MAX_JITTER_MS = 300;
|
|
456
|
+
function isBusyError(err) {
|
|
457
|
+
if (err instanceof Error) {
|
|
458
|
+
const msg = err.message.toLowerCase();
|
|
459
|
+
return msg.includes("sqlite_busy") || msg.includes("database is locked");
|
|
460
|
+
}
|
|
461
|
+
return false;
|
|
462
|
+
}
|
|
463
|
+
function delay(ms) {
|
|
464
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
465
|
+
}
|
|
466
|
+
async function retryOnBusy(fn, label) {
|
|
467
|
+
let lastError;
|
|
468
|
+
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
469
|
+
try {
|
|
470
|
+
return await fn();
|
|
471
|
+
} catch (err) {
|
|
472
|
+
lastError = err;
|
|
473
|
+
if (!isBusyError(err) || attempt === MAX_RETRIES) {
|
|
474
|
+
throw err;
|
|
475
|
+
}
|
|
476
|
+
const backoff = BASE_DELAY_MS * Math.pow(2, attempt);
|
|
477
|
+
const jitter = Math.floor(Math.random() * MAX_JITTER_MS);
|
|
478
|
+
process.stderr.write(
|
|
479
|
+
`[exe-os] SQLITE_BUSY ${label} retry ${attempt + 1}/${MAX_RETRIES} \u2014 waiting ${backoff + jitter}ms
|
|
480
|
+
`
|
|
481
|
+
);
|
|
482
|
+
await delay(backoff + jitter);
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
throw lastError;
|
|
486
|
+
}
|
|
487
|
+
function wrapWithRetry(client) {
|
|
488
|
+
return new Proxy(client, {
|
|
489
|
+
get(target, prop, receiver) {
|
|
490
|
+
if (prop === "execute") {
|
|
491
|
+
return (sql) => retryOnBusy(() => target.execute(sql), "execute");
|
|
492
|
+
}
|
|
493
|
+
if (prop === "batch") {
|
|
494
|
+
return (stmts) => retryOnBusy(() => target.batch(stmts), "batch");
|
|
495
|
+
}
|
|
496
|
+
return Reflect.get(target, prop, receiver);
|
|
497
|
+
}
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
// src/lib/database.ts
|
|
451
502
|
var _client = null;
|
|
503
|
+
var _resilientClient = null;
|
|
452
504
|
var initTurso = initDatabase;
|
|
453
505
|
async function initDatabase(config) {
|
|
454
506
|
if (_client) {
|
|
455
507
|
_client.close();
|
|
456
508
|
_client = null;
|
|
509
|
+
_resilientClient = null;
|
|
457
510
|
}
|
|
458
511
|
const opts = {
|
|
459
512
|
url: `file:${config.dbPath}`
|
|
@@ -462,17 +515,24 @@ async function initDatabase(config) {
|
|
|
462
515
|
opts.encryptionKey = config.encryptionKey;
|
|
463
516
|
}
|
|
464
517
|
_client = createClient(opts);
|
|
518
|
+
_resilientClient = wrapWithRetry(_client);
|
|
465
519
|
}
|
|
466
520
|
function getClient() {
|
|
521
|
+
if (!_resilientClient) {
|
|
522
|
+
throw new Error("Database client not initialized. Call initDatabase() first.");
|
|
523
|
+
}
|
|
524
|
+
return _resilientClient;
|
|
525
|
+
}
|
|
526
|
+
function getRawClient() {
|
|
467
527
|
if (!_client) {
|
|
468
528
|
throw new Error("Database client not initialized. Call initDatabase() first.");
|
|
469
529
|
}
|
|
470
530
|
return _client;
|
|
471
531
|
}
|
|
472
532
|
async function ensureSchema() {
|
|
473
|
-
const client =
|
|
533
|
+
const client = getRawClient();
|
|
474
534
|
await client.execute("PRAGMA journal_mode = WAL");
|
|
475
|
-
await client.execute("PRAGMA busy_timeout =
|
|
535
|
+
await client.execute("PRAGMA busy_timeout = 30000");
|
|
476
536
|
try {
|
|
477
537
|
await client.execute("PRAGMA libsql_vector_search_ef = 128");
|
|
478
538
|
} catch {
|