@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
package/dist/bin/exe-gateway.js
CHANGED
|
@@ -62,7 +62,8 @@ async function gqlRequest(query, variables) {
|
|
|
62
62
|
"Content-Type": "application/json",
|
|
63
63
|
Authorization: `Bearer ${config.apiToken}`
|
|
64
64
|
},
|
|
65
|
-
body: JSON.stringify({ query, variables })
|
|
65
|
+
body: JSON.stringify({ query, variables }),
|
|
66
|
+
signal: AbortSignal.timeout(3e4)
|
|
66
67
|
});
|
|
67
68
|
if (!res.ok) {
|
|
68
69
|
throw new Error(`CRM GraphQL request failed: ${res.status} ${res.statusText}`);
|
|
@@ -369,6 +370,7 @@ async function ensureSchema() {
|
|
|
369
370
|
const client = getRawClient();
|
|
370
371
|
await client.execute("PRAGMA journal_mode = WAL");
|
|
371
372
|
await client.execute("PRAGMA busy_timeout = 30000");
|
|
373
|
+
await client.execute("PRAGMA wal_autocheckpoint = 1000");
|
|
372
374
|
try {
|
|
373
375
|
await client.execute("PRAGMA libsql_vector_search_ef = 128");
|
|
374
376
|
} catch {
|
|
@@ -1201,7 +1203,7 @@ __export(config_exports, {
|
|
|
1201
1203
|
migrateConfig: () => migrateConfig,
|
|
1202
1204
|
saveConfig: () => saveConfig
|
|
1203
1205
|
});
|
|
1204
|
-
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
1206
|
+
import { readFile, writeFile, mkdir, chmod } from "fs/promises";
|
|
1205
1207
|
import { readFileSync, existsSync, renameSync } from "fs";
|
|
1206
1208
|
import path from "path";
|
|
1207
1209
|
import os from "os";
|
|
@@ -1327,6 +1329,9 @@ async function saveConfig(config2) {
|
|
|
1327
1329
|
await mkdir(dir, { recursive: true });
|
|
1328
1330
|
const configPath = path.join(dir, "config.json");
|
|
1329
1331
|
await writeFile(configPath, JSON.stringify(config2, null, 2) + "\n");
|
|
1332
|
+
if (config2.cloud?.apiKey) {
|
|
1333
|
+
await chmod(configPath, 384);
|
|
1334
|
+
}
|
|
1330
1335
|
}
|
|
1331
1336
|
async function loadConfigFrom(configPath) {
|
|
1332
1337
|
const raw = await readFile(configPath, "utf-8");
|
|
@@ -1437,6 +1442,10 @@ import path2 from "path";
|
|
|
1437
1442
|
import { fileURLToPath } from "url";
|
|
1438
1443
|
function handleData(chunk) {
|
|
1439
1444
|
_buffer += chunk.toString();
|
|
1445
|
+
if (_buffer.length > MAX_BUFFER) {
|
|
1446
|
+
_buffer = "";
|
|
1447
|
+
return;
|
|
1448
|
+
}
|
|
1440
1449
|
let newlineIdx;
|
|
1441
1450
|
while ((newlineIdx = _buffer.indexOf("\n")) !== -1) {
|
|
1442
1451
|
const line = _buffer.slice(0, newlineIdx).trim();
|
|
@@ -1744,7 +1753,7 @@ function disconnectClient() {
|
|
|
1744
1753
|
entry.resolve({ error: "Client disconnected" });
|
|
1745
1754
|
}
|
|
1746
1755
|
}
|
|
1747
|
-
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;
|
|
1756
|
+
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;
|
|
1748
1757
|
var init_exe_daemon_client = __esm({
|
|
1749
1758
|
"src/lib/exe-daemon-client.ts"() {
|
|
1750
1759
|
"use strict";
|
|
@@ -1761,6 +1770,7 @@ var init_exe_daemon_client = __esm({
|
|
|
1761
1770
|
_requestCount = 0;
|
|
1762
1771
|
HEALTH_CHECK_INTERVAL = 100;
|
|
1763
1772
|
_pending = /* @__PURE__ */ new Map();
|
|
1773
|
+
MAX_BUFFER = 1e7;
|
|
1764
1774
|
}
|
|
1765
1775
|
});
|
|
1766
1776
|
|
|
@@ -1833,12 +1843,13 @@ var init_embedder = __esm({
|
|
|
1833
1843
|
});
|
|
1834
1844
|
|
|
1835
1845
|
// src/lib/keychain.ts
|
|
1836
|
-
import { readFile as readFile2, writeFile as writeFile2, unlink, mkdir as mkdir2, chmod } from "fs/promises";
|
|
1846
|
+
import { readFile as readFile2, writeFile as writeFile2, unlink, mkdir as mkdir2, chmod as chmod2 } from "fs/promises";
|
|
1837
1847
|
import { existsSync as existsSync3 } from "fs";
|
|
1838
1848
|
import path3 from "path";
|
|
1849
|
+
import os2 from "os";
|
|
1839
1850
|
import crypto from "crypto";
|
|
1840
1851
|
function getKeyDir() {
|
|
1841
|
-
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path3.join(
|
|
1852
|
+
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path3.join(os2.homedir(), ".exe-os");
|
|
1842
1853
|
}
|
|
1843
1854
|
function getKeyPath() {
|
|
1844
1855
|
return path3.join(getKeyDir(), "master.key");
|
|
@@ -1895,7 +1906,7 @@ __export(shard_manager_exports, {
|
|
|
1895
1906
|
shardExists: () => shardExists
|
|
1896
1907
|
});
|
|
1897
1908
|
import path4 from "path";
|
|
1898
|
-
import { existsSync as existsSync4, mkdirSync } from "fs";
|
|
1909
|
+
import { existsSync as existsSync4, mkdirSync, readdirSync } from "fs";
|
|
1899
1910
|
import { createClient as createClient2 } from "@libsql/client";
|
|
1900
1911
|
function initShardManager(encryptionKey) {
|
|
1901
1912
|
_encryptionKey = encryptionKey;
|
|
@@ -1934,8 +1945,7 @@ function shardExists(projectName) {
|
|
|
1934
1945
|
}
|
|
1935
1946
|
function listShards() {
|
|
1936
1947
|
if (!existsSync4(SHARDS_DIR)) return [];
|
|
1937
|
-
|
|
1938
|
-
return readdirSync3(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
|
|
1948
|
+
return readdirSync(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
|
|
1939
1949
|
}
|
|
1940
1950
|
async function ensureShardSchema(client) {
|
|
1941
1951
|
await client.execute("PRAGMA journal_mode = WAL");
|
|
@@ -2140,6 +2150,28 @@ __export(store_exports, {
|
|
|
2140
2150
|
vectorToBlob: () => vectorToBlob,
|
|
2141
2151
|
writeMemory: () => writeMemory
|
|
2142
2152
|
});
|
|
2153
|
+
function isBusyError2(err) {
|
|
2154
|
+
if (err instanceof Error) {
|
|
2155
|
+
const msg = err.message.toLowerCase();
|
|
2156
|
+
return msg.includes("sqlite_busy") || msg.includes("database is locked");
|
|
2157
|
+
}
|
|
2158
|
+
return false;
|
|
2159
|
+
}
|
|
2160
|
+
async function retryOnBusy2(fn, label) {
|
|
2161
|
+
for (let attempt = 0; attempt <= INIT_MAX_RETRIES; attempt++) {
|
|
2162
|
+
try {
|
|
2163
|
+
return await fn();
|
|
2164
|
+
} catch (err) {
|
|
2165
|
+
if (!isBusyError2(err) || attempt === INIT_MAX_RETRIES) throw err;
|
|
2166
|
+
process.stderr.write(
|
|
2167
|
+
`[store] SQLITE_BUSY during ${label}, retry ${attempt + 1}/${INIT_MAX_RETRIES}
|
|
2168
|
+
`
|
|
2169
|
+
);
|
|
2170
|
+
await new Promise((r) => setTimeout(r, INIT_RETRY_DELAY_MS * (attempt + 1)));
|
|
2171
|
+
}
|
|
2172
|
+
}
|
|
2173
|
+
throw new Error("unreachable");
|
|
2174
|
+
}
|
|
2143
2175
|
async function initStore(options) {
|
|
2144
2176
|
if (_flushTimer !== null) {
|
|
2145
2177
|
clearInterval(_flushTimer);
|
|
@@ -2168,14 +2200,17 @@ async function initStore(options) {
|
|
|
2168
2200
|
dbPath,
|
|
2169
2201
|
encryptionKey: hexKey
|
|
2170
2202
|
});
|
|
2171
|
-
await ensureSchema();
|
|
2203
|
+
await retryOnBusy2(() => ensureSchema(), "ensureSchema");
|
|
2172
2204
|
try {
|
|
2173
2205
|
const { initShardManager: initShardManager2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
|
|
2174
2206
|
initShardManager2(hexKey);
|
|
2175
2207
|
} catch {
|
|
2176
2208
|
}
|
|
2177
2209
|
const client = getClient();
|
|
2178
|
-
const vResult = await
|
|
2210
|
+
const vResult = await retryOnBusy2(
|
|
2211
|
+
() => client.execute("SELECT MAX(version) as max_v FROM memories"),
|
|
2212
|
+
"version-query"
|
|
2213
|
+
);
|
|
2179
2214
|
_nextVersion = (Number(vResult.rows[0]?.max_v) || 0) + 1;
|
|
2180
2215
|
}
|
|
2181
2216
|
function classifyTier(record) {
|
|
@@ -2218,6 +2253,12 @@ async function writeMemory(record) {
|
|
|
2218
2253
|
supersedes_id: record.supersedes_id ?? null
|
|
2219
2254
|
};
|
|
2220
2255
|
_pendingRecords.push(dbRow);
|
|
2256
|
+
const MAX_PENDING = 1e3;
|
|
2257
|
+
if (_pendingRecords.length > MAX_PENDING) {
|
|
2258
|
+
const dropped = _pendingRecords.length - MAX_PENDING;
|
|
2259
|
+
_pendingRecords = _pendingRecords.slice(-MAX_PENDING);
|
|
2260
|
+
console.warn(`[store] Dropped ${dropped} oldest pending records (overflow)`);
|
|
2261
|
+
}
|
|
2221
2262
|
if (_flushTimer === null) {
|
|
2222
2263
|
_flushTimer = setInterval(() => {
|
|
2223
2264
|
void flushBatch();
|
|
@@ -2549,7 +2590,7 @@ async function getMemoryCardinality(agentId) {
|
|
|
2549
2590
|
return 0;
|
|
2550
2591
|
}
|
|
2551
2592
|
}
|
|
2552
|
-
var _pendingRecords, _batchSize, _flushIntervalMs, _flushTimer, _flushing, _nextVersion;
|
|
2593
|
+
var INIT_MAX_RETRIES, INIT_RETRY_DELAY_MS, _pendingRecords, _batchSize, _flushIntervalMs, _flushTimer, _flushing, _nextVersion;
|
|
2553
2594
|
var init_store = __esm({
|
|
2554
2595
|
"src/lib/store.ts"() {
|
|
2555
2596
|
"use strict";
|
|
@@ -2557,6 +2598,8 @@ var init_store = __esm({
|
|
|
2557
2598
|
init_database();
|
|
2558
2599
|
init_keychain();
|
|
2559
2600
|
init_config();
|
|
2601
|
+
INIT_MAX_RETRIES = 3;
|
|
2602
|
+
INIT_RETRY_DELAY_MS = 1e3;
|
|
2560
2603
|
_pendingRecords = [];
|
|
2561
2604
|
_batchSize = 20;
|
|
2562
2605
|
_flushIntervalMs = 1e4;
|
|
@@ -2584,12 +2627,30 @@ async function wikiFetch(config2, path20, method = "GET", body) {
|
|
|
2584
2627
|
const controller = new AbortController();
|
|
2585
2628
|
const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS2);
|
|
2586
2629
|
try {
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2630
|
+
let response;
|
|
2631
|
+
try {
|
|
2632
|
+
response = await fetch(url, {
|
|
2633
|
+
method,
|
|
2634
|
+
headers,
|
|
2635
|
+
body: body ? JSON.stringify(body) : void 0,
|
|
2636
|
+
signal: controller.signal
|
|
2637
|
+
});
|
|
2638
|
+
} catch {
|
|
2639
|
+
clearTimeout(timeout);
|
|
2640
|
+
const retryController = new AbortController();
|
|
2641
|
+
const retryTimeout = setTimeout(() => retryController.abort(), REQUEST_TIMEOUT_MS2);
|
|
2642
|
+
try {
|
|
2643
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
2644
|
+
response = await fetch(url, {
|
|
2645
|
+
method,
|
|
2646
|
+
headers,
|
|
2647
|
+
body: body ? JSON.stringify(body) : void 0,
|
|
2648
|
+
signal: retryController.signal
|
|
2649
|
+
});
|
|
2650
|
+
} finally {
|
|
2651
|
+
clearTimeout(retryTimeout);
|
|
2652
|
+
}
|
|
2653
|
+
}
|
|
2593
2654
|
if (!response.ok) {
|
|
2594
2655
|
throw new Error(`Wiki API ${method} ${path20}: ${response.status} ${response.statusText}`);
|
|
2595
2656
|
}
|
|
@@ -2703,12 +2764,22 @@ __export(license_exports, {
|
|
|
2703
2764
|
loadLicense: () => loadLicense,
|
|
2704
2765
|
mirrorLicenseKey: () => mirrorLicenseKey,
|
|
2705
2766
|
saveLicense: () => saveLicense,
|
|
2767
|
+
startLicenseRevalidation: () => startLicenseRevalidation,
|
|
2768
|
+
stopLicenseRevalidation: () => stopLicenseRevalidation,
|
|
2706
2769
|
validateLicense: () => validateLicense
|
|
2707
2770
|
});
|
|
2708
2771
|
import { readFileSync as readFileSync3, writeFileSync, existsSync as existsSync5, mkdirSync as mkdirSync2 } from "fs";
|
|
2709
2772
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
2710
2773
|
import path5 from "path";
|
|
2711
2774
|
import { jwtVerify, importSPKI } from "jose";
|
|
2775
|
+
async function fetchRetry(url, init) {
|
|
2776
|
+
try {
|
|
2777
|
+
return await fetch(url, init);
|
|
2778
|
+
} catch {
|
|
2779
|
+
await new Promise((r) => setTimeout(r, RETRY_DELAY_MS));
|
|
2780
|
+
return fetch(url, { ...init, signal: AbortSignal.timeout(1e4) });
|
|
2781
|
+
}
|
|
2782
|
+
}
|
|
2712
2783
|
function loadDeviceId() {
|
|
2713
2784
|
const deviceJsonPath = path5.join(EXE_AI_DIR, "device.json");
|
|
2714
2785
|
try {
|
|
@@ -2740,7 +2811,7 @@ function loadLicense() {
|
|
|
2740
2811
|
}
|
|
2741
2812
|
function saveLicense(apiKey) {
|
|
2742
2813
|
mkdirSync2(EXE_AI_DIR, { recursive: true });
|
|
2743
|
-
writeFileSync(LICENSE_PATH, apiKey.trim(), "utf8");
|
|
2814
|
+
writeFileSync(LICENSE_PATH, apiKey.trim(), { encoding: "utf8", mode: 384 });
|
|
2744
2815
|
}
|
|
2745
2816
|
async function verifyLicenseJwt(token) {
|
|
2746
2817
|
try {
|
|
@@ -2792,7 +2863,7 @@ function cacheResponse(token) {
|
|
|
2792
2863
|
async function validateLicense(apiKey, deviceId) {
|
|
2793
2864
|
const did = deviceId ?? loadDeviceId();
|
|
2794
2865
|
try {
|
|
2795
|
-
const res = await
|
|
2866
|
+
const res = await fetchRetry(`${API_BASE}/auth/activate`, {
|
|
2796
2867
|
method: "POST",
|
|
2797
2868
|
headers: { "Content-Type": "application/json" },
|
|
2798
2869
|
body: JSON.stringify({ apiKey, deviceId: did }),
|
|
@@ -2827,14 +2898,23 @@ async function validateLicense(apiKey, deviceId) {
|
|
|
2827
2898
|
} catch {
|
|
2828
2899
|
const cached = await getCachedLicense();
|
|
2829
2900
|
if (cached) return cached;
|
|
2830
|
-
return FREE_LICENSE;
|
|
2901
|
+
return { ...FREE_LICENSE, valid: false, error: "offline" };
|
|
2902
|
+
}
|
|
2903
|
+
}
|
|
2904
|
+
function getCacheAgeMs() {
|
|
2905
|
+
try {
|
|
2906
|
+
const { statSync: statSync2 } = __require("fs");
|
|
2907
|
+
const s = statSync2(CACHE_PATH);
|
|
2908
|
+
return Date.now() - s.mtimeMs;
|
|
2909
|
+
} catch {
|
|
2910
|
+
return Infinity;
|
|
2831
2911
|
}
|
|
2832
2912
|
}
|
|
2833
2913
|
async function checkLicense() {
|
|
2834
2914
|
const key = loadLicense();
|
|
2835
2915
|
if (!key) return FREE_LICENSE;
|
|
2836
2916
|
const cached = await getCachedLicense();
|
|
2837
|
-
if (cached) return cached;
|
|
2917
|
+
if (cached && getCacheAgeMs() < CACHE_MAX_AGE_MS) return cached;
|
|
2838
2918
|
const deviceId = loadDeviceId();
|
|
2839
2919
|
return validateLicense(key, deviceId);
|
|
2840
2920
|
}
|
|
@@ -2874,7 +2954,7 @@ async function assertVpsLicense(opts) {
|
|
|
2874
2954
|
let explicitRejection = false;
|
|
2875
2955
|
let transientFailure = false;
|
|
2876
2956
|
try {
|
|
2877
|
-
const res = await
|
|
2957
|
+
const res = await fetchRetry(`${API_BASE}/auth/activate`, {
|
|
2878
2958
|
method: "POST",
|
|
2879
2959
|
headers: { "Content-Type": "application/json" },
|
|
2880
2960
|
body: JSON.stringify({ apiKey, deviceId }),
|
|
@@ -2955,7 +3035,28 @@ async function assertVpsLicense(opts) {
|
|
|
2955
3035
|
`License validation unreachable for more than ${graceDays} days. Restore network connectivity to https://askexe.com/cloud and retry. This VPS image refuses to boot after the offline grace window.`
|
|
2956
3036
|
);
|
|
2957
3037
|
}
|
|
2958
|
-
|
|
3038
|
+
function startLicenseRevalidation(intervalMs = 36e5) {
|
|
3039
|
+
if (_revalTimer) return;
|
|
3040
|
+
_revalTimer = setInterval(async () => {
|
|
3041
|
+
try {
|
|
3042
|
+
const license = await checkLicense();
|
|
3043
|
+
if (!license.valid) {
|
|
3044
|
+
process.stderr.write("[exe-os] License expired or invalid \u2014 features may be restricted\n");
|
|
3045
|
+
}
|
|
3046
|
+
} catch {
|
|
3047
|
+
}
|
|
3048
|
+
}, intervalMs);
|
|
3049
|
+
if (_revalTimer && typeof _revalTimer === "object" && "unref" in _revalTimer) {
|
|
3050
|
+
_revalTimer.unref();
|
|
3051
|
+
}
|
|
3052
|
+
}
|
|
3053
|
+
function stopLicenseRevalidation() {
|
|
3054
|
+
if (_revalTimer) {
|
|
3055
|
+
clearInterval(_revalTimer);
|
|
3056
|
+
_revalTimer = null;
|
|
3057
|
+
}
|
|
3058
|
+
}
|
|
3059
|
+
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, _revalTimer;
|
|
2959
3060
|
var init_license = __esm({
|
|
2960
3061
|
"src/lib/license.ts"() {
|
|
2961
3062
|
"use strict";
|
|
@@ -2964,6 +3065,7 @@ var init_license = __esm({
|
|
|
2964
3065
|
CACHE_PATH = path5.join(EXE_AI_DIR, "license-cache.json");
|
|
2965
3066
|
DEVICE_ID_PATH = path5.join(EXE_AI_DIR, "device-id");
|
|
2966
3067
|
API_BASE = "https://askexe.com/cloud";
|
|
3068
|
+
RETRY_DELAY_MS = 500;
|
|
2967
3069
|
LICENSE_PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----
|
|
2968
3070
|
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeHztAMOpR/ZMh+rWuOASjEZ54CGY
|
|
2969
3071
|
4uj+UqeKCcvtgNHKmOK278HJaJcANe9xAeji8AFYu27q3WtzCi04pHudow==
|
|
@@ -2985,6 +3087,8 @@ MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeHztAMOpR/ZMh+rWuOASjEZ54CGY
|
|
|
2985
3087
|
employeeLimit: 1,
|
|
2986
3088
|
memoryLimit: 5e3
|
|
2987
3089
|
};
|
|
3090
|
+
CACHE_MAX_AGE_MS = 36e5;
|
|
3091
|
+
_revalTimer = null;
|
|
2988
3092
|
}
|
|
2989
3093
|
});
|
|
2990
3094
|
|
|
@@ -3813,6 +3917,7 @@ __export(imessage_exports, {
|
|
|
3813
3917
|
});
|
|
3814
3918
|
import { execFile } from "child_process";
|
|
3815
3919
|
import { promisify } from "util";
|
|
3920
|
+
import os3 from "os";
|
|
3816
3921
|
import path6 from "path";
|
|
3817
3922
|
var execFileAsync, POLL_INTERVAL_MS, MESSAGES_DB_PATH, IMessageAdapter;
|
|
3818
3923
|
var init_imessage = __esm({
|
|
@@ -3821,7 +3926,7 @@ var init_imessage = __esm({
|
|
|
3821
3926
|
execFileAsync = promisify(execFile);
|
|
3822
3927
|
POLL_INTERVAL_MS = 5e3;
|
|
3823
3928
|
MESSAGES_DB_PATH = path6.join(
|
|
3824
|
-
process.env.HOME ??
|
|
3929
|
+
process.env.HOME ?? os3.homedir(),
|
|
3825
3930
|
"Library/Messages/chat.db"
|
|
3826
3931
|
);
|
|
3827
3932
|
IMessageAdapter = class {
|
|
@@ -4287,7 +4392,7 @@ var init_whatsapp_accounts = __esm({
|
|
|
4287
4392
|
// src/lib/session-registry.ts
|
|
4288
4393
|
import { readFileSync as readFileSync5, writeFileSync as writeFileSync2, mkdirSync as mkdirSync4, existsSync as existsSync6 } from "fs";
|
|
4289
4394
|
import path7 from "path";
|
|
4290
|
-
import
|
|
4395
|
+
import os4 from "os";
|
|
4291
4396
|
function registerSession(entry) {
|
|
4292
4397
|
const dir = path7.dirname(REGISTRY_PATH);
|
|
4293
4398
|
if (!existsSync6(dir)) {
|
|
@@ -4314,7 +4419,7 @@ var REGISTRY_PATH;
|
|
|
4314
4419
|
var init_session_registry = __esm({
|
|
4315
4420
|
"src/lib/session-registry.ts"() {
|
|
4316
4421
|
"use strict";
|
|
4317
|
-
REGISTRY_PATH = path7.join(
|
|
4422
|
+
REGISTRY_PATH = path7.join(os4.homedir(), ".exe-os", "session-registry.json");
|
|
4318
4423
|
}
|
|
4319
4424
|
});
|
|
4320
4425
|
|
|
@@ -4536,7 +4641,7 @@ var init_provider_table = __esm({
|
|
|
4536
4641
|
// src/lib/intercom-queue.ts
|
|
4537
4642
|
import { readFileSync as readFileSync6, writeFileSync as writeFileSync3, renameSync as renameSync2, existsSync as existsSync7, mkdirSync as mkdirSync5 } from "fs";
|
|
4538
4643
|
import path8 from "path";
|
|
4539
|
-
import
|
|
4644
|
+
import os5 from "os";
|
|
4540
4645
|
function ensureDir() {
|
|
4541
4646
|
const dir = path8.dirname(QUEUE_PATH);
|
|
4542
4647
|
if (!existsSync7(dir)) mkdirSync5(dir, { recursive: true });
|
|
@@ -4576,9 +4681,9 @@ var QUEUE_PATH, TTL_MS, INTERCOM_LOG;
|
|
|
4576
4681
|
var init_intercom_queue = __esm({
|
|
4577
4682
|
"src/lib/intercom-queue.ts"() {
|
|
4578
4683
|
"use strict";
|
|
4579
|
-
QUEUE_PATH = path8.join(
|
|
4684
|
+
QUEUE_PATH = path8.join(os5.homedir(), ".exe-os", "intercom-queue.json");
|
|
4580
4685
|
TTL_MS = 60 * 60 * 1e3;
|
|
4581
|
-
INTERCOM_LOG = path8.join(
|
|
4686
|
+
INTERCOM_LOG = path8.join(os5.homedir(), ".exe-os", "intercom.log");
|
|
4582
4687
|
}
|
|
4583
4688
|
});
|
|
4584
4689
|
|
|
@@ -4696,7 +4801,7 @@ var init_plan_limits = __esm({
|
|
|
4696
4801
|
import { execFileSync as execFileSync2, execSync as execSync4 } from "child_process";
|
|
4697
4802
|
import { readFileSync as readFileSync9, writeFileSync as writeFileSync4, mkdirSync as mkdirSync6, existsSync as existsSync10, appendFileSync } from "fs";
|
|
4698
4803
|
import path11 from "path";
|
|
4699
|
-
import
|
|
4804
|
+
import os6 from "os";
|
|
4700
4805
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
4701
4806
|
import { unlinkSync as unlinkSync2 } from "fs";
|
|
4702
4807
|
function spawnLockPath(sessionName) {
|
|
@@ -5001,7 +5106,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
5001
5106
|
const transport = getTransport();
|
|
5002
5107
|
const sessionName = employeeSessionName(employeeName, exeSession, opts?.instance);
|
|
5003
5108
|
const instanceLabel = opts?.instance != null && opts.instance > 0 ? `${employeeName}${opts.instance}` : employeeName;
|
|
5004
|
-
const logDir = path11.join(
|
|
5109
|
+
const logDir = path11.join(os6.homedir(), ".exe-os", "session-logs");
|
|
5005
5110
|
const logFile = path11.join(logDir, `${instanceLabel}-${Date.now()}.log`);
|
|
5006
5111
|
if (!existsSync10(logDir)) {
|
|
5007
5112
|
mkdirSync6(logDir, { recursive: true });
|
|
@@ -5017,7 +5122,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
5017
5122
|
} catch {
|
|
5018
5123
|
}
|
|
5019
5124
|
try {
|
|
5020
|
-
const claudeJsonPath = path11.join(
|
|
5125
|
+
const claudeJsonPath = path11.join(os6.homedir(), ".claude.json");
|
|
5021
5126
|
let claudeJson = {};
|
|
5022
5127
|
try {
|
|
5023
5128
|
claudeJson = JSON.parse(readFileSync9(claudeJsonPath, "utf8"));
|
|
@@ -5032,7 +5137,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
5032
5137
|
} catch {
|
|
5033
5138
|
}
|
|
5034
5139
|
try {
|
|
5035
|
-
const settingsDir = path11.join(
|
|
5140
|
+
const settingsDir = path11.join(os6.homedir(), ".claude", "projects");
|
|
5036
5141
|
const normalizedKey = (opts?.cwd ?? projectDir).replace(/\//g, "-").replace(/^-/, "");
|
|
5037
5142
|
const projSettingsDir = path11.join(settingsDir, normalizedKey);
|
|
5038
5143
|
const settingsPath = path11.join(projSettingsDir, "settings.json");
|
|
@@ -5080,7 +5185,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
5080
5185
|
let legacyFallbackWarned = false;
|
|
5081
5186
|
if (!useExeAgent && !useBinSymlink) {
|
|
5082
5187
|
const identityPath = path11.join(
|
|
5083
|
-
|
|
5188
|
+
os6.homedir(),
|
|
5084
5189
|
".exe-os",
|
|
5085
5190
|
"identity",
|
|
5086
5191
|
`${employeeName}.md`
|
|
@@ -5110,7 +5215,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
5110
5215
|
}
|
|
5111
5216
|
let sessionContextFlag = "";
|
|
5112
5217
|
try {
|
|
5113
|
-
const ctxDir = path11.join(
|
|
5218
|
+
const ctxDir = path11.join(os6.homedir(), ".exe-os", "session-cache");
|
|
5114
5219
|
mkdirSync6(ctxDir, { recursive: true });
|
|
5115
5220
|
const ctxFile = path11.join(ctxDir, `session-context-${sessionName}.md`);
|
|
5116
5221
|
const ctxContent = [
|
|
@@ -5221,11 +5326,11 @@ var init_tmux_routing = __esm({
|
|
|
5221
5326
|
init_provider_table();
|
|
5222
5327
|
init_intercom_queue();
|
|
5223
5328
|
init_plan_limits();
|
|
5224
|
-
SPAWN_LOCK_DIR = path11.join(
|
|
5225
|
-
SESSION_CACHE = path11.join(
|
|
5329
|
+
SPAWN_LOCK_DIR = path11.join(os6.homedir(), ".exe-os", "spawn-locks");
|
|
5330
|
+
SESSION_CACHE = path11.join(os6.homedir(), ".exe-os", "session-cache");
|
|
5226
5331
|
BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
|
|
5227
5332
|
INTERCOM_DEBOUNCE_MS = 3e4;
|
|
5228
|
-
INTERCOM_LOG2 = path11.join(
|
|
5333
|
+
INTERCOM_LOG2 = path11.join(os6.homedir(), ".exe-os", "intercom.log");
|
|
5229
5334
|
DEBOUNCE_FILE = path11.join(SESSION_CACHE, "intercom-debounce.json");
|
|
5230
5335
|
DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
|
|
5231
5336
|
BUSY_PATTERN = /[✻✽✶✳·].*…|Running…/;
|
|
@@ -5485,10 +5590,10 @@ var init_messaging = __esm({
|
|
|
5485
5590
|
// src/lib/notifications.ts
|
|
5486
5591
|
import crypto4 from "crypto";
|
|
5487
5592
|
import path12 from "path";
|
|
5488
|
-
import
|
|
5593
|
+
import os7 from "os";
|
|
5489
5594
|
import {
|
|
5490
5595
|
readFileSync as readFileSync10,
|
|
5491
|
-
readdirSync,
|
|
5596
|
+
readdirSync as readdirSync2,
|
|
5492
5597
|
unlinkSync as unlinkSync3,
|
|
5493
5598
|
existsSync as existsSync11,
|
|
5494
5599
|
rmdirSync
|
|
@@ -5937,7 +6042,7 @@ var init_tasks_crud = __esm({
|
|
|
5937
6042
|
|
|
5938
6043
|
// src/lib/tasks-review.ts
|
|
5939
6044
|
import path14 from "path";
|
|
5940
|
-
import { existsSync as existsSync13, readdirSync as
|
|
6045
|
+
import { existsSync as existsSync13, readdirSync as readdirSync3, unlinkSync as unlinkSync4 } from "fs";
|
|
5941
6046
|
async function countPendingReviews() {
|
|
5942
6047
|
const client = getClient();
|
|
5943
6048
|
const result = await client.execute({
|
|
@@ -6059,7 +6164,7 @@ async function cleanupReviewFile(row, taskFile, _baseDir) {
|
|
|
6059
6164
|
try {
|
|
6060
6165
|
const cacheDir = path14.join(EXE_AI_DIR, "session-cache");
|
|
6061
6166
|
if (existsSync13(cacheDir)) {
|
|
6062
|
-
for (const f of
|
|
6167
|
+
for (const f of readdirSync3(cacheDir)) {
|
|
6063
6168
|
if (f.startsWith("review-notified-")) {
|
|
6064
6169
|
unlinkSync4(path14.join(cacheDir, f));
|
|
6065
6170
|
}
|
|
@@ -6802,7 +6907,7 @@ var init_tasks = __esm({
|
|
|
6802
6907
|
import { readFileSync as readFileSync12, writeFileSync as writeFileSync6, existsSync as existsSync14, mkdirSync as mkdirSync8 } from "fs";
|
|
6803
6908
|
import { randomUUID as randomUUID7 } from "crypto";
|
|
6804
6909
|
import path18 from "path";
|
|
6805
|
-
import
|
|
6910
|
+
import os8 from "os";
|
|
6806
6911
|
function substituteTemplate(template, record) {
|
|
6807
6912
|
return template.replace(
|
|
6808
6913
|
/\{\{(\w+(?:\.\w+)*)\}\}/g,
|
|
@@ -6880,7 +6985,7 @@ async function executeSendWhatsapp(params) {
|
|
|
6880
6985
|
const message = params.message ?? params.text;
|
|
6881
6986
|
if (!to || !message)
|
|
6882
6987
|
throw new Error("send_whatsapp requires 'to' and 'message' params");
|
|
6883
|
-
const url = `https://graph.facebook.com
|
|
6988
|
+
const url = `https://graph.facebook.com/${GRAPH_API_VERSION}/${account.phoneNumberId}/messages`;
|
|
6884
6989
|
const res = await fetch(url, {
|
|
6885
6990
|
method: "POST",
|
|
6886
6991
|
headers: {
|
|
@@ -6892,7 +6997,8 @@ async function executeSendWhatsapp(params) {
|
|
|
6892
6997
|
to,
|
|
6893
6998
|
type: "text",
|
|
6894
6999
|
text: { body: message }
|
|
6895
|
-
})
|
|
7000
|
+
}),
|
|
7001
|
+
signal: AbortSignal.timeout(3e4)
|
|
6896
7002
|
});
|
|
6897
7003
|
if (!res.ok) {
|
|
6898
7004
|
const errBody = await res.text();
|
|
@@ -7087,11 +7193,12 @@ async function processCRMEvent(event, executor, triggersOverride) {
|
|
|
7087
7193
|
}
|
|
7088
7194
|
return logs;
|
|
7089
7195
|
}
|
|
7090
|
-
var TRIGGERS_PATH;
|
|
7196
|
+
var TRIGGERS_PATH, GRAPH_API_VERSION;
|
|
7091
7197
|
var init_trigger_engine = __esm({
|
|
7092
7198
|
"src/automation/trigger-engine.ts"() {
|
|
7093
7199
|
"use strict";
|
|
7094
|
-
TRIGGERS_PATH = path18.join(
|
|
7200
|
+
TRIGGERS_PATH = path18.join(os8.homedir(), ".exe-os", "triggers.json");
|
|
7201
|
+
GRAPH_API_VERSION = "v21.0";
|
|
7095
7202
|
}
|
|
7096
7203
|
});
|
|
7097
7204
|
|
|
@@ -7155,7 +7262,7 @@ var init_crm_webhook = __esm({
|
|
|
7155
7262
|
// src/bin/exe-gateway.ts
|
|
7156
7263
|
import { existsSync as existsSync15, readFileSync as readFileSync13 } from "fs";
|
|
7157
7264
|
import path19 from "path";
|
|
7158
|
-
import
|
|
7265
|
+
import os9 from "os";
|
|
7159
7266
|
|
|
7160
7267
|
// src/gateway/webhook-server.ts
|
|
7161
7268
|
import {
|
|
@@ -7979,7 +8086,7 @@ var BotRegistry = class {
|
|
|
7979
8086
|
};
|
|
7980
8087
|
|
|
7981
8088
|
// src/bin/exe-gateway.ts
|
|
7982
|
-
var CONFIG_DIR = path19.join(
|
|
8089
|
+
var CONFIG_DIR = path19.join(os9.homedir(), ".exe-os");
|
|
7983
8090
|
var CONFIG_PATH3 = path19.join(CONFIG_DIR, "gateway.json");
|
|
7984
8091
|
var DEFAULT_PORT = 3100;
|
|
7985
8092
|
function loadConfig2() {
|
|
@@ -8135,6 +8242,8 @@ async function main() {
|
|
|
8135
8242
|
console.log(`[exe-gateway] Ready on port ${port}`);
|
|
8136
8243
|
}
|
|
8137
8244
|
main().catch((err) => {
|
|
8138
|
-
|
|
8245
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
8246
|
+
console.error(`[exe-gateway] Fatal: ${msg}`);
|
|
8247
|
+
if (process.env.DEBUG) console.error(err);
|
|
8139
8248
|
process.exit(1);
|
|
8140
8249
|
});
|