@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
|
@@ -324,7 +324,7 @@ function listShards() {
|
|
|
324
324
|
}
|
|
325
325
|
async function ensureShardSchema(client) {
|
|
326
326
|
await client.execute("PRAGMA journal_mode = WAL");
|
|
327
|
-
await client.execute("PRAGMA busy_timeout =
|
|
327
|
+
await client.execute("PRAGMA busy_timeout = 30000");
|
|
328
328
|
try {
|
|
329
329
|
await client.execute("PRAGMA libsql_vector_search_ef = 128");
|
|
330
330
|
} catch {
|
|
@@ -512,7 +512,7 @@ var init_shard_manager = __esm({
|
|
|
512
512
|
import net from "net";
|
|
513
513
|
import { spawn } from "child_process";
|
|
514
514
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
515
|
-
import { existsSync as existsSync7, unlinkSync, readFileSync as
|
|
515
|
+
import { existsSync as existsSync7, unlinkSync, readFileSync as readFileSync5, openSync, closeSync, statSync } from "fs";
|
|
516
516
|
import path8 from "path";
|
|
517
517
|
import { fileURLToPath } from "url";
|
|
518
518
|
function handleData(chunk) {
|
|
@@ -537,7 +537,7 @@ function handleData(chunk) {
|
|
|
537
537
|
function cleanupStaleFiles() {
|
|
538
538
|
if (existsSync7(PID_PATH)) {
|
|
539
539
|
try {
|
|
540
|
-
const pid = parseInt(
|
|
540
|
+
const pid = parseInt(readFileSync5(PID_PATH, "utf8").trim(), 10);
|
|
541
541
|
if (pid > 0) {
|
|
542
542
|
try {
|
|
543
543
|
process.kill(pid, 0);
|
|
@@ -685,11 +685,11 @@ async function connectEmbedDaemon() {
|
|
|
685
685
|
}
|
|
686
686
|
}
|
|
687
687
|
const start = Date.now();
|
|
688
|
-
let
|
|
688
|
+
let delay2 = 100;
|
|
689
689
|
while (Date.now() - start < CONNECT_TIMEOUT_MS) {
|
|
690
|
-
await new Promise((r) => setTimeout(r,
|
|
690
|
+
await new Promise((r) => setTimeout(r, delay2));
|
|
691
691
|
if (await connectToSocket()) return true;
|
|
692
|
-
|
|
692
|
+
delay2 = Math.min(delay2 * 2, 3e3);
|
|
693
693
|
}
|
|
694
694
|
return false;
|
|
695
695
|
}
|
|
@@ -745,7 +745,7 @@ function killAndRespawnDaemon() {
|
|
|
745
745
|
process.stderr.write("[exed-client] Killing daemon for restart...\n");
|
|
746
746
|
if (existsSync7(PID_PATH)) {
|
|
747
747
|
try {
|
|
748
|
-
const pid = parseInt(
|
|
748
|
+
const pid = parseInt(readFileSync5(PID_PATH, "utf8").trim(), 10);
|
|
749
749
|
if (pid > 0) {
|
|
750
750
|
try {
|
|
751
751
|
process.kill(pid, "SIGKILL");
|
|
@@ -781,11 +781,11 @@ async function embedViaClient(text, priority = "high") {
|
|
|
781
781
|
`);
|
|
782
782
|
killAndRespawnDaemon();
|
|
783
783
|
const start = Date.now();
|
|
784
|
-
let
|
|
784
|
+
let delay2 = 200;
|
|
785
785
|
while (Date.now() - start < CONNECT_TIMEOUT_MS) {
|
|
786
|
-
await new Promise((r) => setTimeout(r,
|
|
786
|
+
await new Promise((r) => setTimeout(r, delay2));
|
|
787
787
|
if (await connectToSocket()) break;
|
|
788
|
-
|
|
788
|
+
delay2 = Math.min(delay2 * 2, 3e3);
|
|
789
789
|
}
|
|
790
790
|
if (!_connected) return null;
|
|
791
791
|
}
|
|
@@ -797,11 +797,11 @@ async function embedViaClient(text, priority = "high") {
|
|
|
797
797
|
`);
|
|
798
798
|
killAndRespawnDaemon();
|
|
799
799
|
const start = Date.now();
|
|
800
|
-
let
|
|
800
|
+
let delay2 = 200;
|
|
801
801
|
while (Date.now() - start < CONNECT_TIMEOUT_MS) {
|
|
802
|
-
await new Promise((r) => setTimeout(r,
|
|
802
|
+
await new Promise((r) => setTimeout(r, delay2));
|
|
803
803
|
if (await connectToSocket()) break;
|
|
804
|
-
|
|
804
|
+
delay2 = Math.min(delay2 * 2, 3e3);
|
|
805
805
|
}
|
|
806
806
|
if (!_connected) return null;
|
|
807
807
|
const retry = await sendRequest([text], priority);
|
|
@@ -958,12 +958,65 @@ init_memory();
|
|
|
958
958
|
|
|
959
959
|
// src/lib/database.ts
|
|
960
960
|
import { createClient } from "@libsql/client";
|
|
961
|
+
|
|
962
|
+
// src/lib/db-retry.ts
|
|
963
|
+
var MAX_RETRIES = 3;
|
|
964
|
+
var BASE_DELAY_MS = 200;
|
|
965
|
+
var MAX_JITTER_MS = 300;
|
|
966
|
+
function isBusyError(err) {
|
|
967
|
+
if (err instanceof Error) {
|
|
968
|
+
const msg = err.message.toLowerCase();
|
|
969
|
+
return msg.includes("sqlite_busy") || msg.includes("database is locked");
|
|
970
|
+
}
|
|
971
|
+
return false;
|
|
972
|
+
}
|
|
973
|
+
function delay(ms) {
|
|
974
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
975
|
+
}
|
|
976
|
+
async function retryOnBusy(fn, label) {
|
|
977
|
+
let lastError;
|
|
978
|
+
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
979
|
+
try {
|
|
980
|
+
return await fn();
|
|
981
|
+
} catch (err) {
|
|
982
|
+
lastError = err;
|
|
983
|
+
if (!isBusyError(err) || attempt === MAX_RETRIES) {
|
|
984
|
+
throw err;
|
|
985
|
+
}
|
|
986
|
+
const backoff = BASE_DELAY_MS * Math.pow(2, attempt);
|
|
987
|
+
const jitter = Math.floor(Math.random() * MAX_JITTER_MS);
|
|
988
|
+
process.stderr.write(
|
|
989
|
+
`[exe-os] SQLITE_BUSY ${label} retry ${attempt + 1}/${MAX_RETRIES} \u2014 waiting ${backoff + jitter}ms
|
|
990
|
+
`
|
|
991
|
+
);
|
|
992
|
+
await delay(backoff + jitter);
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
throw lastError;
|
|
996
|
+
}
|
|
997
|
+
function wrapWithRetry(client) {
|
|
998
|
+
return new Proxy(client, {
|
|
999
|
+
get(target, prop, receiver) {
|
|
1000
|
+
if (prop === "execute") {
|
|
1001
|
+
return (sql) => retryOnBusy(() => target.execute(sql), "execute");
|
|
1002
|
+
}
|
|
1003
|
+
if (prop === "batch") {
|
|
1004
|
+
return (stmts) => retryOnBusy(() => target.batch(stmts), "batch");
|
|
1005
|
+
}
|
|
1006
|
+
return Reflect.get(target, prop, receiver);
|
|
1007
|
+
}
|
|
1008
|
+
});
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
// src/lib/database.ts
|
|
961
1012
|
var _client = null;
|
|
1013
|
+
var _resilientClient = null;
|
|
962
1014
|
var initTurso = initDatabase;
|
|
963
1015
|
async function initDatabase(config) {
|
|
964
1016
|
if (_client) {
|
|
965
1017
|
_client.close();
|
|
966
1018
|
_client = null;
|
|
1019
|
+
_resilientClient = null;
|
|
967
1020
|
}
|
|
968
1021
|
const opts = {
|
|
969
1022
|
url: `file:${config.dbPath}`
|
|
@@ -972,20 +1025,27 @@ async function initDatabase(config) {
|
|
|
972
1025
|
opts.encryptionKey = config.encryptionKey;
|
|
973
1026
|
}
|
|
974
1027
|
_client = createClient(opts);
|
|
1028
|
+
_resilientClient = wrapWithRetry(_client);
|
|
975
1029
|
}
|
|
976
1030
|
function isInitialized() {
|
|
977
1031
|
return _client !== null;
|
|
978
1032
|
}
|
|
979
1033
|
function getClient() {
|
|
1034
|
+
if (!_resilientClient) {
|
|
1035
|
+
throw new Error("Database client not initialized. Call initDatabase() first.");
|
|
1036
|
+
}
|
|
1037
|
+
return _resilientClient;
|
|
1038
|
+
}
|
|
1039
|
+
function getRawClient() {
|
|
980
1040
|
if (!_client) {
|
|
981
1041
|
throw new Error("Database client not initialized. Call initDatabase() first.");
|
|
982
1042
|
}
|
|
983
1043
|
return _client;
|
|
984
1044
|
}
|
|
985
1045
|
async function ensureSchema() {
|
|
986
|
-
const client =
|
|
1046
|
+
const client = getRawClient();
|
|
987
1047
|
await client.execute("PRAGMA journal_mode = WAL");
|
|
988
|
-
await client.execute("PRAGMA busy_timeout =
|
|
1048
|
+
await client.execute("PRAGMA busy_timeout = 30000");
|
|
989
1049
|
try {
|
|
990
1050
|
await client.execute("PRAGMA libsql_vector_search_ef = 128");
|
|
991
1051
|
} catch {
|
|
@@ -2045,20 +2105,20 @@ function vectorToBlob(vector) {
|
|
|
2045
2105
|
}
|
|
2046
2106
|
|
|
2047
2107
|
// src/lib/plan-limits.ts
|
|
2048
|
-
import { readFileSync as
|
|
2108
|
+
import { readFileSync as readFileSync4, existsSync as existsSync6 } from "fs";
|
|
2049
2109
|
import path7 from "path";
|
|
2050
2110
|
|
|
2051
2111
|
// src/lib/employees.ts
|
|
2052
2112
|
init_config();
|
|
2053
2113
|
import { readFile as readFile3, writeFile as writeFile3, mkdir as mkdir3 } from "fs/promises";
|
|
2054
|
-
import { existsSync as existsSync4, symlinkSync, readlinkSync } from "fs";
|
|
2114
|
+
import { existsSync as existsSync4, symlinkSync, readlinkSync, readFileSync as readFileSync2 } from "fs";
|
|
2055
2115
|
import { execSync as execSync2 } from "child_process";
|
|
2056
2116
|
import path5 from "path";
|
|
2057
2117
|
var EMPLOYEES_PATH = path5.join(EXE_AI_DIR, "exe-employees.json");
|
|
2058
2118
|
|
|
2059
2119
|
// src/lib/license.ts
|
|
2060
2120
|
init_config();
|
|
2061
|
-
import { readFileSync as
|
|
2121
|
+
import { readFileSync as readFileSync3, writeFileSync, existsSync as existsSync5, mkdirSync as mkdirSync2 } from "fs";
|
|
2062
2122
|
import { randomUUID } from "crypto";
|
|
2063
2123
|
import path6 from "path";
|
|
2064
2124
|
import { jwtVerify, importSPKI } from "jose";
|
|
@@ -2091,14 +2151,14 @@ function loadDeviceId() {
|
|
|
2091
2151
|
const deviceJsonPath = path6.join(EXE_AI_DIR, "device.json");
|
|
2092
2152
|
try {
|
|
2093
2153
|
if (existsSync5(deviceJsonPath)) {
|
|
2094
|
-
const data = JSON.parse(
|
|
2154
|
+
const data = JSON.parse(readFileSync3(deviceJsonPath, "utf8"));
|
|
2095
2155
|
if (data.deviceId) return data.deviceId;
|
|
2096
2156
|
}
|
|
2097
2157
|
} catch {
|
|
2098
2158
|
}
|
|
2099
2159
|
try {
|
|
2100
2160
|
if (existsSync5(DEVICE_ID_PATH)) {
|
|
2101
|
-
const id2 =
|
|
2161
|
+
const id2 = readFileSync3(DEVICE_ID_PATH, "utf8").trim();
|
|
2102
2162
|
if (id2) return id2;
|
|
2103
2163
|
}
|
|
2104
2164
|
} catch {
|
|
@@ -2111,7 +2171,7 @@ function loadDeviceId() {
|
|
|
2111
2171
|
function loadLicense() {
|
|
2112
2172
|
try {
|
|
2113
2173
|
if (!existsSync5(LICENSE_PATH)) return null;
|
|
2114
|
-
return
|
|
2174
|
+
return readFileSync3(LICENSE_PATH, "utf8").trim();
|
|
2115
2175
|
} catch {
|
|
2116
2176
|
return null;
|
|
2117
2177
|
}
|
|
@@ -2141,7 +2201,7 @@ async function verifyLicenseJwt(token) {
|
|
|
2141
2201
|
async function getCachedLicense() {
|
|
2142
2202
|
try {
|
|
2143
2203
|
if (!existsSync5(CACHE_PATH)) return null;
|
|
2144
|
-
const raw = JSON.parse(
|
|
2204
|
+
const raw = JSON.parse(readFileSync3(CACHE_PATH, "utf8"));
|
|
2145
2205
|
if (!raw.token || typeof raw.token !== "string") return null;
|
|
2146
2206
|
return await verifyLicenseJwt(raw.token);
|
|
2147
2207
|
} catch {
|
|
@@ -277,12 +277,68 @@ var init_memory = __esm({
|
|
|
277
277
|
}
|
|
278
278
|
});
|
|
279
279
|
|
|
280
|
+
// src/lib/db-retry.ts
|
|
281
|
+
function isBusyError(err) {
|
|
282
|
+
if (err instanceof Error) {
|
|
283
|
+
const msg = err.message.toLowerCase();
|
|
284
|
+
return msg.includes("sqlite_busy") || msg.includes("database is locked");
|
|
285
|
+
}
|
|
286
|
+
return false;
|
|
287
|
+
}
|
|
288
|
+
function delay(ms) {
|
|
289
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
290
|
+
}
|
|
291
|
+
async function retryOnBusy(fn, label) {
|
|
292
|
+
let lastError;
|
|
293
|
+
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
294
|
+
try {
|
|
295
|
+
return await fn();
|
|
296
|
+
} catch (err) {
|
|
297
|
+
lastError = err;
|
|
298
|
+
if (!isBusyError(err) || attempt === MAX_RETRIES) {
|
|
299
|
+
throw err;
|
|
300
|
+
}
|
|
301
|
+
const backoff = BASE_DELAY_MS * Math.pow(2, attempt);
|
|
302
|
+
const jitter = Math.floor(Math.random() * MAX_JITTER_MS);
|
|
303
|
+
process.stderr.write(
|
|
304
|
+
`[exe-os] SQLITE_BUSY ${label} retry ${attempt + 1}/${MAX_RETRIES} \u2014 waiting ${backoff + jitter}ms
|
|
305
|
+
`
|
|
306
|
+
);
|
|
307
|
+
await delay(backoff + jitter);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
throw lastError;
|
|
311
|
+
}
|
|
312
|
+
function wrapWithRetry(client) {
|
|
313
|
+
return new Proxy(client, {
|
|
314
|
+
get(target, prop, receiver) {
|
|
315
|
+
if (prop === "execute") {
|
|
316
|
+
return (sql) => retryOnBusy(() => target.execute(sql), "execute");
|
|
317
|
+
}
|
|
318
|
+
if (prop === "batch") {
|
|
319
|
+
return (stmts) => retryOnBusy(() => target.batch(stmts), "batch");
|
|
320
|
+
}
|
|
321
|
+
return Reflect.get(target, prop, receiver);
|
|
322
|
+
}
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
var MAX_RETRIES, BASE_DELAY_MS, MAX_JITTER_MS;
|
|
326
|
+
var init_db_retry = __esm({
|
|
327
|
+
"src/lib/db-retry.ts"() {
|
|
328
|
+
"use strict";
|
|
329
|
+
MAX_RETRIES = 3;
|
|
330
|
+
BASE_DELAY_MS = 200;
|
|
331
|
+
MAX_JITTER_MS = 300;
|
|
332
|
+
}
|
|
333
|
+
});
|
|
334
|
+
|
|
280
335
|
// src/lib/database.ts
|
|
281
336
|
import { createClient } from "@libsql/client";
|
|
282
337
|
async function initDatabase(config) {
|
|
283
338
|
if (_client) {
|
|
284
339
|
_client.close();
|
|
285
340
|
_client = null;
|
|
341
|
+
_resilientClient = null;
|
|
286
342
|
}
|
|
287
343
|
const opts = {
|
|
288
344
|
url: `file:${config.dbPath}`
|
|
@@ -291,17 +347,24 @@ async function initDatabase(config) {
|
|
|
291
347
|
opts.encryptionKey = config.encryptionKey;
|
|
292
348
|
}
|
|
293
349
|
_client = createClient(opts);
|
|
350
|
+
_resilientClient = wrapWithRetry(_client);
|
|
294
351
|
}
|
|
295
352
|
function getClient() {
|
|
353
|
+
if (!_resilientClient) {
|
|
354
|
+
throw new Error("Database client not initialized. Call initDatabase() first.");
|
|
355
|
+
}
|
|
356
|
+
return _resilientClient;
|
|
357
|
+
}
|
|
358
|
+
function getRawClient() {
|
|
296
359
|
if (!_client) {
|
|
297
360
|
throw new Error("Database client not initialized. Call initDatabase() first.");
|
|
298
361
|
}
|
|
299
362
|
return _client;
|
|
300
363
|
}
|
|
301
364
|
async function ensureSchema() {
|
|
302
|
-
const client =
|
|
365
|
+
const client = getRawClient();
|
|
303
366
|
await client.execute("PRAGMA journal_mode = WAL");
|
|
304
|
-
await client.execute("PRAGMA busy_timeout =
|
|
367
|
+
await client.execute("PRAGMA busy_timeout = 30000");
|
|
305
368
|
try {
|
|
306
369
|
await client.execute("PRAGMA libsql_vector_search_ef = 128");
|
|
307
370
|
} catch {
|
|
@@ -1094,13 +1157,16 @@ async function disposeDatabase() {
|
|
|
1094
1157
|
if (_client) {
|
|
1095
1158
|
_client.close();
|
|
1096
1159
|
_client = null;
|
|
1160
|
+
_resilientClient = null;
|
|
1097
1161
|
}
|
|
1098
1162
|
}
|
|
1099
|
-
var _client, initTurso, disposeTurso;
|
|
1163
|
+
var _client, _resilientClient, initTurso, disposeTurso;
|
|
1100
1164
|
var init_database = __esm({
|
|
1101
1165
|
"src/lib/database.ts"() {
|
|
1102
1166
|
"use strict";
|
|
1167
|
+
init_db_retry();
|
|
1103
1168
|
_client = null;
|
|
1169
|
+
_resilientClient = null;
|
|
1104
1170
|
initTurso = initDatabase;
|
|
1105
1171
|
disposeTurso = disposeDatabase;
|
|
1106
1172
|
}
|
|
@@ -1213,7 +1279,7 @@ function listShards() {
|
|
|
1213
1279
|
}
|
|
1214
1280
|
async function ensureShardSchema(client) {
|
|
1215
1281
|
await client.execute("PRAGMA journal_mode = WAL");
|
|
1216
|
-
await client.execute("PRAGMA busy_timeout =
|
|
1282
|
+
await client.execute("PRAGMA busy_timeout = 30000");
|
|
1217
1283
|
try {
|
|
1218
1284
|
await client.execute("PRAGMA libsql_vector_search_ef = 128");
|
|
1219
1285
|
} catch {
|
|
@@ -2098,11 +2164,11 @@ async function connectEmbedDaemon() {
|
|
|
2098
2164
|
}
|
|
2099
2165
|
}
|
|
2100
2166
|
const start = Date.now();
|
|
2101
|
-
let
|
|
2167
|
+
let delay2 = 100;
|
|
2102
2168
|
while (Date.now() - start < CONNECT_TIMEOUT_MS) {
|
|
2103
|
-
await new Promise((r) => setTimeout(r,
|
|
2169
|
+
await new Promise((r) => setTimeout(r, delay2));
|
|
2104
2170
|
if (await connectToSocket()) return true;
|
|
2105
|
-
|
|
2171
|
+
delay2 = Math.min(delay2 * 2, 3e3);
|
|
2106
2172
|
}
|
|
2107
2173
|
return false;
|
|
2108
2174
|
}
|
|
@@ -2194,11 +2260,11 @@ async function embedViaClient(text, priority = "high") {
|
|
|
2194
2260
|
`);
|
|
2195
2261
|
killAndRespawnDaemon();
|
|
2196
2262
|
const start = Date.now();
|
|
2197
|
-
let
|
|
2263
|
+
let delay2 = 200;
|
|
2198
2264
|
while (Date.now() - start < CONNECT_TIMEOUT_MS) {
|
|
2199
|
-
await new Promise((r) => setTimeout(r,
|
|
2265
|
+
await new Promise((r) => setTimeout(r, delay2));
|
|
2200
2266
|
if (await connectToSocket()) break;
|
|
2201
|
-
|
|
2267
|
+
delay2 = Math.min(delay2 * 2, 3e3);
|
|
2202
2268
|
}
|
|
2203
2269
|
if (!_connected) return null;
|
|
2204
2270
|
}
|
|
@@ -2210,11 +2276,11 @@ async function embedViaClient(text, priority = "high") {
|
|
|
2210
2276
|
`);
|
|
2211
2277
|
killAndRespawnDaemon();
|
|
2212
2278
|
const start = Date.now();
|
|
2213
|
-
let
|
|
2279
|
+
let delay2 = 200;
|
|
2214
2280
|
while (Date.now() - start < CONNECT_TIMEOUT_MS) {
|
|
2215
|
-
await new Promise((r) => setTimeout(r,
|
|
2281
|
+
await new Promise((r) => setTimeout(r, delay2));
|
|
2216
2282
|
if (await connectToSocket()) break;
|
|
2217
|
-
|
|
2283
|
+
delay2 = Math.min(delay2 * 2, 3e3);
|
|
2218
2284
|
}
|
|
2219
2285
|
if (!_connected) return null;
|
|
2220
2286
|
const retry = await sendRequest([text], priority);
|
|
@@ -3035,8 +3101,8 @@ function drainQueue(isSessionBusy, sendKeys) {
|
|
|
3035
3101
|
} catch {
|
|
3036
3102
|
}
|
|
3037
3103
|
item.attempts++;
|
|
3038
|
-
if (item.attempts >=
|
|
3039
|
-
logQueue(`FAILED \u2192 ${item.targetSession} (${
|
|
3104
|
+
if (item.attempts >= MAX_RETRIES2) {
|
|
3105
|
+
logQueue(`FAILED \u2192 ${item.targetSession} (${MAX_RETRIES2} retries exhausted, reason: ${item.reason})`);
|
|
3040
3106
|
failed++;
|
|
3041
3107
|
continue;
|
|
3042
3108
|
}
|
|
@@ -3069,12 +3135,12 @@ function logQueue(msg) {
|
|
|
3069
3135
|
} catch {
|
|
3070
3136
|
}
|
|
3071
3137
|
}
|
|
3072
|
-
var QUEUE_PATH,
|
|
3138
|
+
var QUEUE_PATH, MAX_RETRIES2, TTL_MS, INTERCOM_LOG;
|
|
3073
3139
|
var init_intercom_queue = __esm({
|
|
3074
3140
|
"src/lib/intercom-queue.ts"() {
|
|
3075
3141
|
"use strict";
|
|
3076
3142
|
QUEUE_PATH = path10.join(os3.homedir(), ".exe-os", "intercom-queue.json");
|
|
3077
|
-
|
|
3143
|
+
MAX_RETRIES2 = 5;
|
|
3078
3144
|
TTL_MS = 60 * 60 * 1e3;
|
|
3079
3145
|
INTERCOM_LOG = path10.join(os3.homedir(), ".exe-os", "intercom.log");
|
|
3080
3146
|
}
|
|
@@ -3082,7 +3148,7 @@ var init_intercom_queue = __esm({
|
|
|
3082
3148
|
|
|
3083
3149
|
// src/lib/employees.ts
|
|
3084
3150
|
import { readFile as readFile3, writeFile as writeFile3, mkdir as mkdir3 } from "fs/promises";
|
|
3085
|
-
import { existsSync as existsSync9, symlinkSync, readlinkSync } from "fs";
|
|
3151
|
+
import { existsSync as existsSync9, symlinkSync, readlinkSync, readFileSync as readFileSync7 } from "fs";
|
|
3086
3152
|
import { execSync as execSync6 } from "child_process";
|
|
3087
3153
|
import path11 from "path";
|
|
3088
3154
|
async function loadEmployees(employeesPath = EMPLOYEES_PATH) {
|
|
@@ -3109,7 +3175,7 @@ var init_employees = __esm({
|
|
|
3109
3175
|
});
|
|
3110
3176
|
|
|
3111
3177
|
// src/lib/license.ts
|
|
3112
|
-
import { readFileSync as
|
|
3178
|
+
import { readFileSync as readFileSync8, writeFileSync as writeFileSync4, existsSync as existsSync10, mkdirSync as mkdirSync5 } from "fs";
|
|
3113
3179
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
3114
3180
|
import path12 from "path";
|
|
3115
3181
|
import { jwtVerify, importSPKI } from "jose";
|
|
@@ -3132,12 +3198,12 @@ var init_license = __esm({
|
|
|
3132
3198
|
});
|
|
3133
3199
|
|
|
3134
3200
|
// src/lib/plan-limits.ts
|
|
3135
|
-
import { readFileSync as
|
|
3201
|
+
import { readFileSync as readFileSync9, existsSync as existsSync11 } from "fs";
|
|
3136
3202
|
import path13 from "path";
|
|
3137
3203
|
function getLicenseSync() {
|
|
3138
3204
|
try {
|
|
3139
3205
|
if (!existsSync11(CACHE_PATH2)) return freeLicense();
|
|
3140
|
-
const raw = JSON.parse(
|
|
3206
|
+
const raw = JSON.parse(readFileSync9(CACHE_PATH2, "utf8"));
|
|
3141
3207
|
if (!raw.token || typeof raw.token !== "string") return freeLicense();
|
|
3142
3208
|
const parts = raw.token.split(".");
|
|
3143
3209
|
if (parts.length !== 3) return freeLicense();
|
|
@@ -3176,7 +3242,7 @@ function assertEmployeeLimitSync(rosterPath) {
|
|
|
3176
3242
|
let count = 0;
|
|
3177
3243
|
try {
|
|
3178
3244
|
if (existsSync11(filePath)) {
|
|
3179
|
-
const raw =
|
|
3245
|
+
const raw = readFileSync9(filePath, "utf8");
|
|
3180
3246
|
const employees = JSON.parse(raw);
|
|
3181
3247
|
count = Array.isArray(employees) ? employees.length : 0;
|
|
3182
3248
|
}
|
|
@@ -3211,7 +3277,7 @@ var init_plan_limits = __esm({
|
|
|
3211
3277
|
|
|
3212
3278
|
// src/lib/tmux-routing.ts
|
|
3213
3279
|
import { execFileSync as execFileSync2, execSync as execSync7 } from "child_process";
|
|
3214
|
-
import { readFileSync as
|
|
3280
|
+
import { readFileSync as readFileSync10, writeFileSync as writeFileSync5, mkdirSync as mkdirSync6, existsSync as existsSync12, appendFileSync } from "fs";
|
|
3215
3281
|
import path14 from "path";
|
|
3216
3282
|
import os4 from "os";
|
|
3217
3283
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
@@ -3260,7 +3326,7 @@ function extractRootExe(name) {
|
|
|
3260
3326
|
}
|
|
3261
3327
|
function getParentExe(sessionKey) {
|
|
3262
3328
|
try {
|
|
3263
|
-
const data = JSON.parse(
|
|
3329
|
+
const data = JSON.parse(readFileSync10(path14.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
|
|
3264
3330
|
return data.parentExe || null;
|
|
3265
3331
|
} catch {
|
|
3266
3332
|
return null;
|
|
@@ -3294,7 +3360,7 @@ function findFreeInstance(employeeName, exeSession, maxInstances = 10, isAlive =
|
|
|
3294
3360
|
function readDebounceState() {
|
|
3295
3361
|
try {
|
|
3296
3362
|
if (!existsSync12(DEBOUNCE_FILE)) return {};
|
|
3297
|
-
return JSON.parse(
|
|
3363
|
+
return JSON.parse(readFileSync10(DEBOUNCE_FILE, "utf8"));
|
|
3298
3364
|
} catch {
|
|
3299
3365
|
return {};
|
|
3300
3366
|
}
|
|
@@ -3468,7 +3534,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3468
3534
|
const claudeJsonPath = path14.join(os4.homedir(), ".claude.json");
|
|
3469
3535
|
let claudeJson = {};
|
|
3470
3536
|
try {
|
|
3471
|
-
claudeJson = JSON.parse(
|
|
3537
|
+
claudeJson = JSON.parse(readFileSync10(claudeJsonPath, "utf8"));
|
|
3472
3538
|
} catch {
|
|
3473
3539
|
}
|
|
3474
3540
|
if (!claudeJson.projects) claudeJson.projects = {};
|
|
@@ -3486,7 +3552,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3486
3552
|
const settingsPath = path14.join(projSettingsDir, "settings.json");
|
|
3487
3553
|
let settings = {};
|
|
3488
3554
|
try {
|
|
3489
|
-
settings = JSON.parse(
|
|
3555
|
+
settings = JSON.parse(readFileSync10(settingsPath, "utf8"));
|
|
3490
3556
|
} catch {
|
|
3491
3557
|
}
|
|
3492
3558
|
const perms = settings.permissions ?? {};
|
|
@@ -3813,7 +3879,7 @@ async function deliverLocalMessage(messageId) {
|
|
|
3813
3879
|
return true;
|
|
3814
3880
|
} catch {
|
|
3815
3881
|
const newRetryCount = msg.retryCount + 1;
|
|
3816
|
-
if (newRetryCount >=
|
|
3882
|
+
if (newRetryCount >= MAX_RETRIES3) {
|
|
3817
3883
|
await markFailed(messageId, "session unavailable after 10 retries");
|
|
3818
3884
|
} else {
|
|
3819
3885
|
await client.execute({
|
|
@@ -3902,7 +3968,7 @@ async function retryPendingMessages() {
|
|
|
3902
3968
|
sql: `SELECT * FROM messages
|
|
3903
3969
|
WHERE status = 'pending' AND retry_count < ?
|
|
3904
3970
|
ORDER BY id`,
|
|
3905
|
-
args: [
|
|
3971
|
+
args: [MAX_RETRIES3]
|
|
3906
3972
|
});
|
|
3907
3973
|
let delivered = 0;
|
|
3908
3974
|
for (const row of result.rows) {
|
|
@@ -3915,13 +3981,13 @@ async function retryPendingMessages() {
|
|
|
3915
3981
|
}
|
|
3916
3982
|
return delivered;
|
|
3917
3983
|
}
|
|
3918
|
-
var
|
|
3984
|
+
var MAX_RETRIES3, _wsClientSend;
|
|
3919
3985
|
var init_messaging = __esm({
|
|
3920
3986
|
"src/lib/messaging.ts"() {
|
|
3921
3987
|
"use strict";
|
|
3922
3988
|
init_database();
|
|
3923
3989
|
init_tmux_routing();
|
|
3924
|
-
|
|
3990
|
+
MAX_RETRIES3 = 10;
|
|
3925
3991
|
_wsClientSend = null;
|
|
3926
3992
|
}
|
|
3927
3993
|
});
|
|
@@ -3931,7 +3997,7 @@ import crypto4 from "crypto";
|
|
|
3931
3997
|
import path15 from "path";
|
|
3932
3998
|
import os5 from "os";
|
|
3933
3999
|
import {
|
|
3934
|
-
readFileSync as
|
|
4000
|
+
readFileSync as readFileSync11,
|
|
3935
4001
|
readdirSync as readdirSync3,
|
|
3936
4002
|
unlinkSync as unlinkSync3,
|
|
3937
4003
|
existsSync as existsSync13,
|
|
@@ -3973,7 +4039,7 @@ import crypto5 from "crypto";
|
|
|
3973
4039
|
import path16 from "path";
|
|
3974
4040
|
import { execSync as execSync8 } from "child_process";
|
|
3975
4041
|
import { mkdir as mkdir4, writeFile as writeFile4, appendFile } from "fs/promises";
|
|
3976
|
-
import { existsSync as existsSync14, readFileSync as
|
|
4042
|
+
import { existsSync as existsSync14, readFileSync as readFileSync12 } from "fs";
|
|
3977
4043
|
function extractParentFromContext(contextBody) {
|
|
3978
4044
|
if (!contextBody) return null;
|
|
3979
4045
|
const match = contextBody.match(
|
|
@@ -4163,7 +4229,7 @@ async function ensureGitignoreExe(baseDir) {
|
|
|
4163
4229
|
const gitignorePath = path16.join(baseDir, ".gitignore");
|
|
4164
4230
|
try {
|
|
4165
4231
|
if (existsSync14(gitignorePath)) {
|
|
4166
|
-
const content =
|
|
4232
|
+
const content = readFileSync12(gitignorePath, "utf-8");
|
|
4167
4233
|
if (/^\/?exe\/?$/m.test(content)) return;
|
|
4168
4234
|
await appendFile(gitignorePath, "\n# Employee task assignments (private)\n/exe/\n");
|
|
4169
4235
|
} else {
|
|
@@ -4429,7 +4495,7 @@ init_config();
|
|
|
4429
4495
|
init_config();
|
|
4430
4496
|
init_store();
|
|
4431
4497
|
import { spawn as spawn2 } from "child_process";
|
|
4432
|
-
import { readFileSync as
|
|
4498
|
+
import { readFileSync as readFileSync13, writeFileSync as writeFileSync6, mkdirSync as mkdirSync7, existsSync as existsSync16, openSync as openSync2, closeSync as closeSync2 } from "fs";
|
|
4433
4499
|
import path18 from "path";
|
|
4434
4500
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
4435
4501
|
|
|
@@ -4872,7 +4938,7 @@ function openWorkerLog() {
|
|
|
4872
4938
|
var CACHE_DIR2 = path18.join(EXE_AI_DIR, "session-cache");
|
|
4873
4939
|
function loadInjectedIds(sessionId) {
|
|
4874
4940
|
try {
|
|
4875
|
-
const raw =
|
|
4941
|
+
const raw = readFileSync13(path18.join(CACHE_DIR2, `${sessionId}.json`), "utf8");
|
|
4876
4942
|
return new Set(JSON.parse(raw));
|
|
4877
4943
|
} catch {
|
|
4878
4944
|
return /* @__PURE__ */ new Set();
|
|
@@ -4967,7 +5033,7 @@ ${fresh.map(
|
|
|
4967
5033
|
const lastCheckPath = path18.join(CACHE_DIR2, `review-lastcheck-${sessionKey}.json`);
|
|
4968
5034
|
let lastCheckedAt = "";
|
|
4969
5035
|
try {
|
|
4970
|
-
lastCheckedAt =
|
|
5036
|
+
lastCheckedAt = readFileSync13(lastCheckPath, "utf8").trim();
|
|
4971
5037
|
} catch {
|
|
4972
5038
|
}
|
|
4973
5039
|
const totalCount = await countPendingReviews2();
|