@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
|
@@ -3,12 +3,6 @@ var __defProp = Object.defineProperty;
|
|
|
3
3
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
5
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
-
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
7
|
-
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
8
|
-
}) : x)(function(x) {
|
|
9
|
-
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
10
|
-
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
11
|
-
});
|
|
12
6
|
var __esm = (fn, res) => function __init() {
|
|
13
7
|
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
14
8
|
};
|
|
@@ -123,6 +117,7 @@ async function ensureSchema() {
|
|
|
123
117
|
const client = getRawClient();
|
|
124
118
|
await client.execute("PRAGMA journal_mode = WAL");
|
|
125
119
|
await client.execute("PRAGMA busy_timeout = 30000");
|
|
120
|
+
await client.execute("PRAGMA wal_autocheckpoint = 1000");
|
|
126
121
|
try {
|
|
127
122
|
await client.execute("PRAGMA libsql_vector_search_ef = 128");
|
|
128
123
|
} catch {
|
|
@@ -938,15 +933,15 @@ __export(config_exports, {
|
|
|
938
933
|
migrateConfig: () => migrateConfig,
|
|
939
934
|
saveConfig: () => saveConfig
|
|
940
935
|
});
|
|
941
|
-
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
936
|
+
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2, chmod as chmod2 } from "fs/promises";
|
|
942
937
|
import { readFileSync, existsSync as existsSync2, renameSync } from "fs";
|
|
943
938
|
import path2 from "path";
|
|
944
|
-
import
|
|
939
|
+
import os2 from "os";
|
|
945
940
|
function resolveDataDir() {
|
|
946
941
|
if (process.env.EXE_OS_DIR) return process.env.EXE_OS_DIR;
|
|
947
942
|
if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
|
|
948
|
-
const newDir = path2.join(
|
|
949
|
-
const legacyDir = path2.join(
|
|
943
|
+
const newDir = path2.join(os2.homedir(), ".exe-os");
|
|
944
|
+
const legacyDir = path2.join(os2.homedir(), ".exe-mem");
|
|
950
945
|
if (!existsSync2(newDir) && existsSync2(legacyDir)) {
|
|
951
946
|
try {
|
|
952
947
|
renameSync(legacyDir, newDir);
|
|
@@ -1033,7 +1028,7 @@ async function loadConfig() {
|
|
|
1033
1028
|
normalizeAutoUpdate(migratedCfg);
|
|
1034
1029
|
const config = { ...DEFAULT_CONFIG, dbPath: path2.join(dir, "memories.db"), ...migratedCfg };
|
|
1035
1030
|
if (config.dbPath.startsWith("~")) {
|
|
1036
|
-
config.dbPath = config.dbPath.replace(/^~/,
|
|
1031
|
+
config.dbPath = config.dbPath.replace(/^~/, os2.homedir());
|
|
1037
1032
|
}
|
|
1038
1033
|
return config;
|
|
1039
1034
|
} catch {
|
|
@@ -1064,6 +1059,9 @@ async function saveConfig(config) {
|
|
|
1064
1059
|
await mkdir2(dir, { recursive: true });
|
|
1065
1060
|
const configPath = path2.join(dir, "config.json");
|
|
1066
1061
|
await writeFile2(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
1062
|
+
if (config.cloud?.apiKey) {
|
|
1063
|
+
await chmod2(configPath, 384);
|
|
1064
|
+
}
|
|
1067
1065
|
}
|
|
1068
1066
|
async function loadConfigFrom(configPath) {
|
|
1069
1067
|
const raw = await readFile2(configPath, "utf-8");
|
|
@@ -1179,7 +1177,7 @@ __export(shard_manager_exports, {
|
|
|
1179
1177
|
shardExists: () => shardExists
|
|
1180
1178
|
});
|
|
1181
1179
|
import path3 from "path";
|
|
1182
|
-
import { existsSync as existsSync3, mkdirSync } from "fs";
|
|
1180
|
+
import { existsSync as existsSync3, mkdirSync, readdirSync } from "fs";
|
|
1183
1181
|
import { createClient as createClient2 } from "@libsql/client";
|
|
1184
1182
|
function initShardManager(encryptionKey) {
|
|
1185
1183
|
_encryptionKey = encryptionKey;
|
|
@@ -1218,8 +1216,7 @@ function shardExists(projectName) {
|
|
|
1218
1216
|
}
|
|
1219
1217
|
function listShards() {
|
|
1220
1218
|
if (!existsSync3(SHARDS_DIR)) return [];
|
|
1221
|
-
|
|
1222
|
-
return readdirSync3(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
|
|
1219
|
+
return readdirSync(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
|
|
1223
1220
|
}
|
|
1224
1221
|
async function ensureShardSchema(client) {
|
|
1225
1222
|
await client.execute("PRAGMA journal_mode = WAL");
|
|
@@ -1458,6 +1455,10 @@ import path5 from "path";
|
|
|
1458
1455
|
import { fileURLToPath } from "url";
|
|
1459
1456
|
function handleData(chunk) {
|
|
1460
1457
|
_buffer += chunk.toString();
|
|
1458
|
+
if (_buffer.length > MAX_BUFFER) {
|
|
1459
|
+
_buffer = "";
|
|
1460
|
+
return;
|
|
1461
|
+
}
|
|
1461
1462
|
let newlineIdx;
|
|
1462
1463
|
while ((newlineIdx = _buffer.indexOf("\n")) !== -1) {
|
|
1463
1464
|
const line = _buffer.slice(0, newlineIdx).trim();
|
|
@@ -1765,7 +1766,7 @@ function disconnectClient() {
|
|
|
1765
1766
|
entry.resolve({ error: "Client disconnected" });
|
|
1766
1767
|
}
|
|
1767
1768
|
}
|
|
1768
|
-
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;
|
|
1769
|
+
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;
|
|
1769
1770
|
var init_exe_daemon_client = __esm({
|
|
1770
1771
|
"src/lib/exe-daemon-client.ts"() {
|
|
1771
1772
|
"use strict";
|
|
@@ -1782,6 +1783,7 @@ var init_exe_daemon_client = __esm({
|
|
|
1782
1783
|
_requestCount = 0;
|
|
1783
1784
|
HEALTH_CHECK_INTERVAL = 100;
|
|
1784
1785
|
_pending = /* @__PURE__ */ new Map();
|
|
1786
|
+
MAX_BUFFER = 1e7;
|
|
1785
1787
|
}
|
|
1786
1788
|
});
|
|
1787
1789
|
|
|
@@ -1884,10 +1886,10 @@ var init_employees = __esm({
|
|
|
1884
1886
|
// src/lib/notifications.ts
|
|
1885
1887
|
import crypto2 from "crypto";
|
|
1886
1888
|
import path7 from "path";
|
|
1887
|
-
import
|
|
1889
|
+
import os3 from "os";
|
|
1888
1890
|
import {
|
|
1889
1891
|
readFileSync as readFileSync4,
|
|
1890
|
-
readdirSync,
|
|
1892
|
+
readdirSync as readdirSync2,
|
|
1891
1893
|
unlinkSync as unlinkSync2,
|
|
1892
1894
|
existsSync as existsSync6,
|
|
1893
1895
|
rmdirSync
|
|
@@ -2136,12 +2138,12 @@ var init_tasks_crud = __esm({
|
|
|
2136
2138
|
|
|
2137
2139
|
// src/lib/session-registry.ts
|
|
2138
2140
|
import path9 from "path";
|
|
2139
|
-
import
|
|
2141
|
+
import os4 from "os";
|
|
2140
2142
|
var REGISTRY_PATH;
|
|
2141
2143
|
var init_session_registry = __esm({
|
|
2142
2144
|
"src/lib/session-registry.ts"() {
|
|
2143
2145
|
"use strict";
|
|
2144
|
-
REGISTRY_PATH = path9.join(
|
|
2146
|
+
REGISTRY_PATH = path9.join(os4.homedir(), ".exe-os", "session-registry.json");
|
|
2145
2147
|
}
|
|
2146
2148
|
});
|
|
2147
2149
|
|
|
@@ -2319,7 +2321,7 @@ var init_provider_table = __esm({
|
|
|
2319
2321
|
// src/lib/intercom-queue.ts
|
|
2320
2322
|
import { readFileSync as readFileSync6, writeFileSync, renameSync as renameSync2, existsSync as existsSync8, mkdirSync as mkdirSync2 } from "fs";
|
|
2321
2323
|
import path10 from "path";
|
|
2322
|
-
import
|
|
2324
|
+
import os5 from "os";
|
|
2323
2325
|
function ensureDir() {
|
|
2324
2326
|
const dir = path10.dirname(QUEUE_PATH);
|
|
2325
2327
|
if (!existsSync8(dir)) mkdirSync2(dir, { recursive: true });
|
|
@@ -2359,9 +2361,9 @@ var QUEUE_PATH, TTL_MS, INTERCOM_LOG;
|
|
|
2359
2361
|
var init_intercom_queue = __esm({
|
|
2360
2362
|
"src/lib/intercom-queue.ts"() {
|
|
2361
2363
|
"use strict";
|
|
2362
|
-
QUEUE_PATH = path10.join(
|
|
2364
|
+
QUEUE_PATH = path10.join(os5.homedir(), ".exe-os", "intercom-queue.json");
|
|
2363
2365
|
TTL_MS = 60 * 60 * 1e3;
|
|
2364
|
-
INTERCOM_LOG = path10.join(
|
|
2366
|
+
INTERCOM_LOG = path10.join(os5.homedir(), ".exe-os", "intercom.log");
|
|
2365
2367
|
}
|
|
2366
2368
|
});
|
|
2367
2369
|
|
|
@@ -2399,7 +2401,7 @@ var init_plan_limits = __esm({
|
|
|
2399
2401
|
// src/lib/tmux-routing.ts
|
|
2400
2402
|
import { readFileSync as readFileSync9, writeFileSync as writeFileSync3, mkdirSync as mkdirSync4, existsSync as existsSync11, appendFileSync } from "fs";
|
|
2401
2403
|
import path13 from "path";
|
|
2402
|
-
import
|
|
2404
|
+
import os6 from "os";
|
|
2403
2405
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
2404
2406
|
function getParentExe(sessionKey) {
|
|
2405
2407
|
try {
|
|
@@ -2522,10 +2524,10 @@ var init_tmux_routing = __esm({
|
|
|
2522
2524
|
init_provider_table();
|
|
2523
2525
|
init_intercom_queue();
|
|
2524
2526
|
init_plan_limits();
|
|
2525
|
-
SPAWN_LOCK_DIR = path13.join(
|
|
2526
|
-
SESSION_CACHE = path13.join(
|
|
2527
|
+
SPAWN_LOCK_DIR = path13.join(os6.homedir(), ".exe-os", "spawn-locks");
|
|
2528
|
+
SESSION_CACHE = path13.join(os6.homedir(), ".exe-os", "session-cache");
|
|
2527
2529
|
INTERCOM_DEBOUNCE_MS = 3e4;
|
|
2528
|
-
INTERCOM_LOG2 = path13.join(
|
|
2530
|
+
INTERCOM_LOG2 = path13.join(os6.homedir(), ".exe-os", "intercom.log");
|
|
2529
2531
|
DEBOUNCE_FILE = path13.join(SESSION_CACHE, "intercom-debounce.json");
|
|
2530
2532
|
DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
|
|
2531
2533
|
BUSY_PATTERN = /[✻✽✶✳·].*…|Running…/;
|
|
@@ -2543,7 +2545,7 @@ __export(tasks_review_exports, {
|
|
|
2543
2545
|
listPendingReviews: () => listPendingReviews
|
|
2544
2546
|
});
|
|
2545
2547
|
import path14 from "path";
|
|
2546
|
-
import { existsSync as existsSync12, readdirSync as
|
|
2548
|
+
import { existsSync as existsSync12, readdirSync as readdirSync3, unlinkSync as unlinkSync3 } from "fs";
|
|
2547
2549
|
async function countPendingReviews() {
|
|
2548
2550
|
const client = getClient();
|
|
2549
2551
|
const result = await client.execute({
|
|
@@ -2755,7 +2757,7 @@ async function cleanupReviewFile(row, taskFile, _baseDir) {
|
|
|
2755
2757
|
try {
|
|
2756
2758
|
const cacheDir = path14.join(EXE_AI_DIR, "session-cache");
|
|
2757
2759
|
if (existsSync12(cacheDir)) {
|
|
2758
|
-
for (const f of
|
|
2760
|
+
for (const f of readdirSync3(cacheDir)) {
|
|
2759
2761
|
if (f.startsWith("review-notified-")) {
|
|
2760
2762
|
unlinkSync3(path14.join(cacheDir, f));
|
|
2761
2763
|
}
|
|
@@ -3000,11 +3002,12 @@ init_database();
|
|
|
3000
3002
|
import { readFile, writeFile, unlink, mkdir, chmod } from "fs/promises";
|
|
3001
3003
|
import { existsSync } from "fs";
|
|
3002
3004
|
import path from "path";
|
|
3005
|
+
import os from "os";
|
|
3003
3006
|
import crypto from "crypto";
|
|
3004
3007
|
var SERVICE = "exe-mem";
|
|
3005
3008
|
var ACCOUNT = "master-key";
|
|
3006
3009
|
function getKeyDir() {
|
|
3007
|
-
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path.join(
|
|
3010
|
+
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path.join(os.homedir(), ".exe-os");
|
|
3008
3011
|
}
|
|
3009
3012
|
function getKeyPath() {
|
|
3010
3013
|
return path.join(getKeyDir(), "master.key");
|
|
@@ -3041,6 +3044,30 @@ async function getMasterKey() {
|
|
|
3041
3044
|
|
|
3042
3045
|
// src/lib/store.ts
|
|
3043
3046
|
init_config();
|
|
3047
|
+
var INIT_MAX_RETRIES = 3;
|
|
3048
|
+
var INIT_RETRY_DELAY_MS = 1e3;
|
|
3049
|
+
function isBusyError2(err) {
|
|
3050
|
+
if (err instanceof Error) {
|
|
3051
|
+
const msg = err.message.toLowerCase();
|
|
3052
|
+
return msg.includes("sqlite_busy") || msg.includes("database is locked");
|
|
3053
|
+
}
|
|
3054
|
+
return false;
|
|
3055
|
+
}
|
|
3056
|
+
async function retryOnBusy2(fn, label) {
|
|
3057
|
+
for (let attempt = 0; attempt <= INIT_MAX_RETRIES; attempt++) {
|
|
3058
|
+
try {
|
|
3059
|
+
return await fn();
|
|
3060
|
+
} catch (err) {
|
|
3061
|
+
if (!isBusyError2(err) || attempt === INIT_MAX_RETRIES) throw err;
|
|
3062
|
+
process.stderr.write(
|
|
3063
|
+
`[store] SQLITE_BUSY during ${label}, retry ${attempt + 1}/${INIT_MAX_RETRIES}
|
|
3064
|
+
`
|
|
3065
|
+
);
|
|
3066
|
+
await new Promise((r) => setTimeout(r, INIT_RETRY_DELAY_MS * (attempt + 1)));
|
|
3067
|
+
}
|
|
3068
|
+
}
|
|
3069
|
+
throw new Error("unreachable");
|
|
3070
|
+
}
|
|
3044
3071
|
var _pendingRecords = [];
|
|
3045
3072
|
var _batchSize = 20;
|
|
3046
3073
|
var _flushIntervalMs = 1e4;
|
|
@@ -3075,14 +3102,17 @@ async function initStore(options) {
|
|
|
3075
3102
|
dbPath,
|
|
3076
3103
|
encryptionKey: hexKey
|
|
3077
3104
|
});
|
|
3078
|
-
await ensureSchema();
|
|
3105
|
+
await retryOnBusy2(() => ensureSchema(), "ensureSchema");
|
|
3079
3106
|
try {
|
|
3080
3107
|
const { initShardManager: initShardManager2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
|
|
3081
3108
|
initShardManager2(hexKey);
|
|
3082
3109
|
} catch {
|
|
3083
3110
|
}
|
|
3084
3111
|
const client = getClient();
|
|
3085
|
-
const vResult = await
|
|
3112
|
+
const vResult = await retryOnBusy2(
|
|
3113
|
+
() => client.execute("SELECT MAX(version) as max_v FROM memories"),
|
|
3114
|
+
"version-query"
|
|
3115
|
+
);
|
|
3086
3116
|
_nextVersion = (Number(vResult.rows[0]?.max_v) || 0) + 1;
|
|
3087
3117
|
}
|
|
3088
3118
|
function classifyTier(record) {
|
|
@@ -3125,6 +3155,12 @@ async function writeMemory(record) {
|
|
|
3125
3155
|
supersedes_id: record.supersedes_id ?? null
|
|
3126
3156
|
};
|
|
3127
3157
|
_pendingRecords.push(dbRow);
|
|
3158
|
+
const MAX_PENDING = 1e3;
|
|
3159
|
+
if (_pendingRecords.length > MAX_PENDING) {
|
|
3160
|
+
const dropped = _pendingRecords.length - MAX_PENDING;
|
|
3161
|
+
_pendingRecords = _pendingRecords.slice(-MAX_PENDING);
|
|
3162
|
+
console.warn(`[store] Dropped ${dropped} oldest pending records (overflow)`);
|
|
3163
|
+
}
|
|
3128
3164
|
if (_flushTimer === null) {
|
|
3129
3165
|
_flushTimer = setInterval(() => {
|
|
3130
3166
|
void flushBatch();
|
package/dist/bin/exe-settings.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { createInterface } from "readline";
|
|
3
3
|
|
|
4
4
|
// src/lib/config.ts
|
|
5
|
-
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
5
|
+
import { readFile, writeFile, mkdir, chmod } from "fs/promises";
|
|
6
6
|
import { readFileSync, existsSync, renameSync } from "fs";
|
|
7
7
|
import path from "path";
|
|
8
8
|
import os from "os";
|
|
@@ -188,6 +188,9 @@ async function saveConfig(config) {
|
|
|
188
188
|
await mkdir(dir, { recursive: true });
|
|
189
189
|
const configPath = path.join(dir, "config.json");
|
|
190
190
|
await writeFile(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
191
|
+
if (config.cloud?.apiKey) {
|
|
192
|
+
await chmod(configPath, 384);
|
|
193
|
+
}
|
|
191
194
|
}
|
|
192
195
|
|
|
193
196
|
// src/lib/is-main.ts
|
|
@@ -204,6 +207,62 @@ function isMainModule(importMetaUrl) {
|
|
|
204
207
|
}
|
|
205
208
|
}
|
|
206
209
|
|
|
210
|
+
// src/lib/cloud-sync.ts
|
|
211
|
+
import { readFileSync as readFileSync5, writeFileSync as writeFileSync2, existsSync as existsSync5, readdirSync, mkdirSync as mkdirSync2, appendFileSync, unlinkSync } from "fs";
|
|
212
|
+
import path5 from "path";
|
|
213
|
+
import { homedir } from "os";
|
|
214
|
+
|
|
215
|
+
// src/lib/database.ts
|
|
216
|
+
import { createClient } from "@libsql/client";
|
|
217
|
+
|
|
218
|
+
// src/lib/crypto.ts
|
|
219
|
+
import crypto from "crypto";
|
|
220
|
+
|
|
221
|
+
// src/lib/compress.ts
|
|
222
|
+
import { brotliCompressSync, brotliDecompressSync, constants } from "zlib";
|
|
223
|
+
|
|
224
|
+
// src/lib/plan-limits.ts
|
|
225
|
+
import { readFileSync as readFileSync4, existsSync as existsSync4 } from "fs";
|
|
226
|
+
import path4 from "path";
|
|
227
|
+
|
|
228
|
+
// src/lib/employees.ts
|
|
229
|
+
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
230
|
+
import { existsSync as existsSync2, symlinkSync, readlinkSync, readFileSync as readFileSync2 } from "fs";
|
|
231
|
+
import { execSync } from "child_process";
|
|
232
|
+
import path2 from "path";
|
|
233
|
+
var EMPLOYEES_PATH = path2.join(EXE_AI_DIR, "exe-employees.json");
|
|
234
|
+
|
|
235
|
+
// src/lib/license.ts
|
|
236
|
+
import { readFileSync as readFileSync3, writeFileSync, existsSync as existsSync3, mkdirSync } from "fs";
|
|
237
|
+
import { randomUUID } from "crypto";
|
|
238
|
+
import path3 from "path";
|
|
239
|
+
import { jwtVerify, importSPKI } from "jose";
|
|
240
|
+
var LICENSE_PATH = path3.join(EXE_AI_DIR, "license.key");
|
|
241
|
+
var CACHE_PATH = path3.join(EXE_AI_DIR, "license-cache.json");
|
|
242
|
+
var DEVICE_ID_PATH = path3.join(EXE_AI_DIR, "device-id");
|
|
243
|
+
|
|
244
|
+
// src/lib/plan-limits.ts
|
|
245
|
+
var CACHE_PATH2 = path4.join(EXE_AI_DIR, "license-cache.json");
|
|
246
|
+
|
|
247
|
+
// src/lib/cloud-sync.ts
|
|
248
|
+
var LOCALHOST_PATTERNS = /^(localhost|127\.0\.0\.1|\[::1\])$/i;
|
|
249
|
+
var ROSTER_LOCK_PATH = path5.join(EXE_AI_DIR, "roster-merge.lock");
|
|
250
|
+
function assertSecureEndpoint(endpoint) {
|
|
251
|
+
if (endpoint.startsWith("https://")) return;
|
|
252
|
+
if (endpoint.startsWith("http://")) {
|
|
253
|
+
try {
|
|
254
|
+
const parsed = new URL(endpoint);
|
|
255
|
+
if (LOCALHOST_PATTERNS.test(parsed.hostname)) return;
|
|
256
|
+
} catch {
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
throw new Error(
|
|
260
|
+
`Insecure cloud endpoint rejected: "${endpoint}". Use https:// for remote hosts. Plain http:// is only allowed for localhost.`
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
var ROSTER_DELETIONS_PATH = path5.join(EXE_AI_DIR, "roster-deletions.json");
|
|
265
|
+
|
|
207
266
|
// src/bin/exe-settings.ts
|
|
208
267
|
function label(value) {
|
|
209
268
|
return value ? "ON" : "OFF";
|
|
@@ -315,9 +374,11 @@ async function main() {
|
|
|
315
374
|
const endpoint = ep.trim() || "https://askexe.com/cloud";
|
|
316
375
|
console.log(" Validating...");
|
|
317
376
|
try {
|
|
377
|
+
assertSecureEndpoint(endpoint);
|
|
318
378
|
const resp = await fetch(`${endpoint}/auth/verify`, {
|
|
319
379
|
method: "POST",
|
|
320
|
-
headers: { "Authorization": `Bearer ${key}`, "Content-Type": "application/json" }
|
|
380
|
+
headers: { "Authorization": `Bearer ${key}`, "Content-Type": "application/json" },
|
|
381
|
+
signal: AbortSignal.timeout(3e4)
|
|
321
382
|
});
|
|
322
383
|
if (resp.ok) {
|
|
323
384
|
config.cloud = { apiKey: key, endpoint };
|
package/dist/bin/exe-status.js
CHANGED
|
@@ -1,12 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
var __defProp = Object.defineProperty;
|
|
3
3
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
-
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
5
|
-
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
6
|
-
}) : x)(function(x) {
|
|
7
|
-
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
8
|
-
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
9
|
-
});
|
|
10
4
|
var __esm = (fn, res) => function __init() {
|
|
11
5
|
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
12
6
|
};
|
|
@@ -16,7 +10,7 @@ var __export = (target, all) => {
|
|
|
16
10
|
};
|
|
17
11
|
|
|
18
12
|
// src/lib/config.ts
|
|
19
|
-
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
13
|
+
import { readFile, writeFile, mkdir, chmod } from "fs/promises";
|
|
20
14
|
import { readFileSync, existsSync, renameSync } from "fs";
|
|
21
15
|
import path from "path";
|
|
22
16
|
import os from "os";
|
|
@@ -218,7 +212,7 @@ __export(shard_manager_exports, {
|
|
|
218
212
|
shardExists: () => shardExists
|
|
219
213
|
});
|
|
220
214
|
import path4 from "path";
|
|
221
|
-
import { existsSync as existsSync4, mkdirSync } from "fs";
|
|
215
|
+
import { existsSync as existsSync4, mkdirSync, readdirSync } from "fs";
|
|
222
216
|
import { createClient as createClient2 } from "@libsql/client";
|
|
223
217
|
function initShardManager(encryptionKey) {
|
|
224
218
|
_encryptionKey = encryptionKey;
|
|
@@ -257,7 +251,6 @@ function shardExists(projectName) {
|
|
|
257
251
|
}
|
|
258
252
|
function listShards() {
|
|
259
253
|
if (!existsSync4(SHARDS_DIR)) return [];
|
|
260
|
-
const { readdirSync } = __require("fs");
|
|
261
254
|
return readdirSync(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
|
|
262
255
|
}
|
|
263
256
|
async function ensureShardSchema(client) {
|
|
@@ -552,6 +545,7 @@ async function ensureSchema() {
|
|
|
552
545
|
const client = getRawClient();
|
|
553
546
|
await client.execute("PRAGMA journal_mode = WAL");
|
|
554
547
|
await client.execute("PRAGMA busy_timeout = 30000");
|
|
548
|
+
await client.execute("PRAGMA wal_autocheckpoint = 1000");
|
|
555
549
|
try {
|
|
556
550
|
await client.execute("PRAGMA libsql_vector_search_ef = 128");
|
|
557
551
|
} catch {
|
|
@@ -1342,14 +1336,15 @@ async function ensureSchema() {
|
|
|
1342
1336
|
}
|
|
1343
1337
|
|
|
1344
1338
|
// src/lib/keychain.ts
|
|
1345
|
-
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod } from "fs/promises";
|
|
1339
|
+
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
|
|
1346
1340
|
import { existsSync as existsSync3 } from "fs";
|
|
1347
1341
|
import path3 from "path";
|
|
1342
|
+
import os2 from "os";
|
|
1348
1343
|
import crypto from "crypto";
|
|
1349
1344
|
var SERVICE = "exe-mem";
|
|
1350
1345
|
var ACCOUNT = "master-key";
|
|
1351
1346
|
function getKeyDir() {
|
|
1352
|
-
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path3.join(
|
|
1347
|
+
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path3.join(os2.homedir(), ".exe-os");
|
|
1353
1348
|
}
|
|
1354
1349
|
function getKeyPath() {
|
|
1355
1350
|
return path3.join(getKeyDir(), "master.key");
|
|
@@ -1386,6 +1381,30 @@ async function getMasterKey() {
|
|
|
1386
1381
|
|
|
1387
1382
|
// src/lib/store.ts
|
|
1388
1383
|
init_config();
|
|
1384
|
+
var INIT_MAX_RETRIES = 3;
|
|
1385
|
+
var INIT_RETRY_DELAY_MS = 1e3;
|
|
1386
|
+
function isBusyError2(err) {
|
|
1387
|
+
if (err instanceof Error) {
|
|
1388
|
+
const msg = err.message.toLowerCase();
|
|
1389
|
+
return msg.includes("sqlite_busy") || msg.includes("database is locked");
|
|
1390
|
+
}
|
|
1391
|
+
return false;
|
|
1392
|
+
}
|
|
1393
|
+
async function retryOnBusy2(fn, label) {
|
|
1394
|
+
for (let attempt = 0; attempt <= INIT_MAX_RETRIES; attempt++) {
|
|
1395
|
+
try {
|
|
1396
|
+
return await fn();
|
|
1397
|
+
} catch (err) {
|
|
1398
|
+
if (!isBusyError2(err) || attempt === INIT_MAX_RETRIES) throw err;
|
|
1399
|
+
process.stderr.write(
|
|
1400
|
+
`[store] SQLITE_BUSY during ${label}, retry ${attempt + 1}/${INIT_MAX_RETRIES}
|
|
1401
|
+
`
|
|
1402
|
+
);
|
|
1403
|
+
await new Promise((r) => setTimeout(r, INIT_RETRY_DELAY_MS * (attempt + 1)));
|
|
1404
|
+
}
|
|
1405
|
+
}
|
|
1406
|
+
throw new Error("unreachable");
|
|
1407
|
+
}
|
|
1389
1408
|
var _pendingRecords = [];
|
|
1390
1409
|
var _batchSize = 20;
|
|
1391
1410
|
var _flushIntervalMs = 1e4;
|
|
@@ -1420,14 +1439,17 @@ async function initStore(options) {
|
|
|
1420
1439
|
dbPath,
|
|
1421
1440
|
encryptionKey: hexKey
|
|
1422
1441
|
});
|
|
1423
|
-
await ensureSchema();
|
|
1442
|
+
await retryOnBusy2(() => ensureSchema(), "ensureSchema");
|
|
1424
1443
|
try {
|
|
1425
1444
|
const { initShardManager: initShardManager2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
|
|
1426
1445
|
initShardManager2(hexKey);
|
|
1427
1446
|
} catch {
|
|
1428
1447
|
}
|
|
1429
1448
|
const client = getClient();
|
|
1430
|
-
const vResult = await
|
|
1449
|
+
const vResult = await retryOnBusy2(
|
|
1450
|
+
() => client.execute("SELECT MAX(version) as max_v FROM memories"),
|
|
1451
|
+
"version-query"
|
|
1452
|
+
);
|
|
1431
1453
|
_nextVersion = (Number(vResult.rows[0]?.max_v) || 0) + 1;
|
|
1432
1454
|
}
|
|
1433
1455
|
|
package/dist/bin/exe-team.js
CHANGED
|
@@ -1,12 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
var __defProp = Object.defineProperty;
|
|
3
3
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
-
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
5
|
-
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
6
|
-
}) : x)(function(x) {
|
|
7
|
-
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
8
|
-
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
9
|
-
});
|
|
10
4
|
var __esm = (fn, res) => function __init() {
|
|
11
5
|
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
12
6
|
};
|
|
@@ -16,7 +10,7 @@ var __export = (target, all) => {
|
|
|
16
10
|
};
|
|
17
11
|
|
|
18
12
|
// src/lib/config.ts
|
|
19
|
-
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
13
|
+
import { readFile, writeFile, mkdir, chmod } from "fs/promises";
|
|
20
14
|
import { readFileSync, existsSync, renameSync } from "fs";
|
|
21
15
|
import path from "path";
|
|
22
16
|
import os from "os";
|
|
@@ -218,7 +212,7 @@ __export(shard_manager_exports, {
|
|
|
218
212
|
shardExists: () => shardExists
|
|
219
213
|
});
|
|
220
214
|
import path4 from "path";
|
|
221
|
-
import { existsSync as existsSync4, mkdirSync } from "fs";
|
|
215
|
+
import { existsSync as existsSync4, mkdirSync, readdirSync } from "fs";
|
|
222
216
|
import { createClient as createClient2 } from "@libsql/client";
|
|
223
217
|
function initShardManager(encryptionKey) {
|
|
224
218
|
_encryptionKey = encryptionKey;
|
|
@@ -257,7 +251,6 @@ function shardExists(projectName) {
|
|
|
257
251
|
}
|
|
258
252
|
function listShards() {
|
|
259
253
|
if (!existsSync4(SHARDS_DIR)) return [];
|
|
260
|
-
const { readdirSync } = __require("fs");
|
|
261
254
|
return readdirSync(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
|
|
262
255
|
}
|
|
263
256
|
async function ensureShardSchema(client) {
|
|
@@ -552,6 +545,7 @@ async function ensureSchema() {
|
|
|
552
545
|
const client = getRawClient();
|
|
553
546
|
await client.execute("PRAGMA journal_mode = WAL");
|
|
554
547
|
await client.execute("PRAGMA busy_timeout = 30000");
|
|
548
|
+
await client.execute("PRAGMA wal_autocheckpoint = 1000");
|
|
555
549
|
try {
|
|
556
550
|
await client.execute("PRAGMA libsql_vector_search_ef = 128");
|
|
557
551
|
} catch {
|
|
@@ -1342,14 +1336,15 @@ async function ensureSchema() {
|
|
|
1342
1336
|
}
|
|
1343
1337
|
|
|
1344
1338
|
// src/lib/keychain.ts
|
|
1345
|
-
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod } from "fs/promises";
|
|
1339
|
+
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
|
|
1346
1340
|
import { existsSync as existsSync3 } from "fs";
|
|
1347
1341
|
import path3 from "path";
|
|
1342
|
+
import os2 from "os";
|
|
1348
1343
|
import crypto from "crypto";
|
|
1349
1344
|
var SERVICE = "exe-mem";
|
|
1350
1345
|
var ACCOUNT = "master-key";
|
|
1351
1346
|
function getKeyDir() {
|
|
1352
|
-
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path3.join(
|
|
1347
|
+
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path3.join(os2.homedir(), ".exe-os");
|
|
1353
1348
|
}
|
|
1354
1349
|
function getKeyPath() {
|
|
1355
1350
|
return path3.join(getKeyDir(), "master.key");
|
|
@@ -1386,6 +1381,30 @@ async function getMasterKey() {
|
|
|
1386
1381
|
|
|
1387
1382
|
// src/lib/store.ts
|
|
1388
1383
|
init_config();
|
|
1384
|
+
var INIT_MAX_RETRIES = 3;
|
|
1385
|
+
var INIT_RETRY_DELAY_MS = 1e3;
|
|
1386
|
+
function isBusyError2(err) {
|
|
1387
|
+
if (err instanceof Error) {
|
|
1388
|
+
const msg = err.message.toLowerCase();
|
|
1389
|
+
return msg.includes("sqlite_busy") || msg.includes("database is locked");
|
|
1390
|
+
}
|
|
1391
|
+
return false;
|
|
1392
|
+
}
|
|
1393
|
+
async function retryOnBusy2(fn, label) {
|
|
1394
|
+
for (let attempt = 0; attempt <= INIT_MAX_RETRIES; attempt++) {
|
|
1395
|
+
try {
|
|
1396
|
+
return await fn();
|
|
1397
|
+
} catch (err) {
|
|
1398
|
+
if (!isBusyError2(err) || attempt === INIT_MAX_RETRIES) throw err;
|
|
1399
|
+
process.stderr.write(
|
|
1400
|
+
`[store] SQLITE_BUSY during ${label}, retry ${attempt + 1}/${INIT_MAX_RETRIES}
|
|
1401
|
+
`
|
|
1402
|
+
);
|
|
1403
|
+
await new Promise((r) => setTimeout(r, INIT_RETRY_DELAY_MS * (attempt + 1)));
|
|
1404
|
+
}
|
|
1405
|
+
}
|
|
1406
|
+
throw new Error("unreachable");
|
|
1407
|
+
}
|
|
1389
1408
|
var _pendingRecords = [];
|
|
1390
1409
|
var _batchSize = 20;
|
|
1391
1410
|
var _flushIntervalMs = 1e4;
|
|
@@ -1420,14 +1439,17 @@ async function initStore(options) {
|
|
|
1420
1439
|
dbPath,
|
|
1421
1440
|
encryptionKey: hexKey
|
|
1422
1441
|
});
|
|
1423
|
-
await ensureSchema();
|
|
1442
|
+
await retryOnBusy2(() => ensureSchema(), "ensureSchema");
|
|
1424
1443
|
try {
|
|
1425
1444
|
const { initShardManager: initShardManager2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
|
|
1426
1445
|
initShardManager2(hexKey);
|
|
1427
1446
|
} catch {
|
|
1428
1447
|
}
|
|
1429
1448
|
const client = getClient();
|
|
1430
|
-
const vResult = await
|
|
1449
|
+
const vResult = await retryOnBusy2(
|
|
1450
|
+
() => client.execute("SELECT MAX(version) as max_v FROM memories"),
|
|
1451
|
+
"version-query"
|
|
1452
|
+
);
|
|
1431
1453
|
_nextVersion = (Number(vResult.rows[0]?.max_v) || 0) + 1;
|
|
1432
1454
|
}
|
|
1433
1455
|
|