@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
package/dist/bin/exe-review.js
CHANGED
|
@@ -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 {
|
|
@@ -452,7 +452,7 @@ import { randomUUID } from "crypto";
|
|
|
452
452
|
// src/lib/employees.ts
|
|
453
453
|
init_config();
|
|
454
454
|
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
455
|
-
import { existsSync as existsSync2, symlinkSync, readlinkSync } from "fs";
|
|
455
|
+
import { existsSync as existsSync2, symlinkSync, readlinkSync, readFileSync as readFileSync2 } from "fs";
|
|
456
456
|
import { execSync } from "child_process";
|
|
457
457
|
import path2 from "path";
|
|
458
458
|
var EMPLOYEES_PATH = path2.join(EXE_AI_DIR, "exe-employees.json");
|
|
@@ -476,12 +476,65 @@ var EMBEDDING_DIM = 1024;
|
|
|
476
476
|
|
|
477
477
|
// src/lib/database.ts
|
|
478
478
|
import { createClient } from "@libsql/client";
|
|
479
|
+
|
|
480
|
+
// src/lib/db-retry.ts
|
|
481
|
+
var MAX_RETRIES = 3;
|
|
482
|
+
var BASE_DELAY_MS = 200;
|
|
483
|
+
var MAX_JITTER_MS = 300;
|
|
484
|
+
function isBusyError(err) {
|
|
485
|
+
if (err instanceof Error) {
|
|
486
|
+
const msg = err.message.toLowerCase();
|
|
487
|
+
return msg.includes("sqlite_busy") || msg.includes("database is locked");
|
|
488
|
+
}
|
|
489
|
+
return false;
|
|
490
|
+
}
|
|
491
|
+
function delay(ms) {
|
|
492
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
493
|
+
}
|
|
494
|
+
async function retryOnBusy(fn, label) {
|
|
495
|
+
let lastError;
|
|
496
|
+
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
497
|
+
try {
|
|
498
|
+
return await fn();
|
|
499
|
+
} catch (err) {
|
|
500
|
+
lastError = err;
|
|
501
|
+
if (!isBusyError(err) || attempt === MAX_RETRIES) {
|
|
502
|
+
throw err;
|
|
503
|
+
}
|
|
504
|
+
const backoff = BASE_DELAY_MS * Math.pow(2, attempt);
|
|
505
|
+
const jitter = Math.floor(Math.random() * MAX_JITTER_MS);
|
|
506
|
+
process.stderr.write(
|
|
507
|
+
`[exe-os] SQLITE_BUSY ${label} retry ${attempt + 1}/${MAX_RETRIES} \u2014 waiting ${backoff + jitter}ms
|
|
508
|
+
`
|
|
509
|
+
);
|
|
510
|
+
await delay(backoff + jitter);
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
throw lastError;
|
|
514
|
+
}
|
|
515
|
+
function wrapWithRetry(client) {
|
|
516
|
+
return new Proxy(client, {
|
|
517
|
+
get(target, prop, receiver) {
|
|
518
|
+
if (prop === "execute") {
|
|
519
|
+
return (sql) => retryOnBusy(() => target.execute(sql), "execute");
|
|
520
|
+
}
|
|
521
|
+
if (prop === "batch") {
|
|
522
|
+
return (stmts) => retryOnBusy(() => target.batch(stmts), "batch");
|
|
523
|
+
}
|
|
524
|
+
return Reflect.get(target, prop, receiver);
|
|
525
|
+
}
|
|
526
|
+
});
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
// src/lib/database.ts
|
|
479
530
|
var _client = null;
|
|
531
|
+
var _resilientClient = null;
|
|
480
532
|
var initTurso = initDatabase;
|
|
481
533
|
async function initDatabase(config) {
|
|
482
534
|
if (_client) {
|
|
483
535
|
_client.close();
|
|
484
536
|
_client = null;
|
|
537
|
+
_resilientClient = null;
|
|
485
538
|
}
|
|
486
539
|
const opts = {
|
|
487
540
|
url: `file:${config.dbPath}`
|
|
@@ -490,17 +543,24 @@ async function initDatabase(config) {
|
|
|
490
543
|
opts.encryptionKey = config.encryptionKey;
|
|
491
544
|
}
|
|
492
545
|
_client = createClient(opts);
|
|
546
|
+
_resilientClient = wrapWithRetry(_client);
|
|
493
547
|
}
|
|
494
548
|
function getClient() {
|
|
549
|
+
if (!_resilientClient) {
|
|
550
|
+
throw new Error("Database client not initialized. Call initDatabase() first.");
|
|
551
|
+
}
|
|
552
|
+
return _resilientClient;
|
|
553
|
+
}
|
|
554
|
+
function getRawClient() {
|
|
495
555
|
if (!_client) {
|
|
496
556
|
throw new Error("Database client not initialized. Call initDatabase() first.");
|
|
497
557
|
}
|
|
498
558
|
return _client;
|
|
499
559
|
}
|
|
500
560
|
async function ensureSchema() {
|
|
501
|
-
const client =
|
|
561
|
+
const client = getRawClient();
|
|
502
562
|
await client.execute("PRAGMA journal_mode = WAL");
|
|
503
|
-
await client.execute("PRAGMA busy_timeout =
|
|
563
|
+
await client.execute("PRAGMA busy_timeout = 30000");
|
|
504
564
|
try {
|
|
505
565
|
await client.execute("PRAGMA libsql_vector_search_ef = 128");
|
|
506
566
|
} catch {
|
package/dist/bin/exe-search.js
CHANGED
|
@@ -24,12 +24,68 @@ var init_memory = __esm({
|
|
|
24
24
|
}
|
|
25
25
|
});
|
|
26
26
|
|
|
27
|
+
// src/lib/db-retry.ts
|
|
28
|
+
function isBusyError(err) {
|
|
29
|
+
if (err instanceof Error) {
|
|
30
|
+
const msg = err.message.toLowerCase();
|
|
31
|
+
return msg.includes("sqlite_busy") || msg.includes("database is locked");
|
|
32
|
+
}
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
function delay(ms) {
|
|
36
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
37
|
+
}
|
|
38
|
+
async function retryOnBusy(fn, label) {
|
|
39
|
+
let lastError;
|
|
40
|
+
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
41
|
+
try {
|
|
42
|
+
return await fn();
|
|
43
|
+
} catch (err) {
|
|
44
|
+
lastError = err;
|
|
45
|
+
if (!isBusyError(err) || attempt === MAX_RETRIES) {
|
|
46
|
+
throw err;
|
|
47
|
+
}
|
|
48
|
+
const backoff = BASE_DELAY_MS * Math.pow(2, attempt);
|
|
49
|
+
const jitter = Math.floor(Math.random() * MAX_JITTER_MS);
|
|
50
|
+
process.stderr.write(
|
|
51
|
+
`[exe-os] SQLITE_BUSY ${label} retry ${attempt + 1}/${MAX_RETRIES} \u2014 waiting ${backoff + jitter}ms
|
|
52
|
+
`
|
|
53
|
+
);
|
|
54
|
+
await delay(backoff + jitter);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
throw lastError;
|
|
58
|
+
}
|
|
59
|
+
function wrapWithRetry(client) {
|
|
60
|
+
return new Proxy(client, {
|
|
61
|
+
get(target, prop, receiver) {
|
|
62
|
+
if (prop === "execute") {
|
|
63
|
+
return (sql) => retryOnBusy(() => target.execute(sql), "execute");
|
|
64
|
+
}
|
|
65
|
+
if (prop === "batch") {
|
|
66
|
+
return (stmts) => retryOnBusy(() => target.batch(stmts), "batch");
|
|
67
|
+
}
|
|
68
|
+
return Reflect.get(target, prop, receiver);
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
var MAX_RETRIES, BASE_DELAY_MS, MAX_JITTER_MS;
|
|
73
|
+
var init_db_retry = __esm({
|
|
74
|
+
"src/lib/db-retry.ts"() {
|
|
75
|
+
"use strict";
|
|
76
|
+
MAX_RETRIES = 3;
|
|
77
|
+
BASE_DELAY_MS = 200;
|
|
78
|
+
MAX_JITTER_MS = 300;
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
|
|
27
82
|
// src/lib/database.ts
|
|
28
83
|
import { createClient } from "@libsql/client";
|
|
29
84
|
async function initDatabase(config) {
|
|
30
85
|
if (_client) {
|
|
31
86
|
_client.close();
|
|
32
87
|
_client = null;
|
|
88
|
+
_resilientClient = null;
|
|
33
89
|
}
|
|
34
90
|
const opts = {
|
|
35
91
|
url: `file:${config.dbPath}`
|
|
@@ -38,17 +94,24 @@ async function initDatabase(config) {
|
|
|
38
94
|
opts.encryptionKey = config.encryptionKey;
|
|
39
95
|
}
|
|
40
96
|
_client = createClient(opts);
|
|
97
|
+
_resilientClient = wrapWithRetry(_client);
|
|
41
98
|
}
|
|
42
99
|
function getClient() {
|
|
100
|
+
if (!_resilientClient) {
|
|
101
|
+
throw new Error("Database client not initialized. Call initDatabase() first.");
|
|
102
|
+
}
|
|
103
|
+
return _resilientClient;
|
|
104
|
+
}
|
|
105
|
+
function getRawClient() {
|
|
43
106
|
if (!_client) {
|
|
44
107
|
throw new Error("Database client not initialized. Call initDatabase() first.");
|
|
45
108
|
}
|
|
46
109
|
return _client;
|
|
47
110
|
}
|
|
48
111
|
async function ensureSchema() {
|
|
49
|
-
const client =
|
|
112
|
+
const client = getRawClient();
|
|
50
113
|
await client.execute("PRAGMA journal_mode = WAL");
|
|
51
|
-
await client.execute("PRAGMA busy_timeout =
|
|
114
|
+
await client.execute("PRAGMA busy_timeout = 30000");
|
|
52
115
|
try {
|
|
53
116
|
await client.execute("PRAGMA libsql_vector_search_ef = 128");
|
|
54
117
|
} catch {
|
|
@@ -841,13 +904,16 @@ async function disposeDatabase() {
|
|
|
841
904
|
if (_client) {
|
|
842
905
|
_client.close();
|
|
843
906
|
_client = null;
|
|
907
|
+
_resilientClient = null;
|
|
844
908
|
}
|
|
845
909
|
}
|
|
846
|
-
var _client, initTurso, disposeTurso;
|
|
910
|
+
var _client, _resilientClient, initTurso, disposeTurso;
|
|
847
911
|
var init_database = __esm({
|
|
848
912
|
"src/lib/database.ts"() {
|
|
849
913
|
"use strict";
|
|
914
|
+
init_db_retry();
|
|
850
915
|
_client = null;
|
|
916
|
+
_resilientClient = null;
|
|
851
917
|
initTurso = initDatabase;
|
|
852
918
|
disposeTurso = disposeDatabase;
|
|
853
919
|
}
|
|
@@ -1203,7 +1269,7 @@ function listShards() {
|
|
|
1203
1269
|
}
|
|
1204
1270
|
async function ensureShardSchema(client) {
|
|
1205
1271
|
await client.execute("PRAGMA journal_mode = WAL");
|
|
1206
|
-
await client.execute("PRAGMA busy_timeout =
|
|
1272
|
+
await client.execute("PRAGMA busy_timeout = 30000");
|
|
1207
1273
|
try {
|
|
1208
1274
|
await client.execute("PRAGMA libsql_vector_search_ef = 128");
|
|
1209
1275
|
} catch {
|
|
@@ -2088,11 +2154,11 @@ async function connectEmbedDaemon() {
|
|
|
2088
2154
|
}
|
|
2089
2155
|
}
|
|
2090
2156
|
const start = Date.now();
|
|
2091
|
-
let
|
|
2157
|
+
let delay2 = 100;
|
|
2092
2158
|
while (Date.now() - start < CONNECT_TIMEOUT_MS) {
|
|
2093
|
-
await new Promise((r) => setTimeout(r,
|
|
2159
|
+
await new Promise((r) => setTimeout(r, delay2));
|
|
2094
2160
|
if (await connectToSocket()) return true;
|
|
2095
|
-
|
|
2161
|
+
delay2 = Math.min(delay2 * 2, 3e3);
|
|
2096
2162
|
}
|
|
2097
2163
|
return false;
|
|
2098
2164
|
}
|
|
@@ -2184,11 +2250,11 @@ async function embedViaClient(text, priority = "high") {
|
|
|
2184
2250
|
`);
|
|
2185
2251
|
killAndRespawnDaemon();
|
|
2186
2252
|
const start = Date.now();
|
|
2187
|
-
let
|
|
2253
|
+
let delay2 = 200;
|
|
2188
2254
|
while (Date.now() - start < CONNECT_TIMEOUT_MS) {
|
|
2189
|
-
await new Promise((r) => setTimeout(r,
|
|
2255
|
+
await new Promise((r) => setTimeout(r, delay2));
|
|
2190
2256
|
if (await connectToSocket()) break;
|
|
2191
|
-
|
|
2257
|
+
delay2 = Math.min(delay2 * 2, 3e3);
|
|
2192
2258
|
}
|
|
2193
2259
|
if (!_connected) return null;
|
|
2194
2260
|
}
|
|
@@ -2200,11 +2266,11 @@ async function embedViaClient(text, priority = "high") {
|
|
|
2200
2266
|
`);
|
|
2201
2267
|
killAndRespawnDaemon();
|
|
2202
2268
|
const start = Date.now();
|
|
2203
|
-
let
|
|
2269
|
+
let delay2 = 200;
|
|
2204
2270
|
while (Date.now() - start < CONNECT_TIMEOUT_MS) {
|
|
2205
|
-
await new Promise((r) => setTimeout(r,
|
|
2271
|
+
await new Promise((r) => setTimeout(r, delay2));
|
|
2206
2272
|
if (await connectToSocket()) break;
|
|
2207
|
-
|
|
2273
|
+
delay2 = Math.min(delay2 * 2, 3e3);
|
|
2208
2274
|
}
|
|
2209
2275
|
if (!_connected) return null;
|
|
2210
2276
|
const retry = await sendRequest([text], priority);
|
|
@@ -35,12 +35,68 @@ var init_memory = __esm({
|
|
|
35
35
|
}
|
|
36
36
|
});
|
|
37
37
|
|
|
38
|
+
// src/lib/db-retry.ts
|
|
39
|
+
function isBusyError(err) {
|
|
40
|
+
if (err instanceof Error) {
|
|
41
|
+
const msg = err.message.toLowerCase();
|
|
42
|
+
return msg.includes("sqlite_busy") || msg.includes("database is locked");
|
|
43
|
+
}
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
function delay(ms) {
|
|
47
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
48
|
+
}
|
|
49
|
+
async function retryOnBusy(fn, label) {
|
|
50
|
+
let lastError;
|
|
51
|
+
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
52
|
+
try {
|
|
53
|
+
return await fn();
|
|
54
|
+
} catch (err) {
|
|
55
|
+
lastError = err;
|
|
56
|
+
if (!isBusyError(err) || attempt === MAX_RETRIES) {
|
|
57
|
+
throw err;
|
|
58
|
+
}
|
|
59
|
+
const backoff = BASE_DELAY_MS * Math.pow(2, attempt);
|
|
60
|
+
const jitter = Math.floor(Math.random() * MAX_JITTER_MS);
|
|
61
|
+
process.stderr.write(
|
|
62
|
+
`[exe-os] SQLITE_BUSY ${label} retry ${attempt + 1}/${MAX_RETRIES} \u2014 waiting ${backoff + jitter}ms
|
|
63
|
+
`
|
|
64
|
+
);
|
|
65
|
+
await delay(backoff + jitter);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
throw lastError;
|
|
69
|
+
}
|
|
70
|
+
function wrapWithRetry(client) {
|
|
71
|
+
return new Proxy(client, {
|
|
72
|
+
get(target, prop, receiver) {
|
|
73
|
+
if (prop === "execute") {
|
|
74
|
+
return (sql) => retryOnBusy(() => target.execute(sql), "execute");
|
|
75
|
+
}
|
|
76
|
+
if (prop === "batch") {
|
|
77
|
+
return (stmts) => retryOnBusy(() => target.batch(stmts), "batch");
|
|
78
|
+
}
|
|
79
|
+
return Reflect.get(target, prop, receiver);
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
var MAX_RETRIES, BASE_DELAY_MS, MAX_JITTER_MS;
|
|
84
|
+
var init_db_retry = __esm({
|
|
85
|
+
"src/lib/db-retry.ts"() {
|
|
86
|
+
"use strict";
|
|
87
|
+
MAX_RETRIES = 3;
|
|
88
|
+
BASE_DELAY_MS = 200;
|
|
89
|
+
MAX_JITTER_MS = 300;
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
|
|
38
93
|
// src/lib/database.ts
|
|
39
94
|
import { createClient } from "@libsql/client";
|
|
40
95
|
async function initDatabase(config) {
|
|
41
96
|
if (_client) {
|
|
42
97
|
_client.close();
|
|
43
98
|
_client = null;
|
|
99
|
+
_resilientClient = null;
|
|
44
100
|
}
|
|
45
101
|
const opts = {
|
|
46
102
|
url: `file:${config.dbPath}`
|
|
@@ -49,17 +105,24 @@ async function initDatabase(config) {
|
|
|
49
105
|
opts.encryptionKey = config.encryptionKey;
|
|
50
106
|
}
|
|
51
107
|
_client = createClient(opts);
|
|
108
|
+
_resilientClient = wrapWithRetry(_client);
|
|
52
109
|
}
|
|
53
110
|
function getClient() {
|
|
111
|
+
if (!_resilientClient) {
|
|
112
|
+
throw new Error("Database client not initialized. Call initDatabase() first.");
|
|
113
|
+
}
|
|
114
|
+
return _resilientClient;
|
|
115
|
+
}
|
|
116
|
+
function getRawClient() {
|
|
54
117
|
if (!_client) {
|
|
55
118
|
throw new Error("Database client not initialized. Call initDatabase() first.");
|
|
56
119
|
}
|
|
57
120
|
return _client;
|
|
58
121
|
}
|
|
59
122
|
async function ensureSchema() {
|
|
60
|
-
const client =
|
|
123
|
+
const client = getRawClient();
|
|
61
124
|
await client.execute("PRAGMA journal_mode = WAL");
|
|
62
|
-
await client.execute("PRAGMA busy_timeout =
|
|
125
|
+
await client.execute("PRAGMA busy_timeout = 30000");
|
|
63
126
|
try {
|
|
64
127
|
await client.execute("PRAGMA libsql_vector_search_ef = 128");
|
|
65
128
|
} catch {
|
|
@@ -848,11 +911,13 @@ async function ensureSchema() {
|
|
|
848
911
|
}
|
|
849
912
|
}
|
|
850
913
|
}
|
|
851
|
-
var _client, initTurso;
|
|
914
|
+
var _client, _resilientClient, initTurso;
|
|
852
915
|
var init_database = __esm({
|
|
853
916
|
"src/lib/database.ts"() {
|
|
854
917
|
"use strict";
|
|
918
|
+
init_db_retry();
|
|
855
919
|
_client = null;
|
|
920
|
+
_resilientClient = null;
|
|
856
921
|
initTurso = initDatabase;
|
|
857
922
|
}
|
|
858
923
|
});
|
|
@@ -1158,7 +1223,7 @@ function listShards() {
|
|
|
1158
1223
|
}
|
|
1159
1224
|
async function ensureShardSchema(client) {
|
|
1160
1225
|
await client.execute("PRAGMA journal_mode = WAL");
|
|
1161
|
-
await client.execute("PRAGMA busy_timeout =
|
|
1226
|
+
await client.execute("PRAGMA busy_timeout = 30000");
|
|
1162
1227
|
try {
|
|
1163
1228
|
await client.execute("PRAGMA libsql_vector_search_ef = 128");
|
|
1164
1229
|
} catch {
|
|
@@ -1561,11 +1626,11 @@ async function connectEmbedDaemon() {
|
|
|
1561
1626
|
}
|
|
1562
1627
|
}
|
|
1563
1628
|
const start = Date.now();
|
|
1564
|
-
let
|
|
1629
|
+
let delay2 = 100;
|
|
1565
1630
|
while (Date.now() - start < CONNECT_TIMEOUT_MS) {
|
|
1566
|
-
await new Promise((r) => setTimeout(r,
|
|
1631
|
+
await new Promise((r) => setTimeout(r, delay2));
|
|
1567
1632
|
if (await connectToSocket()) return true;
|
|
1568
|
-
|
|
1633
|
+
delay2 = Math.min(delay2 * 2, 3e3);
|
|
1569
1634
|
}
|
|
1570
1635
|
return false;
|
|
1571
1636
|
}
|
|
@@ -1657,11 +1722,11 @@ async function embedViaClient(text, priority = "high") {
|
|
|
1657
1722
|
`);
|
|
1658
1723
|
killAndRespawnDaemon();
|
|
1659
1724
|
const start = Date.now();
|
|
1660
|
-
let
|
|
1725
|
+
let delay2 = 200;
|
|
1661
1726
|
while (Date.now() - start < CONNECT_TIMEOUT_MS) {
|
|
1662
|
-
await new Promise((r) => setTimeout(r,
|
|
1727
|
+
await new Promise((r) => setTimeout(r, delay2));
|
|
1663
1728
|
if (await connectToSocket()) break;
|
|
1664
|
-
|
|
1729
|
+
delay2 = Math.min(delay2 * 2, 3e3);
|
|
1665
1730
|
}
|
|
1666
1731
|
if (!_connected) return null;
|
|
1667
1732
|
}
|
|
@@ -1673,11 +1738,11 @@ async function embedViaClient(text, priority = "high") {
|
|
|
1673
1738
|
`);
|
|
1674
1739
|
killAndRespawnDaemon();
|
|
1675
1740
|
const start = Date.now();
|
|
1676
|
-
let
|
|
1741
|
+
let delay2 = 200;
|
|
1677
1742
|
while (Date.now() - start < CONNECT_TIMEOUT_MS) {
|
|
1678
|
-
await new Promise((r) => setTimeout(r,
|
|
1743
|
+
await new Promise((r) => setTimeout(r, delay2));
|
|
1679
1744
|
if (await connectToSocket()) break;
|
|
1680
|
-
|
|
1745
|
+
delay2 = Math.min(delay2 * 2, 3e3);
|
|
1681
1746
|
}
|
|
1682
1747
|
if (!_connected) return null;
|
|
1683
1748
|
const retry = await sendRequest([text], priority);
|
|
@@ -1790,7 +1855,7 @@ var init_embedder = __esm({
|
|
|
1790
1855
|
|
|
1791
1856
|
// src/lib/employees.ts
|
|
1792
1857
|
import { readFile as readFile3, writeFile as writeFile3, mkdir as mkdir3 } from "fs/promises";
|
|
1793
|
-
import { existsSync as existsSync5, symlinkSync, readlinkSync } from "fs";
|
|
1858
|
+
import { existsSync as existsSync5, symlinkSync, readlinkSync, readFileSync as readFileSync3 } from "fs";
|
|
1794
1859
|
import { execSync as execSync2 } from "child_process";
|
|
1795
1860
|
import path6 from "path";
|
|
1796
1861
|
async function loadEmployees(employeesPath = EMPLOYEES_PATH) {
|
|
@@ -1821,7 +1886,7 @@ import crypto2 from "crypto";
|
|
|
1821
1886
|
import path7 from "path";
|
|
1822
1887
|
import os2 from "os";
|
|
1823
1888
|
import {
|
|
1824
|
-
readFileSync as
|
|
1889
|
+
readFileSync as readFileSync4,
|
|
1825
1890
|
readdirSync,
|
|
1826
1891
|
unlinkSync as unlinkSync2,
|
|
1827
1892
|
existsSync as existsSync6,
|
|
@@ -1863,7 +1928,7 @@ import crypto3 from "crypto";
|
|
|
1863
1928
|
import path8 from "path";
|
|
1864
1929
|
import { execSync as execSync3 } from "child_process";
|
|
1865
1930
|
import { mkdir as mkdir4, writeFile as writeFile4, appendFile } from "fs/promises";
|
|
1866
|
-
import { existsSync as existsSync7, readFileSync as
|
|
1931
|
+
import { existsSync as existsSync7, readFileSync as readFileSync5 } from "fs";
|
|
1867
1932
|
function extractParentFromContext(contextBody) {
|
|
1868
1933
|
if (!contextBody) return null;
|
|
1869
1934
|
const match = contextBody.match(
|
|
@@ -2053,7 +2118,7 @@ async function ensureGitignoreExe(baseDir) {
|
|
|
2053
2118
|
const gitignorePath = path8.join(baseDir, ".gitignore");
|
|
2054
2119
|
try {
|
|
2055
2120
|
if (existsSync7(gitignorePath)) {
|
|
2056
|
-
const content =
|
|
2121
|
+
const content = readFileSync5(gitignorePath, "utf-8");
|
|
2057
2122
|
if (/^\/?exe\/?$/m.test(content)) return;
|
|
2058
2123
|
await appendFile(gitignorePath, "\n# Employee task assignments (private)\n/exe/\n");
|
|
2059
2124
|
} else {
|
|
@@ -2252,7 +2317,7 @@ var init_provider_table = __esm({
|
|
|
2252
2317
|
});
|
|
2253
2318
|
|
|
2254
2319
|
// src/lib/intercom-queue.ts
|
|
2255
|
-
import { readFileSync as
|
|
2320
|
+
import { readFileSync as readFileSync6, writeFileSync, renameSync as renameSync2, existsSync as existsSync8, mkdirSync as mkdirSync2 } from "fs";
|
|
2256
2321
|
import path10 from "path";
|
|
2257
2322
|
import os4 from "os";
|
|
2258
2323
|
function ensureDir() {
|
|
@@ -2262,7 +2327,7 @@ function ensureDir() {
|
|
|
2262
2327
|
function readQueue() {
|
|
2263
2328
|
try {
|
|
2264
2329
|
if (!existsSync8(QUEUE_PATH)) return [];
|
|
2265
|
-
return JSON.parse(
|
|
2330
|
+
return JSON.parse(readFileSync6(QUEUE_PATH, "utf8"));
|
|
2266
2331
|
} catch {
|
|
2267
2332
|
return [];
|
|
2268
2333
|
}
|
|
@@ -2301,7 +2366,7 @@ var init_intercom_queue = __esm({
|
|
|
2301
2366
|
});
|
|
2302
2367
|
|
|
2303
2368
|
// src/lib/license.ts
|
|
2304
|
-
import { readFileSync as
|
|
2369
|
+
import { readFileSync as readFileSync7, writeFileSync as writeFileSync2, existsSync as existsSync9, mkdirSync as mkdirSync3 } from "fs";
|
|
2305
2370
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
2306
2371
|
import path11 from "path";
|
|
2307
2372
|
import { jwtVerify, importSPKI } from "jose";
|
|
@@ -2317,7 +2382,7 @@ var init_license = __esm({
|
|
|
2317
2382
|
});
|
|
2318
2383
|
|
|
2319
2384
|
// src/lib/plan-limits.ts
|
|
2320
|
-
import { readFileSync as
|
|
2385
|
+
import { readFileSync as readFileSync8, existsSync as existsSync10 } from "fs";
|
|
2321
2386
|
import path12 from "path";
|
|
2322
2387
|
var CACHE_PATH2;
|
|
2323
2388
|
var init_plan_limits = __esm({
|
|
@@ -2332,13 +2397,13 @@ var init_plan_limits = __esm({
|
|
|
2332
2397
|
});
|
|
2333
2398
|
|
|
2334
2399
|
// src/lib/tmux-routing.ts
|
|
2335
|
-
import { readFileSync as
|
|
2400
|
+
import { readFileSync as readFileSync9, writeFileSync as writeFileSync3, mkdirSync as mkdirSync4, existsSync as existsSync11, appendFileSync } from "fs";
|
|
2336
2401
|
import path13 from "path";
|
|
2337
2402
|
import os5 from "os";
|
|
2338
2403
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
2339
2404
|
function getParentExe(sessionKey) {
|
|
2340
2405
|
try {
|
|
2341
|
-
const data = JSON.parse(
|
|
2406
|
+
const data = JSON.parse(readFileSync9(path13.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
|
|
2342
2407
|
return data.parentExe || null;
|
|
2343
2408
|
} catch {
|
|
2344
2409
|
return null;
|
|
@@ -2347,7 +2412,7 @@ function getParentExe(sessionKey) {
|
|
|
2347
2412
|
function readDebounceState() {
|
|
2348
2413
|
try {
|
|
2349
2414
|
if (!existsSync11(DEBOUNCE_FILE)) return {};
|
|
2350
|
-
return JSON.parse(
|
|
2415
|
+
return JSON.parse(readFileSync9(DEBOUNCE_FILE, "utf8"));
|
|
2351
2416
|
} catch {
|
|
2352
2417
|
return {};
|
|
2353
2418
|
}
|
|
@@ -2723,7 +2788,7 @@ __export(worktree_exports, {
|
|
|
2723
2788
|
worktreePath: () => worktreePath
|
|
2724
2789
|
});
|
|
2725
2790
|
import { execSync as execSync6 } from "child_process";
|
|
2726
|
-
import { existsSync as existsSync13, readFileSync as
|
|
2791
|
+
import { existsSync as existsSync13, readFileSync as readFileSync10, appendFileSync as appendFileSync2, mkdirSync as mkdirSync5, realpathSync } from "fs";
|
|
2727
2792
|
import path15 from "path";
|
|
2728
2793
|
function getGitRoot(dir) {
|
|
2729
2794
|
try {
|
|
@@ -2903,7 +2968,7 @@ function ensureGitignoreEntry(repoRoot, entry) {
|
|
|
2903
2968
|
try {
|
|
2904
2969
|
const gitignorePath = path15.join(repoRoot, ".gitignore");
|
|
2905
2970
|
if (existsSync13(gitignorePath)) {
|
|
2906
|
-
const content =
|
|
2971
|
+
const content = readFileSync10(gitignorePath, "utf-8");
|
|
2907
2972
|
if (content.includes(entry)) return;
|
|
2908
2973
|
appendFileSync2(gitignorePath, `
|
|
2909
2974
|
# Agent worktrees (exe-os)
|
package/dist/bin/exe-status.js
CHANGED
|
@@ -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 {
|
|
@@ -449,7 +449,7 @@ var init_shard_manager = __esm({
|
|
|
449
449
|
// src/lib/employees.ts
|
|
450
450
|
init_config();
|
|
451
451
|
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
452
|
-
import { existsSync as existsSync2, symlinkSync, readlinkSync } from "fs";
|
|
452
|
+
import { existsSync as existsSync2, symlinkSync, readlinkSync, readFileSync as readFileSync2 } from "fs";
|
|
453
453
|
import { execSync } from "child_process";
|
|
454
454
|
import path2 from "path";
|
|
455
455
|
var EMPLOYEES_PATH = path2.join(EXE_AI_DIR, "exe-employees.json");
|
|
@@ -467,12 +467,65 @@ async function loadEmployees(employeesPath = EMPLOYEES_PATH) {
|
|
|
467
467
|
|
|
468
468
|
// src/lib/database.ts
|
|
469
469
|
import { createClient } from "@libsql/client";
|
|
470
|
+
|
|
471
|
+
// src/lib/db-retry.ts
|
|
472
|
+
var MAX_RETRIES = 3;
|
|
473
|
+
var BASE_DELAY_MS = 200;
|
|
474
|
+
var MAX_JITTER_MS = 300;
|
|
475
|
+
function isBusyError(err) {
|
|
476
|
+
if (err instanceof Error) {
|
|
477
|
+
const msg = err.message.toLowerCase();
|
|
478
|
+
return msg.includes("sqlite_busy") || msg.includes("database is locked");
|
|
479
|
+
}
|
|
480
|
+
return false;
|
|
481
|
+
}
|
|
482
|
+
function delay(ms) {
|
|
483
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
484
|
+
}
|
|
485
|
+
async function retryOnBusy(fn, label) {
|
|
486
|
+
let lastError;
|
|
487
|
+
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
488
|
+
try {
|
|
489
|
+
return await fn();
|
|
490
|
+
} catch (err) {
|
|
491
|
+
lastError = err;
|
|
492
|
+
if (!isBusyError(err) || attempt === MAX_RETRIES) {
|
|
493
|
+
throw err;
|
|
494
|
+
}
|
|
495
|
+
const backoff = BASE_DELAY_MS * Math.pow(2, attempt);
|
|
496
|
+
const jitter = Math.floor(Math.random() * MAX_JITTER_MS);
|
|
497
|
+
process.stderr.write(
|
|
498
|
+
`[exe-os] SQLITE_BUSY ${label} retry ${attempt + 1}/${MAX_RETRIES} \u2014 waiting ${backoff + jitter}ms
|
|
499
|
+
`
|
|
500
|
+
);
|
|
501
|
+
await delay(backoff + jitter);
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
throw lastError;
|
|
505
|
+
}
|
|
506
|
+
function wrapWithRetry(client) {
|
|
507
|
+
return new Proxy(client, {
|
|
508
|
+
get(target, prop, receiver) {
|
|
509
|
+
if (prop === "execute") {
|
|
510
|
+
return (sql) => retryOnBusy(() => target.execute(sql), "execute");
|
|
511
|
+
}
|
|
512
|
+
if (prop === "batch") {
|
|
513
|
+
return (stmts) => retryOnBusy(() => target.batch(stmts), "batch");
|
|
514
|
+
}
|
|
515
|
+
return Reflect.get(target, prop, receiver);
|
|
516
|
+
}
|
|
517
|
+
});
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
// src/lib/database.ts
|
|
470
521
|
var _client = null;
|
|
522
|
+
var _resilientClient = null;
|
|
471
523
|
var initTurso = initDatabase;
|
|
472
524
|
async function initDatabase(config) {
|
|
473
525
|
if (_client) {
|
|
474
526
|
_client.close();
|
|
475
527
|
_client = null;
|
|
528
|
+
_resilientClient = null;
|
|
476
529
|
}
|
|
477
530
|
const opts = {
|
|
478
531
|
url: `file:${config.dbPath}`
|
|
@@ -481,17 +534,24 @@ async function initDatabase(config) {
|
|
|
481
534
|
opts.encryptionKey = config.encryptionKey;
|
|
482
535
|
}
|
|
483
536
|
_client = createClient(opts);
|
|
537
|
+
_resilientClient = wrapWithRetry(_client);
|
|
484
538
|
}
|
|
485
539
|
function getClient() {
|
|
540
|
+
if (!_resilientClient) {
|
|
541
|
+
throw new Error("Database client not initialized. Call initDatabase() first.");
|
|
542
|
+
}
|
|
543
|
+
return _resilientClient;
|
|
544
|
+
}
|
|
545
|
+
function getRawClient() {
|
|
486
546
|
if (!_client) {
|
|
487
547
|
throw new Error("Database client not initialized. Call initDatabase() first.");
|
|
488
548
|
}
|
|
489
549
|
return _client;
|
|
490
550
|
}
|
|
491
551
|
async function ensureSchema() {
|
|
492
|
-
const client =
|
|
552
|
+
const client = getRawClient();
|
|
493
553
|
await client.execute("PRAGMA journal_mode = WAL");
|
|
494
|
-
await client.execute("PRAGMA busy_timeout =
|
|
554
|
+
await client.execute("PRAGMA busy_timeout = 30000");
|
|
495
555
|
try {
|
|
496
556
|
await client.execute("PRAGMA libsql_vector_search_ef = 128");
|
|
497
557
|
} catch {
|