@askexenow/exe-os 0.8.38 → 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 +46 -10
- package/dist/bin/backfill-responses.js +46 -10
- package/dist/bin/backfill-vectors.js +42 -8
- package/dist/bin/cleanup-stale-review-tasks.js +37 -8
- package/dist/bin/cli.js +281 -154
- package/dist/bin/exe-agent.js +19 -4
- package/dist/bin/exe-assign.js +39 -5
- package/dist/bin/exe-boot.js +237 -111
- package/dist/bin/exe-call.js +11 -6
- package/dist/bin/exe-cloud.js +99 -28
- package/dist/bin/exe-dispatch.js +1 -1
- package/dist/bin/exe-doctor.js +37 -8
- package/dist/bin/exe-export-behaviors.js +39 -10
- package/dist/bin/exe-forget.js +38 -9
- package/dist/bin/exe-gateway.js +109 -42
- package/dist/bin/exe-heartbeat.js +49 -20
- package/dist/bin/exe-kill.js +39 -10
- package/dist/bin/exe-launch-agent.js +58 -22
- package/dist/bin/exe-link.js +184 -85
- package/dist/bin/exe-new-employee.js +21 -7
- package/dist/bin/exe-pending-messages.js +46 -17
- package/dist/bin/exe-pending-notifications.js +37 -8
- package/dist/bin/exe-pending-reviews.js +47 -18
- package/dist/bin/exe-rename.js +21 -7
- package/dist/bin/exe-review.js +34 -5
- package/dist/bin/exe-search.js +47 -10
- package/dist/bin/exe-session-cleanup.js +56 -19
- package/dist/bin/exe-settings.js +63 -2
- package/dist/bin/exe-status.js +34 -5
- package/dist/bin/exe-team.js +34 -5
- package/dist/bin/git-sweep.js +38 -9
- package/dist/bin/graph-backfill.js +37 -8
- package/dist/bin/graph-export.js +37 -8
- package/dist/bin/install.js +1 -1
- package/dist/bin/scan-tasks.js +40 -11
- package/dist/bin/setup.js +58 -24
- package/dist/bin/shard-migrate.js +37 -8
- package/dist/bin/wiki-sync.js +39 -9
- package/dist/gateway/index.js +102 -37
- package/dist/hooks/bug-report-worker.js +62 -28
- package/dist/hooks/commit-complete.js +38 -9
- package/dist/hooks/error-recall.js +49 -8
- package/dist/hooks/exe-heartbeat-hook.js +3 -2
- package/dist/hooks/ingest-worker.js +151 -37
- package/dist/hooks/ingest.js +74 -28
- package/dist/hooks/instructions-loaded.js +39 -9
- package/dist/hooks/notification.js +37 -7
- package/dist/hooks/post-compact.js +37 -7
- package/dist/hooks/pre-compact.js +35 -6
- package/dist/hooks/pre-tool-use.js +52 -14
- package/dist/hooks/prompt-ingest-worker.js +56 -10
- package/dist/hooks/prompt-submit.js +61 -23
- package/dist/hooks/response-ingest-worker.js +57 -11
- package/dist/hooks/session-end.js +43 -10
- package/dist/hooks/session-start.js +46 -8
- package/dist/hooks/stop.js +37 -7
- package/dist/hooks/subagent-stop.js +37 -7
- package/dist/hooks/summary-worker.js +317 -99
- package/dist/index.js +87 -22
- package/dist/lib/cloud-sync.js +172 -78
- 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/employees.js +11 -6
- package/dist/lib/exe-daemon-client.js +6 -1
- package/dist/lib/exe-daemon.js +71 -28
- package/dist/lib/hybrid-search.js +47 -10
- package/dist/lib/identity.js +1 -1
- package/dist/lib/keychain.js +2 -1
- package/dist/lib/license.js +13 -4
- package/dist/lib/messaging.js +1 -1
- package/dist/lib/reminders.js +2 -2
- package/dist/lib/schedules.js +37 -8
- package/dist/lib/skill-learning.js +1 -1
- package/dist/lib/store.js +37 -8
- package/dist/lib/tasks.js +1 -1
- package/dist/lib/tmux-routing.js +1 -1
- package/dist/mcp/server.js +97 -43
- 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 +1 -1
- package/dist/mcp/tools/send-message.js +1 -1
- package/dist/mcp/tools/update-task.js +1 -1
- package/dist/runtime/index.js +35 -6
- package/dist/tui/App.js +177 -95
- package/package.json +3 -3
|
@@ -79,6 +79,17 @@ var init_db_retry = __esm({
|
|
|
79
79
|
});
|
|
80
80
|
|
|
81
81
|
// src/lib/database.ts
|
|
82
|
+
var database_exports = {};
|
|
83
|
+
__export(database_exports, {
|
|
84
|
+
disposeDatabase: () => disposeDatabase,
|
|
85
|
+
disposeTurso: () => disposeTurso,
|
|
86
|
+
ensureSchema: () => ensureSchema,
|
|
87
|
+
getClient: () => getClient,
|
|
88
|
+
getRawClient: () => getRawClient,
|
|
89
|
+
initDatabase: () => initDatabase,
|
|
90
|
+
initTurso: () => initTurso,
|
|
91
|
+
isInitialized: () => isInitialized
|
|
92
|
+
});
|
|
82
93
|
import { createClient } from "@libsql/client";
|
|
83
94
|
async function initDatabase(config) {
|
|
84
95
|
if (_client) {
|
|
@@ -114,6 +125,7 @@ async function ensureSchema() {
|
|
|
114
125
|
const client = getRawClient();
|
|
115
126
|
await client.execute("PRAGMA journal_mode = WAL");
|
|
116
127
|
await client.execute("PRAGMA busy_timeout = 30000");
|
|
128
|
+
await client.execute("PRAGMA wal_autocheckpoint = 1000");
|
|
117
129
|
try {
|
|
118
130
|
await client.execute("PRAGMA libsql_vector_search_ef = 128");
|
|
119
131
|
} catch {
|
|
@@ -902,7 +914,14 @@ async function ensureSchema() {
|
|
|
902
914
|
}
|
|
903
915
|
}
|
|
904
916
|
}
|
|
905
|
-
|
|
917
|
+
async function disposeDatabase() {
|
|
918
|
+
if (_client) {
|
|
919
|
+
_client.close();
|
|
920
|
+
_client = null;
|
|
921
|
+
_resilientClient = null;
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
var _client, _resilientClient, initTurso, disposeTurso;
|
|
906
925
|
var init_database = __esm({
|
|
907
926
|
"src/lib/database.ts"() {
|
|
908
927
|
"use strict";
|
|
@@ -910,6 +929,7 @@ var init_database = __esm({
|
|
|
910
929
|
_client = null;
|
|
911
930
|
_resilientClient = null;
|
|
912
931
|
initTurso = initDatabase;
|
|
932
|
+
disposeTurso = disposeDatabase;
|
|
913
933
|
}
|
|
914
934
|
});
|
|
915
935
|
|
|
@@ -925,9 +945,10 @@ __export(keychain_exports, {
|
|
|
925
945
|
import { readFile, writeFile, unlink, mkdir, chmod } from "fs/promises";
|
|
926
946
|
import { existsSync } from "fs";
|
|
927
947
|
import path from "path";
|
|
948
|
+
import os from "os";
|
|
928
949
|
import crypto from "crypto";
|
|
929
950
|
function getKeyDir() {
|
|
930
|
-
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path.join(
|
|
951
|
+
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path.join(os.homedir(), ".exe-os");
|
|
931
952
|
}
|
|
932
953
|
function getKeyPath() {
|
|
933
954
|
return path.join(getKeyDir(), "master.key");
|
|
@@ -1075,15 +1096,15 @@ __export(config_exports, {
|
|
|
1075
1096
|
migrateConfig: () => migrateConfig,
|
|
1076
1097
|
saveConfig: () => saveConfig
|
|
1077
1098
|
});
|
|
1078
|
-
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
1099
|
+
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2, chmod as chmod2 } from "fs/promises";
|
|
1079
1100
|
import { readFileSync, existsSync as existsSync2, renameSync } from "fs";
|
|
1080
1101
|
import path2 from "path";
|
|
1081
|
-
import
|
|
1102
|
+
import os2 from "os";
|
|
1082
1103
|
function resolveDataDir() {
|
|
1083
1104
|
if (process.env.EXE_OS_DIR) return process.env.EXE_OS_DIR;
|
|
1084
1105
|
if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
|
|
1085
|
-
const newDir = path2.join(
|
|
1086
|
-
const legacyDir = path2.join(
|
|
1106
|
+
const newDir = path2.join(os2.homedir(), ".exe-os");
|
|
1107
|
+
const legacyDir = path2.join(os2.homedir(), ".exe-mem");
|
|
1087
1108
|
if (!existsSync2(newDir) && existsSync2(legacyDir)) {
|
|
1088
1109
|
try {
|
|
1089
1110
|
renameSync(legacyDir, newDir);
|
|
@@ -1170,7 +1191,7 @@ async function loadConfig() {
|
|
|
1170
1191
|
normalizeAutoUpdate(migratedCfg);
|
|
1171
1192
|
const config = { ...DEFAULT_CONFIG, dbPath: path2.join(dir, "memories.db"), ...migratedCfg };
|
|
1172
1193
|
if (config.dbPath.startsWith("~")) {
|
|
1173
|
-
config.dbPath = config.dbPath.replace(/^~/,
|
|
1194
|
+
config.dbPath = config.dbPath.replace(/^~/, os2.homedir());
|
|
1174
1195
|
}
|
|
1175
1196
|
return config;
|
|
1176
1197
|
} catch {
|
|
@@ -1201,6 +1222,9 @@ async function saveConfig(config) {
|
|
|
1201
1222
|
await mkdir2(dir, { recursive: true });
|
|
1202
1223
|
const configPath = path2.join(dir, "config.json");
|
|
1203
1224
|
await writeFile2(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
1225
|
+
if (config.cloud?.apiKey) {
|
|
1226
|
+
await chmod2(configPath, 384);
|
|
1227
|
+
}
|
|
1204
1228
|
}
|
|
1205
1229
|
async function loadConfigFrom(configPath) {
|
|
1206
1230
|
const raw = await readFile2(configPath, "utf-8");
|
|
@@ -1563,15 +1587,20 @@ async function saveEmployees(employees, employeesPath = EMPLOYEES_PATH) {
|
|
|
1563
1587
|
await mkdir3(path5.dirname(employeesPath), { recursive: true });
|
|
1564
1588
|
await writeFile3(employeesPath, JSON.stringify(employees, null, 2) + "\n", "utf-8");
|
|
1565
1589
|
}
|
|
1590
|
+
function findExeBin() {
|
|
1591
|
+
try {
|
|
1592
|
+
return execSync(process.platform === "win32" ? "where exe-os" : "which exe-os", { encoding: "utf8" }).trim();
|
|
1593
|
+
} catch {
|
|
1594
|
+
return null;
|
|
1595
|
+
}
|
|
1596
|
+
}
|
|
1566
1597
|
function registerBinSymlinks(name) {
|
|
1567
1598
|
const created = [];
|
|
1568
1599
|
const skipped = [];
|
|
1569
1600
|
const errors = [];
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
} catch {
|
|
1574
|
-
errors.push("Could not find 'exe' in PATH");
|
|
1601
|
+
const exeBinPath = findExeBin();
|
|
1602
|
+
if (!exeBinPath) {
|
|
1603
|
+
errors.push("Could not find 'exe-os' in PATH");
|
|
1575
1604
|
return { created, skipped, errors };
|
|
1576
1605
|
}
|
|
1577
1606
|
const binDir = path5.dirname(exeBinPath);
|
|
@@ -1612,6 +1641,14 @@ import { readFileSync as readFileSync4, writeFileSync, existsSync as existsSync6
|
|
|
1612
1641
|
import { randomUUID } from "crypto";
|
|
1613
1642
|
import path6 from "path";
|
|
1614
1643
|
import { jwtVerify, importSPKI } from "jose";
|
|
1644
|
+
async function fetchRetry(url, init) {
|
|
1645
|
+
try {
|
|
1646
|
+
return await fetch(url, init);
|
|
1647
|
+
} catch {
|
|
1648
|
+
await new Promise((r) => setTimeout(r, RETRY_DELAY_MS));
|
|
1649
|
+
return fetch(url, { ...init, signal: AbortSignal.timeout(1e4) });
|
|
1650
|
+
}
|
|
1651
|
+
}
|
|
1615
1652
|
function loadDeviceId() {
|
|
1616
1653
|
const deviceJsonPath = path6.join(EXE_AI_DIR, "device.json");
|
|
1617
1654
|
try {
|
|
@@ -1682,7 +1719,7 @@ function cacheResponse(token) {
|
|
|
1682
1719
|
async function validateLicense(apiKey, deviceId) {
|
|
1683
1720
|
const did = deviceId ?? loadDeviceId();
|
|
1684
1721
|
try {
|
|
1685
|
-
const res = await
|
|
1722
|
+
const res = await fetchRetry(`${API_BASE}/auth/activate`, {
|
|
1686
1723
|
method: "POST",
|
|
1687
1724
|
headers: { "Content-Type": "application/json" },
|
|
1688
1725
|
body: JSON.stringify({ apiKey, deviceId: did }),
|
|
@@ -1747,7 +1784,7 @@ function isFeatureAllowed(license, feature) {
|
|
|
1747
1784
|
return license.plan === "team" || license.plan === "agency" || license.plan === "enterprise";
|
|
1748
1785
|
}
|
|
1749
1786
|
}
|
|
1750
|
-
var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH, API_BASE, LICENSE_PUBLIC_KEY_PEM, LICENSE_JWT_ALG, PLAN_LIMITS, FREE_LICENSE, CACHE_MAX_AGE_MS;
|
|
1787
|
+
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;
|
|
1751
1788
|
var init_license = __esm({
|
|
1752
1789
|
"src/lib/license.ts"() {
|
|
1753
1790
|
"use strict";
|
|
@@ -1756,6 +1793,7 @@ var init_license = __esm({
|
|
|
1756
1793
|
CACHE_PATH = path6.join(EXE_AI_DIR, "license-cache.json");
|
|
1757
1794
|
DEVICE_ID_PATH = path6.join(EXE_AI_DIR, "device-id");
|
|
1758
1795
|
API_BASE = "https://askexe.com/cloud";
|
|
1796
|
+
RETRY_DELAY_MS = 500;
|
|
1759
1797
|
LICENSE_PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----
|
|
1760
1798
|
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeHztAMOpR/ZMh+rWuOASjEZ54CGY
|
|
1761
1799
|
4uj+UqeKCcvtgNHKmOK278HJaJcANe9xAeji8AFYu27q3WtzCi04pHudow==
|
|
@@ -1915,6 +1953,10 @@ import path8 from "path";
|
|
|
1915
1953
|
import { fileURLToPath } from "url";
|
|
1916
1954
|
function handleData(chunk) {
|
|
1917
1955
|
_buffer += chunk.toString();
|
|
1956
|
+
if (_buffer.length > MAX_BUFFER) {
|
|
1957
|
+
_buffer = "";
|
|
1958
|
+
return;
|
|
1959
|
+
}
|
|
1918
1960
|
let newlineIdx;
|
|
1919
1961
|
while ((newlineIdx = _buffer.indexOf("\n")) !== -1) {
|
|
1920
1962
|
const line = _buffer.slice(0, newlineIdx).trim();
|
|
@@ -2222,7 +2264,7 @@ function disconnectClient() {
|
|
|
2222
2264
|
entry.resolve({ error: "Client disconnected" });
|
|
2223
2265
|
}
|
|
2224
2266
|
}
|
|
2225
|
-
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;
|
|
2267
|
+
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;
|
|
2226
2268
|
var init_exe_daemon_client = __esm({
|
|
2227
2269
|
"src/lib/exe-daemon-client.ts"() {
|
|
2228
2270
|
"use strict";
|
|
@@ -2239,6 +2281,7 @@ var init_exe_daemon_client = __esm({
|
|
|
2239
2281
|
_requestCount = 0;
|
|
2240
2282
|
HEALTH_CHECK_INTERVAL = 100;
|
|
2241
2283
|
_pending = /* @__PURE__ */ new Map();
|
|
2284
|
+
MAX_BUFFER = 1e7;
|
|
2242
2285
|
}
|
|
2243
2286
|
});
|
|
2244
2287
|
|
|
@@ -2280,8 +2323,8 @@ async function embedDirect(text) {
|
|
|
2280
2323
|
const llamaCpp = await import("node-llama-cpp");
|
|
2281
2324
|
const { MODELS_DIR: MODELS_DIR2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
2282
2325
|
const { existsSync: existsSync11 } = await import("fs");
|
|
2283
|
-
const
|
|
2284
|
-
const modelPath =
|
|
2326
|
+
const path12 = await import("path");
|
|
2327
|
+
const modelPath = path12.join(MODELS_DIR2, "jina-embeddings-v5-small-q4_k_m.gguf");
|
|
2285
2328
|
if (!existsSync11(modelPath)) {
|
|
2286
2329
|
throw new Error(`Embedding model not found at ${modelPath}. Run '/exe-setup' to download it.`);
|
|
2287
2330
|
}
|
|
@@ -2392,6 +2435,7 @@ var init_compress = __esm({
|
|
|
2392
2435
|
// src/lib/cloud-sync.ts
|
|
2393
2436
|
var cloud_sync_exports = {};
|
|
2394
2437
|
__export(cloud_sync_exports, {
|
|
2438
|
+
assertSecureEndpoint: () => assertSecureEndpoint,
|
|
2395
2439
|
buildRosterBlob: () => buildRosterBlob,
|
|
2396
2440
|
cloudPull: () => cloudPull,
|
|
2397
2441
|
cloudPullBehaviors: () => cloudPullBehaviors,
|
|
@@ -2411,9 +2455,10 @@ __export(cloud_sync_exports, {
|
|
|
2411
2455
|
cloudPushTasks: () => cloudPushTasks,
|
|
2412
2456
|
cloudSync: () => cloudSync,
|
|
2413
2457
|
mergeConfig: () => mergeConfig,
|
|
2414
|
-
mergeRosterFromRemote: () => mergeRosterFromRemote
|
|
2458
|
+
mergeRosterFromRemote: () => mergeRosterFromRemote,
|
|
2459
|
+
recordRosterDeletion: () => recordRosterDeletion
|
|
2415
2460
|
});
|
|
2416
|
-
import { readFileSync as readFileSync7, writeFileSync as writeFileSync2, existsSync as existsSync9, readdirSync as readdirSync3, mkdirSync as mkdirSync3, appendFileSync } from "fs";
|
|
2461
|
+
import { readFileSync as readFileSync7, writeFileSync as writeFileSync2, existsSync as existsSync9, readdirSync as readdirSync3, mkdirSync as mkdirSync3, appendFileSync, unlinkSync as unlinkSync3 } from "fs";
|
|
2417
2462
|
import path9 from "path";
|
|
2418
2463
|
import { homedir } from "os";
|
|
2419
2464
|
function logError(msg) {
|
|
@@ -2424,16 +2469,47 @@ function logError(msg) {
|
|
|
2424
2469
|
} catch {
|
|
2425
2470
|
}
|
|
2426
2471
|
}
|
|
2472
|
+
async function withRosterLock(fn) {
|
|
2473
|
+
if (existsSync9(ROSTER_LOCK_PATH)) {
|
|
2474
|
+
try {
|
|
2475
|
+
const ts = parseInt(readFileSync7(ROSTER_LOCK_PATH, "utf-8"), 10);
|
|
2476
|
+
if (Date.now() - ts < LOCK_STALE_MS) {
|
|
2477
|
+
throw new Error("Roster merge already in progress \u2014 another sync is running");
|
|
2478
|
+
}
|
|
2479
|
+
} catch (err) {
|
|
2480
|
+
if (err instanceof Error && err.message.includes("already in progress")) throw err;
|
|
2481
|
+
}
|
|
2482
|
+
}
|
|
2483
|
+
writeFileSync2(ROSTER_LOCK_PATH, String(Date.now()));
|
|
2484
|
+
try {
|
|
2485
|
+
return await fn();
|
|
2486
|
+
} finally {
|
|
2487
|
+
try {
|
|
2488
|
+
unlinkSync3(ROSTER_LOCK_PATH);
|
|
2489
|
+
} catch {
|
|
2490
|
+
}
|
|
2491
|
+
}
|
|
2492
|
+
}
|
|
2427
2493
|
async function fetchWithRetry(url, init) {
|
|
2428
|
-
const
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2494
|
+
const MAX_RETRIES2 = 3;
|
|
2495
|
+
const BASE_DELAY_MS2 = 200;
|
|
2496
|
+
let lastError;
|
|
2497
|
+
for (let attempt = 0; attempt <= MAX_RETRIES2; attempt++) {
|
|
2498
|
+
try {
|
|
2499
|
+
const signal = AbortSignal.timeout(FETCH_TIMEOUT_MS);
|
|
2500
|
+
const resp = await fetch(url, { ...init, signal });
|
|
2501
|
+
if (resp.status >= 500 && attempt < MAX_RETRIES2) {
|
|
2502
|
+
await new Promise((r) => setTimeout(r, BASE_DELAY_MS2 * Math.pow(2, attempt)));
|
|
2503
|
+
continue;
|
|
2504
|
+
}
|
|
2505
|
+
return resp;
|
|
2506
|
+
} catch (err) {
|
|
2507
|
+
lastError = err;
|
|
2508
|
+
if (attempt === MAX_RETRIES2) throw err;
|
|
2509
|
+
await new Promise((r) => setTimeout(r, BASE_DELAY_MS2 * Math.pow(2, attempt)));
|
|
2510
|
+
}
|
|
2435
2511
|
}
|
|
2436
|
-
|
|
2512
|
+
throw lastError;
|
|
2437
2513
|
}
|
|
2438
2514
|
function assertSecureEndpoint(endpoint) {
|
|
2439
2515
|
if (endpoint.startsWith("https://")) return;
|
|
@@ -2461,10 +2537,15 @@ async function cloudPush(records, maxVersion, config) {
|
|
|
2461
2537
|
headers: {
|
|
2462
2538
|
Authorization: `Bearer ${config.apiKey}`,
|
|
2463
2539
|
"Content-Type": "application/json",
|
|
2464
|
-
"X-Device-Id": loadDeviceId()
|
|
2540
|
+
"X-Device-Id": loadDeviceId(),
|
|
2541
|
+
"X-Expected-Version": String(maxVersion)
|
|
2465
2542
|
},
|
|
2466
2543
|
body: JSON.stringify({ version: maxVersion, blob })
|
|
2467
2544
|
});
|
|
2545
|
+
if (resp.status === 409) {
|
|
2546
|
+
logError("[cloud-sync] PUSH VERSION CONFLICT \u2014 re-pull required before next push");
|
|
2547
|
+
return false;
|
|
2548
|
+
}
|
|
2468
2549
|
return resp.ok;
|
|
2469
2550
|
} catch (err) {
|
|
2470
2551
|
logError(`[cloud-sync] PUSH FAILED: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -2551,18 +2632,21 @@ async function cloudSync(config) {
|
|
|
2551
2632
|
"SELECT value FROM sync_meta WHERE key = 'last_cloud_push_version'"
|
|
2552
2633
|
);
|
|
2553
2634
|
const lastPushVersion = pushMeta.rows.length > 0 ? Number(pushMeta.rows[0].value) : 0;
|
|
2554
|
-
const recordsResult = await client.execute({
|
|
2555
|
-
sql: `SELECT id, agent_id, agent_role, session_id, timestamp,
|
|
2556
|
-
tool_name, project_name, has_error, raw_text, version,
|
|
2557
|
-
author_device_id, scope
|
|
2558
|
-
FROM memories
|
|
2559
|
-
WHERE version > ?
|
|
2560
|
-
AND (scope IS NULL OR scope != 'personal')
|
|
2561
|
-
ORDER BY version ASC`,
|
|
2562
|
-
args: [lastPushVersion]
|
|
2563
|
-
});
|
|
2564
2635
|
let pushed = 0;
|
|
2565
|
-
|
|
2636
|
+
let batchCursor = lastPushVersion;
|
|
2637
|
+
while (true) {
|
|
2638
|
+
const recordsResult = await client.execute({
|
|
2639
|
+
sql: `SELECT id, agent_id, agent_role, session_id, timestamp,
|
|
2640
|
+
tool_name, project_name, has_error, raw_text, version,
|
|
2641
|
+
author_device_id, scope
|
|
2642
|
+
FROM memories
|
|
2643
|
+
WHERE version > ?
|
|
2644
|
+
AND (scope IS NULL OR scope != 'personal')
|
|
2645
|
+
ORDER BY version ASC
|
|
2646
|
+
LIMIT ?`,
|
|
2647
|
+
args: [batchCursor, PUSH_BATCH_SIZE]
|
|
2648
|
+
});
|
|
2649
|
+
if (recordsResult.rows.length === 0) break;
|
|
2566
2650
|
const records = recordsResult.rows.map((row) => ({
|
|
2567
2651
|
id: row.id,
|
|
2568
2652
|
agent_id: row.agent_id,
|
|
@@ -2579,13 +2663,14 @@ async function cloudSync(config) {
|
|
|
2579
2663
|
}));
|
|
2580
2664
|
const maxVersion = Number(records[records.length - 1].version);
|
|
2581
2665
|
const pushOk = await cloudPush(records, maxVersion, config);
|
|
2582
|
-
if (pushOk)
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2666
|
+
if (!pushOk) break;
|
|
2667
|
+
await client.execute({
|
|
2668
|
+
sql: "INSERT OR REPLACE INTO sync_meta (key, value) VALUES ('last_cloud_push_version', ?)",
|
|
2669
|
+
args: [String(maxVersion)]
|
|
2670
|
+
});
|
|
2671
|
+
pushed += records.length;
|
|
2672
|
+
batchCursor = maxVersion;
|
|
2673
|
+
if (recordsResult.rows.length < PUSH_BATCH_SIZE) break;
|
|
2589
2674
|
}
|
|
2590
2675
|
try {
|
|
2591
2676
|
await cloudPushRoster(config);
|
|
@@ -2667,6 +2752,27 @@ async function cloudSync(config) {
|
|
|
2667
2752
|
documents: documentsResult
|
|
2668
2753
|
};
|
|
2669
2754
|
}
|
|
2755
|
+
function recordRosterDeletion(name) {
|
|
2756
|
+
let deletions = [];
|
|
2757
|
+
try {
|
|
2758
|
+
if (existsSync9(ROSTER_DELETIONS_PATH)) {
|
|
2759
|
+
deletions = JSON.parse(readFileSync7(ROSTER_DELETIONS_PATH, "utf-8"));
|
|
2760
|
+
}
|
|
2761
|
+
} catch {
|
|
2762
|
+
}
|
|
2763
|
+
if (!deletions.includes(name)) deletions.push(name);
|
|
2764
|
+
writeFileSync2(ROSTER_DELETIONS_PATH, JSON.stringify(deletions));
|
|
2765
|
+
}
|
|
2766
|
+
function consumeRosterDeletions() {
|
|
2767
|
+
try {
|
|
2768
|
+
if (!existsSync9(ROSTER_DELETIONS_PATH)) return [];
|
|
2769
|
+
const deletions = JSON.parse(readFileSync7(ROSTER_DELETIONS_PATH, "utf-8"));
|
|
2770
|
+
writeFileSync2(ROSTER_DELETIONS_PATH, "[]");
|
|
2771
|
+
return deletions;
|
|
2772
|
+
} catch {
|
|
2773
|
+
return [];
|
|
2774
|
+
}
|
|
2775
|
+
}
|
|
2670
2776
|
function buildRosterBlob(paths) {
|
|
2671
2777
|
const rosterPath = paths?.rosterPath ?? path9.join(EXE_AI_DIR, "exe-employees.json");
|
|
2672
2778
|
const identityDir = paths?.identityDir ?? path9.join(EXE_AI_DIR, "identity");
|
|
@@ -2694,9 +2800,10 @@ function buildRosterBlob(paths) {
|
|
|
2694
2800
|
} catch {
|
|
2695
2801
|
}
|
|
2696
2802
|
}
|
|
2697
|
-
const
|
|
2803
|
+
const deletedNames = consumeRosterDeletions();
|
|
2804
|
+
const content = JSON.stringify({ roster, identities, config, deletedNames });
|
|
2698
2805
|
const hash = Buffer.from(content).length;
|
|
2699
|
-
return { roster, identities, config, version: hash };
|
|
2806
|
+
return { roster, identities, config, deletedNames, version: hash };
|
|
2700
2807
|
}
|
|
2701
2808
|
async function cloudPushRoster(config) {
|
|
2702
2809
|
assertSecureEndpoint(config.endpoint);
|
|
@@ -2779,38 +2886,50 @@ function mergeConfig(remoteConfig, configPath) {
|
|
|
2779
2886
|
writeFileSync2(cfgPath, JSON.stringify(merged, null, 2), "utf-8");
|
|
2780
2887
|
}
|
|
2781
2888
|
async function mergeRosterFromRemote(remote, paths) {
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
if (
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
|
|
2889
|
+
return withRosterLock(async () => {
|
|
2890
|
+
const rosterPath = paths?.rosterPath ?? void 0;
|
|
2891
|
+
const identityDir = paths?.identityDir ?? path9.join(EXE_AI_DIR, "identity");
|
|
2892
|
+
const localEmployees = await loadEmployees(rosterPath);
|
|
2893
|
+
const localNames = new Set(localEmployees.map((e) => e.name));
|
|
2894
|
+
let added = 0;
|
|
2895
|
+
for (const remoteEmp of remote.roster) {
|
|
2896
|
+
if (localNames.has(remoteEmp.name)) continue;
|
|
2897
|
+
localEmployees.push(remoteEmp);
|
|
2898
|
+
localNames.add(remoteEmp.name);
|
|
2899
|
+
added++;
|
|
2900
|
+
if (remote.identities[`${remoteEmp.name}.md`]) {
|
|
2901
|
+
if (!existsSync9(identityDir)) mkdirSync3(identityDir, { recursive: true });
|
|
2902
|
+
const idPath = path9.join(identityDir, `${remoteEmp.name}.md`);
|
|
2903
|
+
if (!existsSync9(idPath)) {
|
|
2904
|
+
writeFileSync2(idPath, remote.identities[`${remoteEmp.name}.md`], "utf-8");
|
|
2905
|
+
}
|
|
2906
|
+
}
|
|
2907
|
+
try {
|
|
2908
|
+
registerBinSymlinks(remoteEmp.name);
|
|
2909
|
+
} catch {
|
|
2797
2910
|
}
|
|
2798
2911
|
}
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2912
|
+
let removed = 0;
|
|
2913
|
+
if (remote.deletedNames && remote.deletedNames.length > 0) {
|
|
2914
|
+
const toRemove = new Set(remote.deletedNames);
|
|
2915
|
+
const filtered = localEmployees.filter((e) => !toRemove.has(e.name));
|
|
2916
|
+
removed = localEmployees.length - filtered.length;
|
|
2917
|
+
if (removed > 0) {
|
|
2918
|
+
localEmployees.length = 0;
|
|
2919
|
+
localEmployees.push(...filtered);
|
|
2920
|
+
}
|
|
2802
2921
|
}
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
await saveEmployees(localEmployees, rosterPath);
|
|
2806
|
-
}
|
|
2807
|
-
if (remote.config && Object.keys(remote.config).length > 0) {
|
|
2808
|
-
try {
|
|
2809
|
-
mergeConfig(remote.config, paths?.configPath);
|
|
2810
|
-
} catch {
|
|
2922
|
+
if (added > 0 || removed > 0) {
|
|
2923
|
+
await saveEmployees(localEmployees, rosterPath);
|
|
2811
2924
|
}
|
|
2812
|
-
|
|
2813
|
-
|
|
2925
|
+
if (remote.config && Object.keys(remote.config).length > 0) {
|
|
2926
|
+
try {
|
|
2927
|
+
mergeConfig(remote.config, paths?.configPath);
|
|
2928
|
+
} catch {
|
|
2929
|
+
}
|
|
2930
|
+
}
|
|
2931
|
+
return { added };
|
|
2932
|
+
});
|
|
2814
2933
|
}
|
|
2815
2934
|
async function cloudPushBlob(route, data, metaKey, config) {
|
|
2816
2935
|
if (data.length === 0) return { ok: true };
|
|
@@ -2878,7 +2997,7 @@ async function cloudPullBlob(route, config) {
|
|
|
2878
2997
|
}
|
|
2879
2998
|
async function cloudPushBehaviors(config) {
|
|
2880
2999
|
const client = getClient();
|
|
2881
|
-
const result = await client.execute("SELECT * FROM behaviors");
|
|
3000
|
+
const result = await client.execute("SELECT * FROM behaviors LIMIT 10000");
|
|
2882
3001
|
const rows = result.rows;
|
|
2883
3002
|
const { ok } = await cloudPushBlob(
|
|
2884
3003
|
"/sync/push-behaviors",
|
|
@@ -2926,13 +3045,13 @@ async function cloudPullBehaviors(config) {
|
|
|
2926
3045
|
async function cloudPushGraphRAG(config) {
|
|
2927
3046
|
const client = getClient();
|
|
2928
3047
|
const [entities, relationships, aliases, entityMems, relMems, hyperedges, hyperedgeNodes] = await Promise.all([
|
|
2929
|
-
client.execute("SELECT * FROM entities"),
|
|
2930
|
-
client.execute("SELECT * FROM relationships"),
|
|
2931
|
-
client.execute("SELECT * FROM entity_aliases"),
|
|
2932
|
-
client.execute("SELECT * FROM entity_memories"),
|
|
2933
|
-
client.execute("SELECT * FROM relationship_memories"),
|
|
2934
|
-
client.execute("SELECT * FROM hyperedges"),
|
|
2935
|
-
client.execute("SELECT * FROM hyperedge_nodes")
|
|
3048
|
+
client.execute("SELECT * FROM entities LIMIT 50000"),
|
|
3049
|
+
client.execute("SELECT * FROM relationships LIMIT 50000"),
|
|
3050
|
+
client.execute("SELECT * FROM entity_aliases LIMIT 50000"),
|
|
3051
|
+
client.execute("SELECT * FROM entity_memories LIMIT 50000"),
|
|
3052
|
+
client.execute("SELECT * FROM relationship_memories LIMIT 50000"),
|
|
3053
|
+
client.execute("SELECT * FROM hyperedges LIMIT 50000"),
|
|
3054
|
+
client.execute("SELECT * FROM hyperedge_nodes LIMIT 50000")
|
|
2936
3055
|
]);
|
|
2937
3056
|
const blob = {
|
|
2938
3057
|
entities: entities.rows,
|
|
@@ -3034,7 +3153,7 @@ async function cloudPullGraphRAG(config) {
|
|
|
3034
3153
|
}
|
|
3035
3154
|
async function cloudPushTasks(config) {
|
|
3036
3155
|
const client = getClient();
|
|
3037
|
-
const result = await client.execute("SELECT * FROM tasks");
|
|
3156
|
+
const result = await client.execute("SELECT * FROM tasks LIMIT 10000");
|
|
3038
3157
|
const rows = result.rows;
|
|
3039
3158
|
const { ok } = await cloudPushBlob(
|
|
3040
3159
|
"/sync/push-tasks",
|
|
@@ -3080,7 +3199,7 @@ async function cloudPullTasks(config) {
|
|
|
3080
3199
|
}
|
|
3081
3200
|
async function cloudPushConversations(config) {
|
|
3082
3201
|
const client = getClient();
|
|
3083
|
-
const result = await client.execute("SELECT * FROM conversations");
|
|
3202
|
+
const result = await client.execute("SELECT * FROM conversations LIMIT 50000");
|
|
3084
3203
|
const rows = result.rows;
|
|
3085
3204
|
const { ok } = await cloudPushBlob(
|
|
3086
3205
|
"/sync/push-conversations",
|
|
@@ -3130,8 +3249,8 @@ async function cloudPullConversations(config) {
|
|
|
3130
3249
|
async function cloudPushDocuments(config) {
|
|
3131
3250
|
const client = getClient();
|
|
3132
3251
|
const [workspaces, documents] = await Promise.all([
|
|
3133
|
-
client.execute("SELECT * FROM workspaces"),
|
|
3134
|
-
client.execute("SELECT * FROM documents")
|
|
3252
|
+
client.execute("SELECT * FROM workspaces LIMIT 1000"),
|
|
3253
|
+
client.execute("SELECT * FROM documents LIMIT 10000")
|
|
3135
3254
|
]);
|
|
3136
3255
|
const blob = {
|
|
3137
3256
|
workspaces: workspaces.rows,
|
|
@@ -3184,7 +3303,7 @@ async function cloudPullDocuments(config) {
|
|
|
3184
3303
|
}
|
|
3185
3304
|
return { pulled };
|
|
3186
3305
|
}
|
|
3187
|
-
var LOCALHOST_PATTERNS, FETCH_TIMEOUT_MS;
|
|
3306
|
+
var LOCALHOST_PATTERNS, FETCH_TIMEOUT_MS, PUSH_BATCH_SIZE, ROSTER_LOCK_PATH, LOCK_STALE_MS, ROSTER_DELETIONS_PATH;
|
|
3188
3307
|
var init_cloud_sync = __esm({
|
|
3189
3308
|
"src/lib/cloud-sync.ts"() {
|
|
3190
3309
|
"use strict";
|
|
@@ -3197,6 +3316,68 @@ var init_cloud_sync = __esm({
|
|
|
3197
3316
|
init_employees();
|
|
3198
3317
|
LOCALHOST_PATTERNS = /^(localhost|127\.0\.0\.1|\[::1\])$/i;
|
|
3199
3318
|
FETCH_TIMEOUT_MS = 3e4;
|
|
3319
|
+
PUSH_BATCH_SIZE = 5e3;
|
|
3320
|
+
ROSTER_LOCK_PATH = path9.join(EXE_AI_DIR, "roster-merge.lock");
|
|
3321
|
+
LOCK_STALE_MS = 3e4;
|
|
3322
|
+
ROSTER_DELETIONS_PATH = path9.join(EXE_AI_DIR, "roster-deletions.json");
|
|
3323
|
+
}
|
|
3324
|
+
});
|
|
3325
|
+
|
|
3326
|
+
// src/lib/worker-gate.ts
|
|
3327
|
+
var worker_gate_exports = {};
|
|
3328
|
+
__export(worker_gate_exports, {
|
|
3329
|
+
MAX_CONCURRENT_WORKERS: () => MAX_CONCURRENT_WORKERS,
|
|
3330
|
+
cleanupWorkerPid: () => cleanupWorkerPid,
|
|
3331
|
+
registerWorkerPid: () => registerWorkerPid,
|
|
3332
|
+
tryAcquireWorkerSlot: () => tryAcquireWorkerSlot
|
|
3333
|
+
});
|
|
3334
|
+
import { readdirSync as readdirSync4, writeFileSync as writeFileSync3, unlinkSync as unlinkSync4, mkdirSync as mkdirSync4 } from "fs";
|
|
3335
|
+
import path10 from "path";
|
|
3336
|
+
function tryAcquireWorkerSlot() {
|
|
3337
|
+
try {
|
|
3338
|
+
mkdirSync4(WORKER_PID_DIR, { recursive: true });
|
|
3339
|
+
const files = readdirSync4(WORKER_PID_DIR);
|
|
3340
|
+
let alive = 0;
|
|
3341
|
+
for (const f of files) {
|
|
3342
|
+
if (!f.endsWith(".pid")) continue;
|
|
3343
|
+
const dashIdx = f.lastIndexOf("-");
|
|
3344
|
+
const pid = parseInt(f.slice(dashIdx + 1).replace(".pid", ""), 10);
|
|
3345
|
+
if (isNaN(pid)) continue;
|
|
3346
|
+
try {
|
|
3347
|
+
process.kill(pid, 0);
|
|
3348
|
+
alive++;
|
|
3349
|
+
} catch {
|
|
3350
|
+
try {
|
|
3351
|
+
unlinkSync4(path10.join(WORKER_PID_DIR, f));
|
|
3352
|
+
} catch {
|
|
3353
|
+
}
|
|
3354
|
+
}
|
|
3355
|
+
}
|
|
3356
|
+
return alive < MAX_CONCURRENT_WORKERS;
|
|
3357
|
+
} catch {
|
|
3358
|
+
return true;
|
|
3359
|
+
}
|
|
3360
|
+
}
|
|
3361
|
+
function registerWorkerPid(pid) {
|
|
3362
|
+
try {
|
|
3363
|
+
mkdirSync4(WORKER_PID_DIR, { recursive: true });
|
|
3364
|
+
writeFileSync3(path10.join(WORKER_PID_DIR, `worker-${pid}.pid`), String(pid));
|
|
3365
|
+
} catch {
|
|
3366
|
+
}
|
|
3367
|
+
}
|
|
3368
|
+
function cleanupWorkerPid() {
|
|
3369
|
+
try {
|
|
3370
|
+
unlinkSync4(path10.join(WORKER_PID_DIR, `worker-${process.pid}.pid`));
|
|
3371
|
+
} catch {
|
|
3372
|
+
}
|
|
3373
|
+
}
|
|
3374
|
+
var WORKER_PID_DIR, MAX_CONCURRENT_WORKERS;
|
|
3375
|
+
var init_worker_gate = __esm({
|
|
3376
|
+
"src/lib/worker-gate.ts"() {
|
|
3377
|
+
"use strict";
|
|
3378
|
+
init_config();
|
|
3379
|
+
WORKER_PID_DIR = path10.join(EXE_AI_DIR, "worker-pids");
|
|
3380
|
+
MAX_CONCURRENT_WORKERS = 3;
|
|
3200
3381
|
}
|
|
3201
3382
|
});
|
|
3202
3383
|
|
|
@@ -3205,6 +3386,30 @@ init_memory();
|
|
|
3205
3386
|
init_database();
|
|
3206
3387
|
init_keychain();
|
|
3207
3388
|
init_config();
|
|
3389
|
+
var INIT_MAX_RETRIES = 3;
|
|
3390
|
+
var INIT_RETRY_DELAY_MS = 1e3;
|
|
3391
|
+
function isBusyError2(err) {
|
|
3392
|
+
if (err instanceof Error) {
|
|
3393
|
+
const msg = err.message.toLowerCase();
|
|
3394
|
+
return msg.includes("sqlite_busy") || msg.includes("database is locked");
|
|
3395
|
+
}
|
|
3396
|
+
return false;
|
|
3397
|
+
}
|
|
3398
|
+
async function retryOnBusy2(fn, label) {
|
|
3399
|
+
for (let attempt = 0; attempt <= INIT_MAX_RETRIES; attempt++) {
|
|
3400
|
+
try {
|
|
3401
|
+
return await fn();
|
|
3402
|
+
} catch (err) {
|
|
3403
|
+
if (!isBusyError2(err) || attempt === INIT_MAX_RETRIES) throw err;
|
|
3404
|
+
process.stderr.write(
|
|
3405
|
+
`[store] SQLITE_BUSY during ${label}, retry ${attempt + 1}/${INIT_MAX_RETRIES}
|
|
3406
|
+
`
|
|
3407
|
+
);
|
|
3408
|
+
await new Promise((r) => setTimeout(r, INIT_RETRY_DELAY_MS * (attempt + 1)));
|
|
3409
|
+
}
|
|
3410
|
+
}
|
|
3411
|
+
throw new Error("unreachable");
|
|
3412
|
+
}
|
|
3208
3413
|
var _pendingRecords = [];
|
|
3209
3414
|
var _batchSize = 20;
|
|
3210
3415
|
var _flushIntervalMs = 1e4;
|
|
@@ -3239,14 +3444,17 @@ async function initStore(options) {
|
|
|
3239
3444
|
dbPath,
|
|
3240
3445
|
encryptionKey: hexKey
|
|
3241
3446
|
});
|
|
3242
|
-
await ensureSchema();
|
|
3447
|
+
await retryOnBusy2(() => ensureSchema(), "ensureSchema");
|
|
3243
3448
|
try {
|
|
3244
3449
|
const { initShardManager: initShardManager2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
|
|
3245
3450
|
initShardManager2(hexKey);
|
|
3246
3451
|
} catch {
|
|
3247
3452
|
}
|
|
3248
3453
|
const client = getClient();
|
|
3249
|
-
const vResult = await
|
|
3454
|
+
const vResult = await retryOnBusy2(
|
|
3455
|
+
() => client.execute("SELECT MAX(version) as max_v FROM memories"),
|
|
3456
|
+
"version-query"
|
|
3457
|
+
);
|
|
3250
3458
|
_nextVersion = (Number(vResult.rows[0]?.max_v) || 0) + 1;
|
|
3251
3459
|
}
|
|
3252
3460
|
function classifyTier(record) {
|
|
@@ -3451,7 +3659,7 @@ import crypto4 from "crypto";
|
|
|
3451
3659
|
init_database();
|
|
3452
3660
|
import crypto2 from "crypto";
|
|
3453
3661
|
import path4 from "path";
|
|
3454
|
-
import
|
|
3662
|
+
import os3 from "os";
|
|
3455
3663
|
import {
|
|
3456
3664
|
readFileSync as readFileSync2,
|
|
3457
3665
|
readdirSync as readdirSync2,
|
|
@@ -3486,8 +3694,8 @@ async function writeNotification(notification) {
|
|
|
3486
3694
|
|
|
3487
3695
|
// src/adapters/claude/hooks/summary-worker.ts
|
|
3488
3696
|
import { execSync as execSync2 } from "child_process";
|
|
3489
|
-
import { existsSync as existsSync10, mkdirSync as
|
|
3490
|
-
import
|
|
3697
|
+
import { existsSync as existsSync10, mkdirSync as mkdirSync5, openSync as openSync2, closeSync as closeSync2 } from "fs";
|
|
3698
|
+
import path11 from "path";
|
|
3491
3699
|
async function main() {
|
|
3492
3700
|
const agentId = process.env.AGENT_ID ?? "default";
|
|
3493
3701
|
const agentRole = process.env.AGENT_ROLE ?? "employee";
|
|
@@ -3611,16 +3819,16 @@ async function main() {
|
|
|
3611
3819
|
}
|
|
3612
3820
|
try {
|
|
3613
3821
|
const { EXE_AI_DIR: EXE_AI_DIR2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
3614
|
-
const flagPath =
|
|
3822
|
+
const flagPath = path11.join(EXE_AI_DIR2, "session-cache", "needs-backfill");
|
|
3615
3823
|
if (existsSync10(flagPath)) {
|
|
3616
3824
|
const { spawn: spawn2 } = await import("child_process");
|
|
3617
3825
|
const { fileURLToPath: fileURLToPath2 } = await import("url");
|
|
3618
3826
|
const thisFile = fileURLToPath2(import.meta.url);
|
|
3619
|
-
const backfillPath =
|
|
3827
|
+
const backfillPath = path11.resolve(path11.dirname(thisFile), "backfill-vectors.js");
|
|
3620
3828
|
if (existsSync10(backfillPath)) {
|
|
3621
3829
|
const { EXE_AI_DIR: exeDir2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
3622
|
-
const bLogPath =
|
|
3623
|
-
|
|
3830
|
+
const bLogPath = path11.join(exeDir2, "workers.log");
|
|
3831
|
+
mkdirSync5(path11.dirname(bLogPath), { recursive: true });
|
|
3624
3832
|
const bLogFd = openSync2(bLogPath, "a");
|
|
3625
3833
|
const child = spawn2(process.execPath, [backfillPath], {
|
|
3626
3834
|
detached: true,
|
|
@@ -3693,9 +3901,19 @@ async function main() {
|
|
|
3693
3901
|
process.stderr.write("[summary-worker] orphan scan failed: " + (err instanceof Error ? err.message : String(err)) + "\n");
|
|
3694
3902
|
}
|
|
3695
3903
|
}
|
|
3904
|
+
try {
|
|
3905
|
+
const { getRawClient: getRawClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
3906
|
+
await getRawClient2().execute("PRAGMA wal_checkpoint(PASSIVE)");
|
|
3907
|
+
} catch {
|
|
3908
|
+
}
|
|
3696
3909
|
}
|
|
3697
3910
|
main().catch((err) => {
|
|
3698
3911
|
process.stderr.write("[summary-worker] FATAL: " + (err instanceof Error ? err.message : String(err)) + "\n");
|
|
3699
|
-
}).finally(() => {
|
|
3912
|
+
}).finally(async () => {
|
|
3913
|
+
try {
|
|
3914
|
+
const { cleanupWorkerPid: cleanupWorkerPid2 } = await Promise.resolve().then(() => (init_worker_gate(), worker_gate_exports));
|
|
3915
|
+
cleanupWorkerPid2();
|
|
3916
|
+
} catch {
|
|
3917
|
+
}
|
|
3700
3918
|
process.exit(0);
|
|
3701
3919
|
});
|