@askexenow/exe-os 0.8.33 → 0.8.37
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 +341 -349
- package/dist/bin/backfill-responses.js +81 -13
- package/dist/bin/backfill-vectors.js +72 -12
- package/dist/bin/cleanup-stale-review-tasks.js +63 -3
- package/dist/bin/cli.js +1737 -1117
- package/dist/bin/exe-assign.js +89 -19
- package/dist/bin/exe-boot.js +951 -101
- package/dist/bin/exe-call.js +61 -2
- package/dist/bin/exe-dispatch.js +61 -13
- package/dist/bin/exe-doctor.js +63 -3
- package/dist/bin/exe-export-behaviors.js +71 -3
- package/dist/bin/exe-forget.js +69 -4
- package/dist/bin/exe-gateway.js +178 -45
- package/dist/bin/exe-heartbeat.js +79 -14
- package/dist/bin/exe-kill.js +71 -3
- package/dist/bin/exe-launch-agent.js +148 -14
- package/dist/bin/exe-link.js +1437 -0
- package/dist/bin/exe-new-employee.js +98 -13
- package/dist/bin/exe-pending-messages.js +74 -8
- package/dist/bin/exe-pending-notifications.js +63 -3
- package/dist/bin/exe-pending-reviews.js +77 -11
- package/dist/bin/exe-rename.js +1287 -0
- package/dist/bin/exe-review.js +73 -5
- package/dist/bin/exe-search.js +88 -14
- package/dist/bin/exe-session-cleanup.js +102 -28
- package/dist/bin/exe-status.js +64 -4
- package/dist/bin/exe-team.js +64 -4
- package/dist/bin/git-sweep.js +80 -5
- package/dist/bin/graph-backfill.js +71 -3
- package/dist/bin/graph-export.js +71 -3
- package/dist/bin/install.js +38 -8
- package/dist/bin/scan-tasks.js +80 -5
- package/dist/bin/setup.js +128 -10
- package/dist/bin/shard-migrate.js +71 -3
- package/dist/bin/wiki-sync.js +71 -3
- package/dist/gateway/index.js +179 -46
- package/dist/hooks/bug-report-worker.js +254 -28
- package/dist/hooks/commit-complete.js +80 -5
- package/dist/hooks/error-recall.js +89 -15
- package/dist/hooks/exe-heartbeat-hook.js +1 -1
- package/dist/hooks/ingest-worker.js +185 -51
- package/dist/hooks/ingest.js +1 -1
- package/dist/hooks/instructions-loaded.js +81 -6
- package/dist/hooks/notification.js +81 -6
- package/dist/hooks/post-compact.js +81 -6
- package/dist/hooks/pre-compact.js +81 -6
- package/dist/hooks/pre-tool-use.js +423 -196
- package/dist/hooks/prompt-ingest-worker.js +91 -23
- package/dist/hooks/prompt-submit.js +159 -45
- package/dist/hooks/response-ingest-worker.js +96 -23
- package/dist/hooks/session-end.js +81 -6
- package/dist/hooks/session-start.js +89 -15
- package/dist/hooks/stop.js +81 -6
- package/dist/hooks/subagent-stop.js +81 -6
- package/dist/hooks/summary-worker.js +807 -55
- package/dist/index.js +198 -60
- package/dist/lib/cloud-sync.js +703 -18
- 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 +26 -0
- package/dist/lib/employees.js +34 -1
- package/dist/lib/exe-daemon.js +207 -74
- package/dist/lib/hybrid-search.js +88 -14
- package/dist/lib/identity-templates.js +51 -0
- package/dist/lib/identity.js +3 -3
- package/dist/lib/messaging.js +65 -17
- 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 +73 -4
- package/dist/lib/task-router.js +4 -2
- package/dist/lib/tasks.js +95 -28
- package/dist/lib/tmux-routing.js +92 -23
- package/dist/mcp/server.js +800 -74
- 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 +198 -31
- package/dist/mcp/tools/deactivate-behavior.js +4 -4
- package/dist/mcp/tools/list-reminders.js +3 -3
- package/dist/mcp/tools/list-tasks.js +19 -9
- package/dist/mcp/tools/send-message.js +69 -21
- package/dist/mcp/tools/update-task.js +28 -18
- package/dist/runtime/index.js +166 -28
- package/dist/tui/App.js +193 -40
- package/package.json +7 -3
- package/src/commands/exe/afk.md +116 -0
- 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 {
|
|
@@ -1886,7 +1946,8 @@ async function writeMemory(record) {
|
|
|
1886
1946
|
has_error: record.has_error ? 1 : 0,
|
|
1887
1947
|
raw_text: record.raw_text,
|
|
1888
1948
|
vector: record.vector,
|
|
1889
|
-
version:
|
|
1949
|
+
version: 0,
|
|
1950
|
+
// Placeholder — assigned atomically at flush time
|
|
1890
1951
|
task_id: record.task_id ?? null,
|
|
1891
1952
|
importance: record.importance ?? 5,
|
|
1892
1953
|
status: record.status ?? "active",
|
|
@@ -1920,6 +1981,13 @@ async function flushBatch() {
|
|
|
1920
1981
|
_flushing = true;
|
|
1921
1982
|
try {
|
|
1922
1983
|
const batch = _pendingRecords.slice(0);
|
|
1984
|
+
const client = getClient();
|
|
1985
|
+
const vResult = await client.execute("SELECT MAX(version) as max_v FROM memories");
|
|
1986
|
+
let baseVersion = (Number(vResult.rows[0]?.max_v) || 0) + 1;
|
|
1987
|
+
for (const row of batch) {
|
|
1988
|
+
row.version = baseVersion++;
|
|
1989
|
+
}
|
|
1990
|
+
_nextVersion = baseVersion;
|
|
1923
1991
|
const buildStmt = (row) => {
|
|
1924
1992
|
const hasVector = row.vector !== null;
|
|
1925
1993
|
const taskId = row.task_id ?? null;
|
|
@@ -2045,20 +2113,20 @@ function vectorToBlob(vector) {
|
|
|
2045
2113
|
}
|
|
2046
2114
|
|
|
2047
2115
|
// src/lib/plan-limits.ts
|
|
2048
|
-
import { readFileSync as
|
|
2116
|
+
import { readFileSync as readFileSync4, existsSync as existsSync6 } from "fs";
|
|
2049
2117
|
import path7 from "path";
|
|
2050
2118
|
|
|
2051
2119
|
// src/lib/employees.ts
|
|
2052
2120
|
init_config();
|
|
2053
2121
|
import { readFile as readFile3, writeFile as writeFile3, mkdir as mkdir3 } from "fs/promises";
|
|
2054
|
-
import { existsSync as existsSync4, symlinkSync, readlinkSync } from "fs";
|
|
2122
|
+
import { existsSync as existsSync4, symlinkSync, readlinkSync, readFileSync as readFileSync2 } from "fs";
|
|
2055
2123
|
import { execSync as execSync2 } from "child_process";
|
|
2056
2124
|
import path5 from "path";
|
|
2057
2125
|
var EMPLOYEES_PATH = path5.join(EXE_AI_DIR, "exe-employees.json");
|
|
2058
2126
|
|
|
2059
2127
|
// src/lib/license.ts
|
|
2060
2128
|
init_config();
|
|
2061
|
-
import { readFileSync as
|
|
2129
|
+
import { readFileSync as readFileSync3, writeFileSync, existsSync as existsSync5, mkdirSync as mkdirSync2 } from "fs";
|
|
2062
2130
|
import { randomUUID } from "crypto";
|
|
2063
2131
|
import path6 from "path";
|
|
2064
2132
|
import { jwtVerify, importSPKI } from "jose";
|
|
@@ -2091,14 +2159,14 @@ function loadDeviceId() {
|
|
|
2091
2159
|
const deviceJsonPath = path6.join(EXE_AI_DIR, "device.json");
|
|
2092
2160
|
try {
|
|
2093
2161
|
if (existsSync5(deviceJsonPath)) {
|
|
2094
|
-
const data = JSON.parse(
|
|
2162
|
+
const data = JSON.parse(readFileSync3(deviceJsonPath, "utf8"));
|
|
2095
2163
|
if (data.deviceId) return data.deviceId;
|
|
2096
2164
|
}
|
|
2097
2165
|
} catch {
|
|
2098
2166
|
}
|
|
2099
2167
|
try {
|
|
2100
2168
|
if (existsSync5(DEVICE_ID_PATH)) {
|
|
2101
|
-
const id2 =
|
|
2169
|
+
const id2 = readFileSync3(DEVICE_ID_PATH, "utf8").trim();
|
|
2102
2170
|
if (id2) return id2;
|
|
2103
2171
|
}
|
|
2104
2172
|
} catch {
|
|
@@ -2111,7 +2179,7 @@ function loadDeviceId() {
|
|
|
2111
2179
|
function loadLicense() {
|
|
2112
2180
|
try {
|
|
2113
2181
|
if (!existsSync5(LICENSE_PATH)) return null;
|
|
2114
|
-
return
|
|
2182
|
+
return readFileSync3(LICENSE_PATH, "utf8").trim();
|
|
2115
2183
|
} catch {
|
|
2116
2184
|
return null;
|
|
2117
2185
|
}
|
|
@@ -2141,7 +2209,7 @@ async function verifyLicenseJwt(token) {
|
|
|
2141
2209
|
async function getCachedLicense() {
|
|
2142
2210
|
try {
|
|
2143
2211
|
if (!existsSync5(CACHE_PATH)) return null;
|
|
2144
|
-
const raw = JSON.parse(
|
|
2212
|
+
const raw = JSON.parse(readFileSync3(CACHE_PATH, "utf8"));
|
|
2145
2213
|
if (!raw.token || typeof raw.token !== "string") return null;
|
|
2146
2214
|
return await verifyLicenseJwt(raw.token);
|
|
2147
2215
|
} catch {
|