@askexenow/exe-os 0.8.37 → 0.8.39
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/README.md +17 -8
- package/dist/bin/backfill-conversations.js +112 -70
- package/dist/bin/backfill-responses.js +53 -18
- package/dist/bin/backfill-vectors.js +43 -16
- package/dist/bin/cleanup-stale-review-tasks.js +38 -16
- package/dist/bin/cli.js +790 -468
- package/dist/bin/exe-agent.js +19 -4
- package/dist/bin/exe-assign.js +46 -13
- package/dist/bin/exe-boot.js +288 -129
- package/dist/bin/exe-call.js +20 -10
- package/dist/bin/exe-cloud.js +135 -30
- package/dist/bin/exe-dispatch.js +1 -1
- package/dist/bin/exe-doctor.js +38 -16
- package/dist/bin/exe-export-behaviors.js +43 -21
- package/dist/bin/exe-forget.js +39 -17
- package/dist/bin/exe-gateway.js +159 -50
- package/dist/bin/exe-heartbeat.js +53 -31
- package/dist/bin/exe-kill.js +40 -18
- package/dist/bin/exe-launch-agent.js +109 -36
- package/dist/bin/exe-link.js +196 -87
- package/dist/bin/exe-new-employee.js +56 -17
- package/dist/bin/exe-pending-messages.js +47 -25
- package/dist/bin/exe-pending-notifications.js +38 -16
- package/dist/bin/exe-pending-reviews.js +51 -29
- package/dist/bin/exe-rename.js +21 -7
- package/dist/bin/exe-review.js +41 -13
- package/dist/bin/exe-search.js +57 -21
- package/dist/bin/exe-session-cleanup.js +67 -31
- package/dist/bin/exe-settings.js +63 -2
- package/dist/bin/exe-status.js +35 -13
- package/dist/bin/exe-team.js +35 -13
- package/dist/bin/git-sweep.js +45 -17
- package/dist/bin/graph-backfill.js +38 -16
- package/dist/bin/graph-export.js +38 -16
- package/dist/bin/install.js +10 -1
- package/dist/bin/scan-tasks.js +47 -19
- package/dist/bin/setup.js +444 -259
- package/dist/bin/shard-migrate.js +38 -16
- package/dist/bin/wiki-sync.js +40 -17
- package/dist/gateway/index.js +113 -48
- package/dist/hooks/bug-report-worker.js +66 -39
- package/dist/hooks/commit-complete.js +45 -17
- package/dist/hooks/error-recall.js +60 -20
- package/dist/hooks/exe-heartbeat-hook.js +3 -2
- package/dist/hooks/ingest-worker.js +174 -45
- package/dist/hooks/ingest.js +74 -28
- package/dist/hooks/instructions-loaded.js +46 -17
- package/dist/hooks/notification.js +44 -15
- package/dist/hooks/post-compact.js +44 -15
- package/dist/hooks/pre-compact.js +42 -14
- package/dist/hooks/pre-tool-use.js +59 -22
- package/dist/hooks/prompt-ingest-worker.js +75 -14
- package/dist/hooks/prompt-submit.js +75 -32
- package/dist/hooks/response-ingest-worker.js +76 -15
- package/dist/hooks/session-end.js +54 -22
- package/dist/hooks/session-start.js +57 -20
- package/dist/hooks/stop.js +44 -15
- package/dist/hooks/subagent-stop.js +44 -15
- package/dist/hooks/summary-worker.js +339 -106
- package/dist/index.js +94 -23
- package/dist/lib/cloud-sync.js +191 -80
- package/dist/lib/config.js +4 -1
- package/dist/lib/consolidation.js +5 -4
- package/dist/lib/database.js +1 -0
- package/dist/lib/device-registry.js +2 -1
- package/dist/lib/embedder.js +9 -1
- package/dist/lib/employee-templates.js +5 -0
- package/dist/lib/employees.js +11 -6
- package/dist/lib/exe-daemon-client.js +6 -1
- package/dist/lib/exe-daemon.js +95 -36
- package/dist/lib/hybrid-search.js +57 -21
- package/dist/lib/identity-templates.js +16 -7
- package/dist/lib/identity.js +1 -1
- package/dist/lib/keychain.js +2 -1
- package/dist/lib/license.js +56 -6
- package/dist/lib/messaging.js +1 -1
- package/dist/lib/reminders.js +2 -2
- package/dist/lib/schedules.js +38 -16
- package/dist/lib/skill-learning.js +1 -1
- package/dist/lib/store.js +44 -16
- package/dist/lib/tasks.js +1 -1
- package/dist/lib/tmux-routing.js +1 -1
- package/dist/mcp/server.js +280 -155
- package/dist/mcp/tools/complete-reminder.js +1 -1
- package/dist/mcp/tools/create-task.js +14 -6
- package/dist/mcp/tools/deactivate-behavior.js +2 -2
- package/dist/mcp/tools/list-reminders.js +1 -1
- package/dist/mcp/tools/list-tasks.js +36 -28
- package/dist/mcp/tools/send-message.js +1 -1
- package/dist/mcp/tools/update-task.js +1 -1
- package/dist/runtime/index.js +42 -8
- package/dist/tui/App.js +220 -99
- package/package.json +5 -3
|
@@ -211,6 +211,7 @@ async function ensureSchema() {
|
|
|
211
211
|
const client = getRawClient();
|
|
212
212
|
await client.execute("PRAGMA journal_mode = WAL");
|
|
213
213
|
await client.execute("PRAGMA busy_timeout = 30000");
|
|
214
|
+
await client.execute("PRAGMA wal_autocheckpoint = 1000");
|
|
214
215
|
try {
|
|
215
216
|
await client.execute("PRAGMA libsql_vector_search_ef = 128");
|
|
216
217
|
} catch {
|
|
@@ -1034,15 +1035,15 @@ __export(config_exports, {
|
|
|
1034
1035
|
migrateConfig: () => migrateConfig,
|
|
1035
1036
|
saveConfig: () => saveConfig
|
|
1036
1037
|
});
|
|
1037
|
-
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
1038
|
+
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2, chmod as chmod2 } from "fs/promises";
|
|
1038
1039
|
import { readFileSync as readFileSync2, existsSync as existsSync3, renameSync } from "fs";
|
|
1039
1040
|
import path4 from "path";
|
|
1040
|
-
import
|
|
1041
|
+
import os2 from "os";
|
|
1041
1042
|
function resolveDataDir() {
|
|
1042
1043
|
if (process.env.EXE_OS_DIR) return process.env.EXE_OS_DIR;
|
|
1043
1044
|
if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
|
|
1044
|
-
const newDir = path4.join(
|
|
1045
|
-
const legacyDir = path4.join(
|
|
1045
|
+
const newDir = path4.join(os2.homedir(), ".exe-os");
|
|
1046
|
+
const legacyDir = path4.join(os2.homedir(), ".exe-mem");
|
|
1046
1047
|
if (!existsSync3(newDir) && existsSync3(legacyDir)) {
|
|
1047
1048
|
try {
|
|
1048
1049
|
renameSync(legacyDir, newDir);
|
|
@@ -1129,7 +1130,7 @@ async function loadConfig() {
|
|
|
1129
1130
|
normalizeAutoUpdate(migratedCfg);
|
|
1130
1131
|
const config = { ...DEFAULT_CONFIG, dbPath: path4.join(dir, "memories.db"), ...migratedCfg };
|
|
1131
1132
|
if (config.dbPath.startsWith("~")) {
|
|
1132
|
-
config.dbPath = config.dbPath.replace(/^~/,
|
|
1133
|
+
config.dbPath = config.dbPath.replace(/^~/, os2.homedir());
|
|
1133
1134
|
}
|
|
1134
1135
|
return config;
|
|
1135
1136
|
} catch {
|
|
@@ -1160,6 +1161,9 @@ async function saveConfig(config) {
|
|
|
1160
1161
|
await mkdir2(dir, { recursive: true });
|
|
1161
1162
|
const configPath = path4.join(dir, "config.json");
|
|
1162
1163
|
await writeFile2(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
1164
|
+
if (config.cloud?.apiKey) {
|
|
1165
|
+
await chmod2(configPath, 384);
|
|
1166
|
+
}
|
|
1163
1167
|
}
|
|
1164
1168
|
async function loadConfigFrom(configPath) {
|
|
1165
1169
|
const raw = await readFile2(configPath, "utf-8");
|
|
@@ -1275,7 +1279,7 @@ __export(shard_manager_exports, {
|
|
|
1275
1279
|
shardExists: () => shardExists
|
|
1276
1280
|
});
|
|
1277
1281
|
import path5 from "path";
|
|
1278
|
-
import { existsSync as existsSync4, mkdirSync } from "fs";
|
|
1282
|
+
import { existsSync as existsSync4, mkdirSync, readdirSync as readdirSync2 } from "fs";
|
|
1279
1283
|
import { createClient as createClient2 } from "@libsql/client";
|
|
1280
1284
|
function initShardManager(encryptionKey) {
|
|
1281
1285
|
_encryptionKey = encryptionKey;
|
|
@@ -1314,8 +1318,7 @@ function shardExists(projectName) {
|
|
|
1314
1318
|
}
|
|
1315
1319
|
function listShards() {
|
|
1316
1320
|
if (!existsSync4(SHARDS_DIR)) return [];
|
|
1317
|
-
|
|
1318
|
-
return readdirSync4(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
|
|
1321
|
+
return readdirSync2(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
|
|
1319
1322
|
}
|
|
1320
1323
|
async function ensureShardSchema(client) {
|
|
1321
1324
|
await client.execute("PRAGMA journal_mode = WAL");
|
|
@@ -1506,10 +1509,10 @@ var init_shard_manager = __esm({
|
|
|
1506
1509
|
// src/lib/notifications.ts
|
|
1507
1510
|
import crypto3 from "crypto";
|
|
1508
1511
|
import path6 from "path";
|
|
1509
|
-
import
|
|
1512
|
+
import os3 from "os";
|
|
1510
1513
|
import {
|
|
1511
1514
|
readFileSync as readFileSync3,
|
|
1512
|
-
readdirSync as
|
|
1515
|
+
readdirSync as readdirSync3,
|
|
1513
1516
|
unlinkSync,
|
|
1514
1517
|
existsSync as existsSync5,
|
|
1515
1518
|
rmdirSync
|
|
@@ -1592,6 +1595,14 @@ import { readFileSync as readFileSync5, writeFileSync, existsSync as existsSync7
|
|
|
1592
1595
|
import { randomUUID } from "crypto";
|
|
1593
1596
|
import path8 from "path";
|
|
1594
1597
|
import { jwtVerify, importSPKI } from "jose";
|
|
1598
|
+
async function fetchRetry(url, init) {
|
|
1599
|
+
try {
|
|
1600
|
+
return await fetch(url, init);
|
|
1601
|
+
} catch {
|
|
1602
|
+
await new Promise((r) => setTimeout(r, RETRY_DELAY_MS));
|
|
1603
|
+
return fetch(url, { ...init, signal: AbortSignal.timeout(1e4) });
|
|
1604
|
+
}
|
|
1605
|
+
}
|
|
1595
1606
|
function loadDeviceId() {
|
|
1596
1607
|
const deviceJsonPath = path8.join(EXE_AI_DIR, "device.json");
|
|
1597
1608
|
try {
|
|
@@ -1662,7 +1673,7 @@ function cacheResponse(token) {
|
|
|
1662
1673
|
async function validateLicense(apiKey, deviceId) {
|
|
1663
1674
|
const did = deviceId ?? loadDeviceId();
|
|
1664
1675
|
try {
|
|
1665
|
-
const res = await
|
|
1676
|
+
const res = await fetchRetry(`${API_BASE}/auth/activate`, {
|
|
1666
1677
|
method: "POST",
|
|
1667
1678
|
headers: { "Content-Type": "application/json" },
|
|
1668
1679
|
body: JSON.stringify({ apiKey, deviceId: did }),
|
|
@@ -1697,18 +1708,27 @@ async function validateLicense(apiKey, deviceId) {
|
|
|
1697
1708
|
} catch {
|
|
1698
1709
|
const cached = await getCachedLicense();
|
|
1699
1710
|
if (cached) return cached;
|
|
1700
|
-
return FREE_LICENSE;
|
|
1711
|
+
return { ...FREE_LICENSE, valid: false, error: "offline" };
|
|
1712
|
+
}
|
|
1713
|
+
}
|
|
1714
|
+
function getCacheAgeMs() {
|
|
1715
|
+
try {
|
|
1716
|
+
const { statSync: statSync3 } = __require("fs");
|
|
1717
|
+
const s = statSync3(CACHE_PATH);
|
|
1718
|
+
return Date.now() - s.mtimeMs;
|
|
1719
|
+
} catch {
|
|
1720
|
+
return Infinity;
|
|
1701
1721
|
}
|
|
1702
1722
|
}
|
|
1703
1723
|
async function checkLicense() {
|
|
1704
1724
|
const key = loadLicense();
|
|
1705
1725
|
if (!key) return FREE_LICENSE;
|
|
1706
1726
|
const cached = await getCachedLicense();
|
|
1707
|
-
if (cached) return cached;
|
|
1727
|
+
if (cached && getCacheAgeMs() < CACHE_MAX_AGE_MS) return cached;
|
|
1708
1728
|
const deviceId = loadDeviceId();
|
|
1709
1729
|
return validateLicense(key, deviceId);
|
|
1710
1730
|
}
|
|
1711
|
-
var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH, API_BASE, LICENSE_PUBLIC_KEY_PEM, LICENSE_JWT_ALG, PLAN_LIMITS, FREE_LICENSE;
|
|
1731
|
+
var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH, API_BASE, RETRY_DELAY_MS, LICENSE_PUBLIC_KEY_PEM, LICENSE_JWT_ALG, PLAN_LIMITS, FREE_LICENSE, CACHE_MAX_AGE_MS;
|
|
1712
1732
|
var init_license = __esm({
|
|
1713
1733
|
"src/lib/license.ts"() {
|
|
1714
1734
|
"use strict";
|
|
@@ -1717,6 +1737,7 @@ var init_license = __esm({
|
|
|
1717
1737
|
CACHE_PATH = path8.join(EXE_AI_DIR, "license-cache.json");
|
|
1718
1738
|
DEVICE_ID_PATH = path8.join(EXE_AI_DIR, "device-id");
|
|
1719
1739
|
API_BASE = "https://askexe.com/cloud";
|
|
1740
|
+
RETRY_DELAY_MS = 500;
|
|
1720
1741
|
LICENSE_PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----
|
|
1721
1742
|
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeHztAMOpR/ZMh+rWuOASjEZ54CGY
|
|
1722
1743
|
4uj+UqeKCcvtgNHKmOK278HJaJcANe9xAeji8AFYu27q3WtzCi04pHudow==
|
|
@@ -1738,6 +1759,7 @@ MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeHztAMOpR/ZMh+rWuOASjEZ54CGY
|
|
|
1738
1759
|
employeeLimit: 1,
|
|
1739
1760
|
memoryLimit: 5e3
|
|
1740
1761
|
};
|
|
1762
|
+
CACHE_MAX_AGE_MS = 36e5;
|
|
1741
1763
|
}
|
|
1742
1764
|
});
|
|
1743
1765
|
|
|
@@ -1847,6 +1869,10 @@ import path10 from "path";
|
|
|
1847
1869
|
import { fileURLToPath } from "url";
|
|
1848
1870
|
function handleData(chunk) {
|
|
1849
1871
|
_buffer += chunk.toString();
|
|
1872
|
+
if (_buffer.length > MAX_BUFFER) {
|
|
1873
|
+
_buffer = "";
|
|
1874
|
+
return;
|
|
1875
|
+
}
|
|
1850
1876
|
let newlineIdx;
|
|
1851
1877
|
while ((newlineIdx = _buffer.indexOf("\n")) !== -1) {
|
|
1852
1878
|
const line = _buffer.slice(0, newlineIdx).trim();
|
|
@@ -2154,7 +2180,7 @@ function disconnectClient() {
|
|
|
2154
2180
|
entry.resolve({ error: "Client disconnected" });
|
|
2155
2181
|
}
|
|
2156
2182
|
}
|
|
2157
|
-
var SOCKET_PATH, PID_PATH, SPAWN_LOCK_PATH, SPAWN_LOCK_STALE_MS, CONNECT_TIMEOUT_MS, REQUEST_TIMEOUT_MS, _socket, _connected, _buffer, _requestCount, HEALTH_CHECK_INTERVAL, _pending;
|
|
2183
|
+
var SOCKET_PATH, PID_PATH, SPAWN_LOCK_PATH, SPAWN_LOCK_STALE_MS, CONNECT_TIMEOUT_MS, REQUEST_TIMEOUT_MS, _socket, _connected, _buffer, _requestCount, HEALTH_CHECK_INTERVAL, _pending, MAX_BUFFER;
|
|
2158
2184
|
var init_exe_daemon_client = __esm({
|
|
2159
2185
|
"src/lib/exe-daemon-client.ts"() {
|
|
2160
2186
|
"use strict";
|
|
@@ -2171,6 +2197,7 @@ var init_exe_daemon_client = __esm({
|
|
|
2171
2197
|
_requestCount = 0;
|
|
2172
2198
|
HEALTH_CHECK_INTERVAL = 100;
|
|
2173
2199
|
_pending = /* @__PURE__ */ new Map();
|
|
2200
|
+
MAX_BUFFER = 1e7;
|
|
2174
2201
|
}
|
|
2175
2202
|
});
|
|
2176
2203
|
|
|
@@ -2212,8 +2239,8 @@ async function embedDirect(text) {
|
|
|
2212
2239
|
const llamaCpp = await import("node-llama-cpp");
|
|
2213
2240
|
const { MODELS_DIR: MODELS_DIR2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
2214
2241
|
const { existsSync: existsSync15 } = await import("fs");
|
|
2215
|
-
const
|
|
2216
|
-
const modelPath =
|
|
2242
|
+
const path20 = await import("path");
|
|
2243
|
+
const modelPath = path20.join(MODELS_DIR2, "jina-embeddings-v5-small-q4_k_m.gguf");
|
|
2217
2244
|
if (!existsSync15(modelPath)) {
|
|
2218
2245
|
throw new Error(`Embedding model not found at ${modelPath}. Run '/exe-setup' to download it.`);
|
|
2219
2246
|
}
|
|
@@ -2646,7 +2673,7 @@ var init_tasks_crud = __esm({
|
|
|
2646
2673
|
// src/lib/session-registry.ts
|
|
2647
2674
|
import { readFileSync as readFileSync9, writeFileSync as writeFileSync2, mkdirSync as mkdirSync3, existsSync as existsSync11 } from "fs";
|
|
2648
2675
|
import path12 from "path";
|
|
2649
|
-
import
|
|
2676
|
+
import os4 from "os";
|
|
2650
2677
|
function registerSession(entry) {
|
|
2651
2678
|
const dir = path12.dirname(REGISTRY_PATH);
|
|
2652
2679
|
if (!existsSync11(dir)) {
|
|
@@ -2673,7 +2700,7 @@ var REGISTRY_PATH;
|
|
|
2673
2700
|
var init_session_registry = __esm({
|
|
2674
2701
|
"src/lib/session-registry.ts"() {
|
|
2675
2702
|
"use strict";
|
|
2676
|
-
REGISTRY_PATH = path12.join(
|
|
2703
|
+
REGISTRY_PATH = path12.join(os4.homedir(), ".exe-os", "session-registry.json");
|
|
2677
2704
|
}
|
|
2678
2705
|
});
|
|
2679
2706
|
|
|
@@ -2872,7 +2899,7 @@ var init_provider_table = __esm({
|
|
|
2872
2899
|
// src/lib/intercom-queue.ts
|
|
2873
2900
|
import { readFileSync as readFileSync10, writeFileSync as writeFileSync3, renameSync as renameSync2, existsSync as existsSync12, mkdirSync as mkdirSync4 } from "fs";
|
|
2874
2901
|
import path13 from "path";
|
|
2875
|
-
import
|
|
2902
|
+
import os5 from "os";
|
|
2876
2903
|
function ensureDir() {
|
|
2877
2904
|
const dir = path13.dirname(QUEUE_PATH);
|
|
2878
2905
|
if (!existsSync12(dir)) mkdirSync4(dir, { recursive: true });
|
|
@@ -2912,9 +2939,9 @@ var QUEUE_PATH, TTL_MS, INTERCOM_LOG;
|
|
|
2912
2939
|
var init_intercom_queue = __esm({
|
|
2913
2940
|
"src/lib/intercom-queue.ts"() {
|
|
2914
2941
|
"use strict";
|
|
2915
|
-
QUEUE_PATH = path13.join(
|
|
2942
|
+
QUEUE_PATH = path13.join(os5.homedir(), ".exe-os", "intercom-queue.json");
|
|
2916
2943
|
TTL_MS = 60 * 60 * 1e3;
|
|
2917
|
-
INTERCOM_LOG = path13.join(
|
|
2944
|
+
INTERCOM_LOG = path13.join(os5.homedir(), ".exe-os", "intercom.log");
|
|
2918
2945
|
}
|
|
2919
2946
|
});
|
|
2920
2947
|
|
|
@@ -2922,7 +2949,7 @@ var init_intercom_queue = __esm({
|
|
|
2922
2949
|
import { execFileSync as execFileSync2, execSync as execSync7 } from "child_process";
|
|
2923
2950
|
import { readFileSync as readFileSync11, writeFileSync as writeFileSync4, mkdirSync as mkdirSync5, existsSync as existsSync13, appendFileSync } from "fs";
|
|
2924
2951
|
import path14 from "path";
|
|
2925
|
-
import
|
|
2952
|
+
import os6 from "os";
|
|
2926
2953
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
2927
2954
|
import { unlinkSync as unlinkSync3 } from "fs";
|
|
2928
2955
|
function spawnLockPath(sessionName) {
|
|
@@ -3227,7 +3254,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3227
3254
|
const transport = getTransport();
|
|
3228
3255
|
const sessionName = employeeSessionName(employeeName, exeSession, opts?.instance);
|
|
3229
3256
|
const instanceLabel = opts?.instance != null && opts.instance > 0 ? `${employeeName}${opts.instance}` : employeeName;
|
|
3230
|
-
const logDir = path14.join(
|
|
3257
|
+
const logDir = path14.join(os6.homedir(), ".exe-os", "session-logs");
|
|
3231
3258
|
const logFile = path14.join(logDir, `${instanceLabel}-${Date.now()}.log`);
|
|
3232
3259
|
if (!existsSync13(logDir)) {
|
|
3233
3260
|
mkdirSync5(logDir, { recursive: true });
|
|
@@ -3243,7 +3270,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3243
3270
|
} catch {
|
|
3244
3271
|
}
|
|
3245
3272
|
try {
|
|
3246
|
-
const claudeJsonPath = path14.join(
|
|
3273
|
+
const claudeJsonPath = path14.join(os6.homedir(), ".claude.json");
|
|
3247
3274
|
let claudeJson = {};
|
|
3248
3275
|
try {
|
|
3249
3276
|
claudeJson = JSON.parse(readFileSync11(claudeJsonPath, "utf8"));
|
|
@@ -3258,7 +3285,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3258
3285
|
} catch {
|
|
3259
3286
|
}
|
|
3260
3287
|
try {
|
|
3261
|
-
const settingsDir = path14.join(
|
|
3288
|
+
const settingsDir = path14.join(os6.homedir(), ".claude", "projects");
|
|
3262
3289
|
const normalizedKey = (opts?.cwd ?? projectDir).replace(/\//g, "-").replace(/^-/, "");
|
|
3263
3290
|
const projSettingsDir = path14.join(settingsDir, normalizedKey);
|
|
3264
3291
|
const settingsPath = path14.join(projSettingsDir, "settings.json");
|
|
@@ -3306,7 +3333,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3306
3333
|
let legacyFallbackWarned = false;
|
|
3307
3334
|
if (!useExeAgent && !useBinSymlink) {
|
|
3308
3335
|
const identityPath = path14.join(
|
|
3309
|
-
|
|
3336
|
+
os6.homedir(),
|
|
3310
3337
|
".exe-os",
|
|
3311
3338
|
"identity",
|
|
3312
3339
|
`${employeeName}.md`
|
|
@@ -3336,7 +3363,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3336
3363
|
}
|
|
3337
3364
|
let sessionContextFlag = "";
|
|
3338
3365
|
try {
|
|
3339
|
-
const ctxDir = path14.join(
|
|
3366
|
+
const ctxDir = path14.join(os6.homedir(), ".exe-os", "session-cache");
|
|
3340
3367
|
mkdirSync5(ctxDir, { recursive: true });
|
|
3341
3368
|
const ctxFile = path14.join(ctxDir, `session-context-${sessionName}.md`);
|
|
3342
3369
|
const ctxContent = [
|
|
@@ -3447,11 +3474,11 @@ var init_tmux_routing = __esm({
|
|
|
3447
3474
|
init_provider_table();
|
|
3448
3475
|
init_intercom_queue();
|
|
3449
3476
|
init_plan_limits();
|
|
3450
|
-
SPAWN_LOCK_DIR = path14.join(
|
|
3451
|
-
SESSION_CACHE = path14.join(
|
|
3477
|
+
SPAWN_LOCK_DIR = path14.join(os6.homedir(), ".exe-os", "spawn-locks");
|
|
3478
|
+
SESSION_CACHE = path14.join(os6.homedir(), ".exe-os", "session-cache");
|
|
3452
3479
|
BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
|
|
3453
3480
|
INTERCOM_DEBOUNCE_MS = 3e4;
|
|
3454
|
-
INTERCOM_LOG2 = path14.join(
|
|
3481
|
+
INTERCOM_LOG2 = path14.join(os6.homedir(), ".exe-os", "intercom.log");
|
|
3455
3482
|
DEBOUNCE_FILE = path14.join(SESSION_CACHE, "intercom-debounce.json");
|
|
3456
3483
|
DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
|
|
3457
3484
|
BUSY_PATTERN = /[✻✽✶✳·].*…|Running…/;
|
|
@@ -3460,7 +3487,7 @@ var init_tmux_routing = __esm({
|
|
|
3460
3487
|
|
|
3461
3488
|
// src/lib/tasks-review.ts
|
|
3462
3489
|
import path15 from "path";
|
|
3463
|
-
import { existsSync as existsSync14, readdirSync as
|
|
3490
|
+
import { existsSync as existsSync14, readdirSync as readdirSync4, unlinkSync as unlinkSync4 } from "fs";
|
|
3464
3491
|
async function countPendingReviews() {
|
|
3465
3492
|
const client = getClient();
|
|
3466
3493
|
const result = await client.execute({
|
|
@@ -3582,7 +3609,7 @@ async function cleanupReviewFile(row, taskFile, _baseDir) {
|
|
|
3582
3609
|
try {
|
|
3583
3610
|
const cacheDir = path15.join(EXE_AI_DIR, "session-cache");
|
|
3584
3611
|
if (existsSync14(cacheDir)) {
|
|
3585
|
-
for (const f of
|
|
3612
|
+
for (const f of readdirSync4(cacheDir)) {
|
|
3586
3613
|
if (f.startsWith("review-notified-")) {
|
|
3587
3614
|
unlinkSync4(path15.join(cacheDir, f));
|
|
3588
3615
|
}
|
|
@@ -4279,11 +4306,69 @@ var init_tasks = __esm({
|
|
|
4279
4306
|
}
|
|
4280
4307
|
});
|
|
4281
4308
|
|
|
4309
|
+
// src/lib/worker-gate.ts
|
|
4310
|
+
var worker_gate_exports = {};
|
|
4311
|
+
__export(worker_gate_exports, {
|
|
4312
|
+
MAX_CONCURRENT_WORKERS: () => MAX_CONCURRENT_WORKERS,
|
|
4313
|
+
cleanupWorkerPid: () => cleanupWorkerPid,
|
|
4314
|
+
registerWorkerPid: () => registerWorkerPid,
|
|
4315
|
+
tryAcquireWorkerSlot: () => tryAcquireWorkerSlot
|
|
4316
|
+
});
|
|
4317
|
+
import { readdirSync as readdirSync5, writeFileSync as writeFileSync6, unlinkSync as unlinkSync6, mkdirSync as mkdirSync7 } from "fs";
|
|
4318
|
+
import path18 from "path";
|
|
4319
|
+
function tryAcquireWorkerSlot() {
|
|
4320
|
+
try {
|
|
4321
|
+
mkdirSync7(WORKER_PID_DIR, { recursive: true });
|
|
4322
|
+
const files = readdirSync5(WORKER_PID_DIR);
|
|
4323
|
+
let alive = 0;
|
|
4324
|
+
for (const f of files) {
|
|
4325
|
+
if (!f.endsWith(".pid")) continue;
|
|
4326
|
+
const dashIdx = f.lastIndexOf("-");
|
|
4327
|
+
const pid = parseInt(f.slice(dashIdx + 1).replace(".pid", ""), 10);
|
|
4328
|
+
if (isNaN(pid)) continue;
|
|
4329
|
+
try {
|
|
4330
|
+
process.kill(pid, 0);
|
|
4331
|
+
alive++;
|
|
4332
|
+
} catch {
|
|
4333
|
+
try {
|
|
4334
|
+
unlinkSync6(path18.join(WORKER_PID_DIR, f));
|
|
4335
|
+
} catch {
|
|
4336
|
+
}
|
|
4337
|
+
}
|
|
4338
|
+
}
|
|
4339
|
+
return alive < MAX_CONCURRENT_WORKERS;
|
|
4340
|
+
} catch {
|
|
4341
|
+
return true;
|
|
4342
|
+
}
|
|
4343
|
+
}
|
|
4344
|
+
function registerWorkerPid(pid) {
|
|
4345
|
+
try {
|
|
4346
|
+
mkdirSync7(WORKER_PID_DIR, { recursive: true });
|
|
4347
|
+
writeFileSync6(path18.join(WORKER_PID_DIR, `worker-${pid}.pid`), String(pid));
|
|
4348
|
+
} catch {
|
|
4349
|
+
}
|
|
4350
|
+
}
|
|
4351
|
+
function cleanupWorkerPid() {
|
|
4352
|
+
try {
|
|
4353
|
+
unlinkSync6(path18.join(WORKER_PID_DIR, `worker-${process.pid}.pid`));
|
|
4354
|
+
} catch {
|
|
4355
|
+
}
|
|
4356
|
+
}
|
|
4357
|
+
var WORKER_PID_DIR, MAX_CONCURRENT_WORKERS;
|
|
4358
|
+
var init_worker_gate = __esm({
|
|
4359
|
+
"src/lib/worker-gate.ts"() {
|
|
4360
|
+
"use strict";
|
|
4361
|
+
init_config();
|
|
4362
|
+
WORKER_PID_DIR = path18.join(EXE_AI_DIR, "worker-pids");
|
|
4363
|
+
MAX_CONCURRENT_WORKERS = 3;
|
|
4364
|
+
}
|
|
4365
|
+
});
|
|
4366
|
+
|
|
4282
4367
|
// src/adapters/claude/hooks/ingest-worker.ts
|
|
4283
4368
|
import crypto7 from "crypto";
|
|
4284
4369
|
import { execSync as execSync8 } from "child_process";
|
|
4285
|
-
import { mkdirSync as
|
|
4286
|
-
import
|
|
4370
|
+
import { mkdirSync as mkdirSync8, writeFileSync as writeFileSync7 } from "fs";
|
|
4371
|
+
import path19 from "path";
|
|
4287
4372
|
|
|
4288
4373
|
// src/lib/error-detector.ts
|
|
4289
4374
|
init_mcp_prefix();
|
|
@@ -4397,11 +4482,12 @@ init_database();
|
|
|
4397
4482
|
import { readFile, writeFile, unlink, mkdir, chmod } from "fs/promises";
|
|
4398
4483
|
import { existsSync as existsSync2 } from "fs";
|
|
4399
4484
|
import path3 from "path";
|
|
4485
|
+
import os from "os";
|
|
4400
4486
|
import crypto2 from "crypto";
|
|
4401
4487
|
var SERVICE = "exe-mem";
|
|
4402
4488
|
var ACCOUNT = "master-key";
|
|
4403
4489
|
function getKeyDir() {
|
|
4404
|
-
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path3.join(
|
|
4490
|
+
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path3.join(os.homedir(), ".exe-os");
|
|
4405
4491
|
}
|
|
4406
4492
|
function getKeyPath() {
|
|
4407
4493
|
return path3.join(getKeyDir(), "master.key");
|
|
@@ -4438,6 +4524,30 @@ async function getMasterKey() {
|
|
|
4438
4524
|
|
|
4439
4525
|
// src/lib/store.ts
|
|
4440
4526
|
init_config();
|
|
4527
|
+
var INIT_MAX_RETRIES = 3;
|
|
4528
|
+
var INIT_RETRY_DELAY_MS = 1e3;
|
|
4529
|
+
function isBusyError2(err) {
|
|
4530
|
+
if (err instanceof Error) {
|
|
4531
|
+
const msg = err.message.toLowerCase();
|
|
4532
|
+
return msg.includes("sqlite_busy") || msg.includes("database is locked");
|
|
4533
|
+
}
|
|
4534
|
+
return false;
|
|
4535
|
+
}
|
|
4536
|
+
async function retryOnBusy2(fn, label) {
|
|
4537
|
+
for (let attempt = 0; attempt <= INIT_MAX_RETRIES; attempt++) {
|
|
4538
|
+
try {
|
|
4539
|
+
return await fn();
|
|
4540
|
+
} catch (err) {
|
|
4541
|
+
if (!isBusyError2(err) || attempt === INIT_MAX_RETRIES) throw err;
|
|
4542
|
+
process.stderr.write(
|
|
4543
|
+
`[store] SQLITE_BUSY during ${label}, retry ${attempt + 1}/${INIT_MAX_RETRIES}
|
|
4544
|
+
`
|
|
4545
|
+
);
|
|
4546
|
+
await new Promise((r) => setTimeout(r, INIT_RETRY_DELAY_MS * (attempt + 1)));
|
|
4547
|
+
}
|
|
4548
|
+
}
|
|
4549
|
+
throw new Error("unreachable");
|
|
4550
|
+
}
|
|
4441
4551
|
var _pendingRecords = [];
|
|
4442
4552
|
var _batchSize = 20;
|
|
4443
4553
|
var _flushIntervalMs = 1e4;
|
|
@@ -4472,14 +4582,17 @@ async function initStore(options) {
|
|
|
4472
4582
|
dbPath,
|
|
4473
4583
|
encryptionKey: hexKey
|
|
4474
4584
|
});
|
|
4475
|
-
await ensureSchema();
|
|
4585
|
+
await retryOnBusy2(() => ensureSchema(), "ensureSchema");
|
|
4476
4586
|
try {
|
|
4477
4587
|
const { initShardManager: initShardManager2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
|
|
4478
4588
|
initShardManager2(hexKey);
|
|
4479
4589
|
} catch {
|
|
4480
4590
|
}
|
|
4481
4591
|
const client = getClient();
|
|
4482
|
-
const vResult = await
|
|
4592
|
+
const vResult = await retryOnBusy2(
|
|
4593
|
+
() => client.execute("SELECT MAX(version) as max_v FROM memories"),
|
|
4594
|
+
"version-query"
|
|
4595
|
+
);
|
|
4483
4596
|
_nextVersion = (Number(vResult.rows[0]?.max_v) || 0) + 1;
|
|
4484
4597
|
}
|
|
4485
4598
|
function classifyTier(record) {
|
|
@@ -4522,6 +4635,12 @@ async function writeMemory(record) {
|
|
|
4522
4635
|
supersedes_id: record.supersedes_id ?? null
|
|
4523
4636
|
};
|
|
4524
4637
|
_pendingRecords.push(dbRow);
|
|
4638
|
+
const MAX_PENDING = 1e3;
|
|
4639
|
+
if (_pendingRecords.length > MAX_PENDING) {
|
|
4640
|
+
const dropped = _pendingRecords.length - MAX_PENDING;
|
|
4641
|
+
_pendingRecords = _pendingRecords.slice(-MAX_PENDING);
|
|
4642
|
+
console.warn(`[store] Dropped ${dropped} oldest pending records (overflow)`);
|
|
4643
|
+
}
|
|
4525
4644
|
if (_flushTimer === null) {
|
|
4526
4645
|
_flushTimer = setInterval(() => {
|
|
4527
4646
|
void flushBatch();
|
|
@@ -4772,9 +4891,9 @@ function extractBash(input2, response) {
|
|
|
4772
4891
|
}
|
|
4773
4892
|
function extractGrep(input2, response) {
|
|
4774
4893
|
const pattern = String(input2.pattern ?? "");
|
|
4775
|
-
const
|
|
4894
|
+
const path20 = input2.path ? String(input2.path) : "";
|
|
4776
4895
|
const output = String(response.text ?? response.content ?? JSON.stringify(response).slice(0, MAX_OUTPUT));
|
|
4777
|
-
return `Searched for "${pattern}"${
|
|
4896
|
+
return `Searched for "${pattern}"${path20 ? ` in ${path20}` : ""}
|
|
4778
4897
|
${output.slice(0, MAX_OUTPUT)}`;
|
|
4779
4898
|
}
|
|
4780
4899
|
function extractGlob(input2, response) {
|
|
@@ -4909,7 +5028,7 @@ process.stdin.on("end", async () => {
|
|
|
4909
5028
|
try {
|
|
4910
5029
|
const { EXE_AI_DIR: exeDir } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
4911
5030
|
const agentId2 = process.env.AGENT_ID;
|
|
4912
|
-
const cachePath =
|
|
5031
|
+
const cachePath = path19.join(exeDir, "session-cache", `current-task-${agentId2}.json`);
|
|
4913
5032
|
const { readFileSync: rf } = await import("fs");
|
|
4914
5033
|
const cached = JSON.parse(rf(cachePath, "utf8"));
|
|
4915
5034
|
taskId = cached.taskId ?? null;
|
|
@@ -4934,8 +5053,8 @@ process.stdin.on("end", async () => {
|
|
|
4934
5053
|
if (needsBackfill) {
|
|
4935
5054
|
try {
|
|
4936
5055
|
const { EXE_AI_DIR: exeDir } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
4937
|
-
const flagPath =
|
|
4938
|
-
|
|
5056
|
+
const flagPath = path19.join(exeDir, "session-cache", "needs-backfill");
|
|
5057
|
+
writeFileSync7(flagPath, "1");
|
|
4939
5058
|
} catch (err) {
|
|
4940
5059
|
process.stderr.write(`[ingest-worker] backfill flag write failed: ${err instanceof Error ? err.message : String(err)}
|
|
4941
5060
|
`);
|
|
@@ -5047,8 +5166,8 @@ process.stdin.on("end", async () => {
|
|
|
5047
5166
|
}
|
|
5048
5167
|
const cwd = data.cwd ?? process.cwd();
|
|
5049
5168
|
try {
|
|
5050
|
-
|
|
5051
|
-
|
|
5169
|
+
mkdirSync8(path19.join(cwd, "exe/output"), { recursive: true });
|
|
5170
|
+
mkdirSync8(path19.join(cwd, "exe/research"), { recursive: true });
|
|
5052
5171
|
const { ensureGitignoreExe: ensureGitignoreExe2 } = await Promise.resolve().then(() => (init_tasks(), tasks_exports));
|
|
5053
5172
|
await ensureGitignoreExe2(cwd);
|
|
5054
5173
|
} catch (err) {
|
|
@@ -5058,9 +5177,19 @@ process.stdin.on("end", async () => {
|
|
|
5058
5177
|
}
|
|
5059
5178
|
}
|
|
5060
5179
|
}
|
|
5180
|
+
try {
|
|
5181
|
+
const { getRawClient: getRawClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
5182
|
+
await getRawClient2().execute("PRAGMA wal_checkpoint(PASSIVE)");
|
|
5183
|
+
} catch {
|
|
5184
|
+
}
|
|
5061
5185
|
} catch (err) {
|
|
5062
5186
|
process.stderr.write(`[ingest-worker] FATAL: ${err instanceof Error ? err.message : String(err)}
|
|
5063
5187
|
`);
|
|
5188
|
+
}
|
|
5189
|
+
try {
|
|
5190
|
+
const { cleanupWorkerPid: cleanupWorkerPid2 } = await Promise.resolve().then(() => (init_worker_gate(), worker_gate_exports));
|
|
5191
|
+
cleanupWorkerPid2();
|
|
5192
|
+
} catch {
|
|
5064
5193
|
}
|
|
5065
5194
|
process.exit(0);
|
|
5066
5195
|
});
|