@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
package/dist/bin/exe-boot.js
CHANGED
|
@@ -42,7 +42,7 @@ __export(config_exports, {
|
|
|
42
42
|
migrateConfig: () => migrateConfig,
|
|
43
43
|
saveConfig: () => saveConfig
|
|
44
44
|
});
|
|
45
|
-
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
45
|
+
import { readFile, writeFile, mkdir, chmod } from "fs/promises";
|
|
46
46
|
import { readFileSync, existsSync, renameSync } from "fs";
|
|
47
47
|
import path from "path";
|
|
48
48
|
import os from "os";
|
|
@@ -168,6 +168,9 @@ async function saveConfig(config) {
|
|
|
168
168
|
await mkdir(dir, { recursive: true });
|
|
169
169
|
const configPath = path.join(dir, "config.json");
|
|
170
170
|
await writeFile(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
171
|
+
if (config.cloud?.apiKey) {
|
|
172
|
+
await chmod(configPath, 384);
|
|
173
|
+
}
|
|
171
174
|
}
|
|
172
175
|
async function loadConfigFrom(configPath) {
|
|
173
176
|
const raw = await readFile(configPath, "utf-8");
|
|
@@ -306,15 +309,20 @@ function isMultiInstance(agentName, employees) {
|
|
|
306
309
|
if (!emp) return false;
|
|
307
310
|
return MULTI_INSTANCE_ROLES.has(emp.role.toLowerCase());
|
|
308
311
|
}
|
|
312
|
+
function findExeBin() {
|
|
313
|
+
try {
|
|
314
|
+
return execSync(process.platform === "win32" ? "where exe-os" : "which exe-os", { encoding: "utf8" }).trim();
|
|
315
|
+
} catch {
|
|
316
|
+
return null;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
309
319
|
function registerBinSymlinks(name) {
|
|
310
320
|
const created = [];
|
|
311
321
|
const skipped = [];
|
|
312
322
|
const errors = [];
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
} catch {
|
|
317
|
-
errors.push("Could not find 'exe' in PATH");
|
|
323
|
+
const exeBinPath = findExeBin();
|
|
324
|
+
if (!exeBinPath) {
|
|
325
|
+
errors.push("Could not find 'exe-os' in PATH");
|
|
318
326
|
return { created, skipped, errors };
|
|
319
327
|
}
|
|
320
328
|
const binDir = path2.dirname(exeBinPath);
|
|
@@ -449,6 +457,7 @@ async function ensureSchema() {
|
|
|
449
457
|
const client = getRawClient();
|
|
450
458
|
await client.execute("PRAGMA journal_mode = WAL");
|
|
451
459
|
await client.execute("PRAGMA busy_timeout = 30000");
|
|
460
|
+
await client.execute("PRAGMA wal_autocheckpoint = 1000");
|
|
452
461
|
try {
|
|
453
462
|
await client.execute("PRAGMA libsql_vector_search_ef = 128");
|
|
454
463
|
} catch {
|
|
@@ -1257,12 +1266,13 @@ __export(keychain_exports, {
|
|
|
1257
1266
|
importMnemonic: () => importMnemonic,
|
|
1258
1267
|
setMasterKey: () => setMasterKey
|
|
1259
1268
|
});
|
|
1260
|
-
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod } from "fs/promises";
|
|
1269
|
+
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
|
|
1261
1270
|
import { existsSync as existsSync3 } from "fs";
|
|
1262
1271
|
import path3 from "path";
|
|
1272
|
+
import os2 from "os";
|
|
1263
1273
|
import crypto from "crypto";
|
|
1264
1274
|
function getKeyDir() {
|
|
1265
|
-
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path3.join(
|
|
1275
|
+
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path3.join(os2.homedir(), ".exe-os");
|
|
1266
1276
|
}
|
|
1267
1277
|
function getKeyPath() {
|
|
1268
1278
|
return path3.join(getKeyDir(), "master.key");
|
|
@@ -1310,7 +1320,7 @@ async function setMasterKey(key) {
|
|
|
1310
1320
|
await mkdir3(dir, { recursive: true });
|
|
1311
1321
|
const keyPath = getKeyPath();
|
|
1312
1322
|
await writeFile3(keyPath, b64 + "\n", "utf-8");
|
|
1313
|
-
await
|
|
1323
|
+
await chmod2(keyPath, 384);
|
|
1314
1324
|
}
|
|
1315
1325
|
async function deleteMasterKey() {
|
|
1316
1326
|
const keytar = await tryKeytar();
|
|
@@ -1636,6 +1646,28 @@ var init_shard_manager = __esm({
|
|
|
1636
1646
|
});
|
|
1637
1647
|
|
|
1638
1648
|
// src/lib/store.ts
|
|
1649
|
+
function isBusyError2(err) {
|
|
1650
|
+
if (err instanceof Error) {
|
|
1651
|
+
const msg = err.message.toLowerCase();
|
|
1652
|
+
return msg.includes("sqlite_busy") || msg.includes("database is locked");
|
|
1653
|
+
}
|
|
1654
|
+
return false;
|
|
1655
|
+
}
|
|
1656
|
+
async function retryOnBusy2(fn, label) {
|
|
1657
|
+
for (let attempt = 0; attempt <= INIT_MAX_RETRIES; attempt++) {
|
|
1658
|
+
try {
|
|
1659
|
+
return await fn();
|
|
1660
|
+
} catch (err) {
|
|
1661
|
+
if (!isBusyError2(err) || attempt === INIT_MAX_RETRIES) throw err;
|
|
1662
|
+
process.stderr.write(
|
|
1663
|
+
`[store] SQLITE_BUSY during ${label}, retry ${attempt + 1}/${INIT_MAX_RETRIES}
|
|
1664
|
+
`
|
|
1665
|
+
);
|
|
1666
|
+
await new Promise((r) => setTimeout(r, INIT_RETRY_DELAY_MS * (attempt + 1)));
|
|
1667
|
+
}
|
|
1668
|
+
}
|
|
1669
|
+
throw new Error("unreachable");
|
|
1670
|
+
}
|
|
1639
1671
|
async function initStore(options) {
|
|
1640
1672
|
if (_flushTimer !== null) {
|
|
1641
1673
|
clearInterval(_flushTimer);
|
|
@@ -1664,17 +1696,20 @@ async function initStore(options) {
|
|
|
1664
1696
|
dbPath,
|
|
1665
1697
|
encryptionKey: hexKey
|
|
1666
1698
|
});
|
|
1667
|
-
await ensureSchema();
|
|
1699
|
+
await retryOnBusy2(() => ensureSchema(), "ensureSchema");
|
|
1668
1700
|
try {
|
|
1669
1701
|
const { initShardManager: initShardManager2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
|
|
1670
1702
|
initShardManager2(hexKey);
|
|
1671
1703
|
} catch {
|
|
1672
1704
|
}
|
|
1673
1705
|
const client = getClient();
|
|
1674
|
-
const vResult = await
|
|
1706
|
+
const vResult = await retryOnBusy2(
|
|
1707
|
+
() => client.execute("SELECT MAX(version) as max_v FROM memories"),
|
|
1708
|
+
"version-query"
|
|
1709
|
+
);
|
|
1675
1710
|
_nextVersion = (Number(vResult.rows[0]?.max_v) || 0) + 1;
|
|
1676
1711
|
}
|
|
1677
|
-
var _pendingRecords, _batchSize, _flushIntervalMs, _flushTimer, _flushing, _nextVersion;
|
|
1712
|
+
var INIT_MAX_RETRIES, INIT_RETRY_DELAY_MS, _pendingRecords, _batchSize, _flushIntervalMs, _flushTimer, _flushing, _nextVersion;
|
|
1678
1713
|
var init_store = __esm({
|
|
1679
1714
|
"src/lib/store.ts"() {
|
|
1680
1715
|
"use strict";
|
|
@@ -1682,6 +1717,8 @@ var init_store = __esm({
|
|
|
1682
1717
|
init_database();
|
|
1683
1718
|
init_keychain();
|
|
1684
1719
|
init_config();
|
|
1720
|
+
INIT_MAX_RETRIES = 3;
|
|
1721
|
+
INIT_RETRY_DELAY_MS = 1e3;
|
|
1685
1722
|
_pendingRecords = [];
|
|
1686
1723
|
_batchSize = 20;
|
|
1687
1724
|
_flushIntervalMs = 1e4;
|
|
@@ -1694,7 +1731,7 @@ var init_store = __esm({
|
|
|
1694
1731
|
// src/lib/notifications.ts
|
|
1695
1732
|
import crypto2 from "crypto";
|
|
1696
1733
|
import path5 from "path";
|
|
1697
|
-
import
|
|
1734
|
+
import os3 from "os";
|
|
1698
1735
|
import {
|
|
1699
1736
|
readFileSync as readFileSync3,
|
|
1700
1737
|
readdirSync as readdirSync2,
|
|
@@ -1812,7 +1849,7 @@ async function markDoneTaskNotificationsAsRead() {
|
|
|
1812
1849
|
}
|
|
1813
1850
|
}
|
|
1814
1851
|
async function migrateJsonNotifications() {
|
|
1815
|
-
const base = process.env.EXE_OS_DIR || process.env.EXE_MEM_DIR || path5.join(
|
|
1852
|
+
const base = process.env.EXE_OS_DIR || process.env.EXE_MEM_DIR || path5.join(os3.homedir(), ".exe-os");
|
|
1816
1853
|
const notifDir = path5.join(base, "notifications");
|
|
1817
1854
|
if (!existsSync5(notifDir)) return 0;
|
|
1818
1855
|
let migrated = 0;
|
|
@@ -1909,7 +1946,7 @@ __export(session_registry_exports, {
|
|
|
1909
1946
|
import { readFileSync as readFileSync5, writeFileSync as writeFileSync2, mkdirSync as mkdirSync3, existsSync as existsSync6 } from "fs";
|
|
1910
1947
|
import { execSync as execSync4 } from "child_process";
|
|
1911
1948
|
import path7 from "path";
|
|
1912
|
-
import
|
|
1949
|
+
import os4 from "os";
|
|
1913
1950
|
function registerSession(entry) {
|
|
1914
1951
|
const dir = path7.dirname(REGISTRY_PATH);
|
|
1915
1952
|
if (!existsSync6(dir)) {
|
|
@@ -1955,7 +1992,7 @@ var REGISTRY_PATH;
|
|
|
1955
1992
|
var init_session_registry = __esm({
|
|
1956
1993
|
"src/lib/session-registry.ts"() {
|
|
1957
1994
|
"use strict";
|
|
1958
|
-
REGISTRY_PATH = path7.join(
|
|
1995
|
+
REGISTRY_PATH = path7.join(os4.homedir(), ".exe-os", "session-registry.json");
|
|
1959
1996
|
}
|
|
1960
1997
|
});
|
|
1961
1998
|
|
|
@@ -2142,7 +2179,7 @@ var init_provider_table = __esm({
|
|
|
2142
2179
|
// src/lib/intercom-queue.ts
|
|
2143
2180
|
import { readFileSync as readFileSync6, writeFileSync as writeFileSync3, renameSync as renameSync2, existsSync as existsSync7, mkdirSync as mkdirSync4 } from "fs";
|
|
2144
2181
|
import path8 from "path";
|
|
2145
|
-
import
|
|
2182
|
+
import os5 from "os";
|
|
2146
2183
|
function ensureDir() {
|
|
2147
2184
|
const dir = path8.dirname(QUEUE_PATH);
|
|
2148
2185
|
if (!existsSync7(dir)) mkdirSync4(dir, { recursive: true });
|
|
@@ -2182,9 +2219,9 @@ var QUEUE_PATH, TTL_MS, INTERCOM_LOG;
|
|
|
2182
2219
|
var init_intercom_queue = __esm({
|
|
2183
2220
|
"src/lib/intercom-queue.ts"() {
|
|
2184
2221
|
"use strict";
|
|
2185
|
-
QUEUE_PATH = path8.join(
|
|
2222
|
+
QUEUE_PATH = path8.join(os5.homedir(), ".exe-os", "intercom-queue.json");
|
|
2186
2223
|
TTL_MS = 60 * 60 * 1e3;
|
|
2187
|
-
INTERCOM_LOG = path8.join(
|
|
2224
|
+
INTERCOM_LOG = path8.join(os5.homedir(), ".exe-os", "intercom.log");
|
|
2188
2225
|
}
|
|
2189
2226
|
});
|
|
2190
2227
|
|
|
@@ -2209,6 +2246,14 @@ import { readFileSync as readFileSync7, writeFileSync as writeFileSync4, existsS
|
|
|
2209
2246
|
import { randomUUID } from "crypto";
|
|
2210
2247
|
import path9 from "path";
|
|
2211
2248
|
import { jwtVerify, importSPKI } from "jose";
|
|
2249
|
+
async function fetchRetry(url, init) {
|
|
2250
|
+
try {
|
|
2251
|
+
return await fetch(url, init);
|
|
2252
|
+
} catch {
|
|
2253
|
+
await new Promise((r) => setTimeout(r, RETRY_DELAY_MS));
|
|
2254
|
+
return fetch(url, { ...init, signal: AbortSignal.timeout(1e4) });
|
|
2255
|
+
}
|
|
2256
|
+
}
|
|
2212
2257
|
function loadDeviceId() {
|
|
2213
2258
|
const deviceJsonPath = path9.join(EXE_AI_DIR, "device.json");
|
|
2214
2259
|
try {
|
|
@@ -2240,7 +2285,7 @@ function loadLicense() {
|
|
|
2240
2285
|
}
|
|
2241
2286
|
function saveLicense(apiKey) {
|
|
2242
2287
|
mkdirSync5(EXE_AI_DIR, { recursive: true });
|
|
2243
|
-
writeFileSync4(LICENSE_PATH, apiKey.trim(), "utf8");
|
|
2288
|
+
writeFileSync4(LICENSE_PATH, apiKey.trim(), { encoding: "utf8", mode: 384 });
|
|
2244
2289
|
}
|
|
2245
2290
|
async function verifyLicenseJwt(token) {
|
|
2246
2291
|
try {
|
|
@@ -2292,7 +2337,7 @@ function cacheResponse(token) {
|
|
|
2292
2337
|
async function validateLicense(apiKey, deviceId) {
|
|
2293
2338
|
const did = deviceId ?? loadDeviceId();
|
|
2294
2339
|
try {
|
|
2295
|
-
const res = await
|
|
2340
|
+
const res = await fetchRetry(`${API_BASE}/auth/activate`, {
|
|
2296
2341
|
method: "POST",
|
|
2297
2342
|
headers: { "Content-Type": "application/json" },
|
|
2298
2343
|
body: JSON.stringify({ apiKey, deviceId: did }),
|
|
@@ -2383,7 +2428,7 @@ async function assertVpsLicense(opts) {
|
|
|
2383
2428
|
let explicitRejection = false;
|
|
2384
2429
|
let transientFailure = false;
|
|
2385
2430
|
try {
|
|
2386
|
-
const res = await
|
|
2431
|
+
const res = await fetchRetry(`${API_BASE}/auth/activate`, {
|
|
2387
2432
|
method: "POST",
|
|
2388
2433
|
headers: { "Content-Type": "application/json" },
|
|
2389
2434
|
body: JSON.stringify({ apiKey, deviceId }),
|
|
@@ -2485,7 +2530,7 @@ function stopLicenseRevalidation() {
|
|
|
2485
2530
|
_revalTimer = null;
|
|
2486
2531
|
}
|
|
2487
2532
|
}
|
|
2488
|
-
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, _revalTimer;
|
|
2533
|
+
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;
|
|
2489
2534
|
var init_license = __esm({
|
|
2490
2535
|
"src/lib/license.ts"() {
|
|
2491
2536
|
"use strict";
|
|
@@ -2494,6 +2539,7 @@ var init_license = __esm({
|
|
|
2494
2539
|
CACHE_PATH = path9.join(EXE_AI_DIR, "license-cache.json");
|
|
2495
2540
|
DEVICE_ID_PATH = path9.join(EXE_AI_DIR, "device-id");
|
|
2496
2541
|
API_BASE = "https://askexe.com/cloud";
|
|
2542
|
+
RETRY_DELAY_MS = 500;
|
|
2497
2543
|
LICENSE_PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----
|
|
2498
2544
|
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeHztAMOpR/ZMh+rWuOASjEZ54CGY
|
|
2499
2545
|
4uj+UqeKCcvtgNHKmOK278HJaJcANe9xAeji8AFYu27q3WtzCi04pHudow==
|
|
@@ -2610,7 +2656,7 @@ var init_plan_limits = __esm({
|
|
|
2610
2656
|
import { execFileSync as execFileSync2, execSync as execSync6 } from "child_process";
|
|
2611
2657
|
import { readFileSync as readFileSync9, writeFileSync as writeFileSync5, mkdirSync as mkdirSync6, existsSync as existsSync10, appendFileSync } from "fs";
|
|
2612
2658
|
import path11 from "path";
|
|
2613
|
-
import
|
|
2659
|
+
import os6 from "os";
|
|
2614
2660
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
2615
2661
|
import { unlinkSync as unlinkSync3 } from "fs";
|
|
2616
2662
|
function spawnLockPath(sessionName) {
|
|
@@ -2915,7 +2961,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
2915
2961
|
const transport = getTransport();
|
|
2916
2962
|
const sessionName = employeeSessionName(employeeName, exeSession, opts?.instance);
|
|
2917
2963
|
const instanceLabel = opts?.instance != null && opts.instance > 0 ? `${employeeName}${opts.instance}` : employeeName;
|
|
2918
|
-
const logDir = path11.join(
|
|
2964
|
+
const logDir = path11.join(os6.homedir(), ".exe-os", "session-logs");
|
|
2919
2965
|
const logFile = path11.join(logDir, `${instanceLabel}-${Date.now()}.log`);
|
|
2920
2966
|
if (!existsSync10(logDir)) {
|
|
2921
2967
|
mkdirSync6(logDir, { recursive: true });
|
|
@@ -2931,7 +2977,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
2931
2977
|
} catch {
|
|
2932
2978
|
}
|
|
2933
2979
|
try {
|
|
2934
|
-
const claudeJsonPath = path11.join(
|
|
2980
|
+
const claudeJsonPath = path11.join(os6.homedir(), ".claude.json");
|
|
2935
2981
|
let claudeJson = {};
|
|
2936
2982
|
try {
|
|
2937
2983
|
claudeJson = JSON.parse(readFileSync9(claudeJsonPath, "utf8"));
|
|
@@ -2946,7 +2992,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
2946
2992
|
} catch {
|
|
2947
2993
|
}
|
|
2948
2994
|
try {
|
|
2949
|
-
const settingsDir = path11.join(
|
|
2995
|
+
const settingsDir = path11.join(os6.homedir(), ".claude", "projects");
|
|
2950
2996
|
const normalizedKey = (opts?.cwd ?? projectDir).replace(/\//g, "-").replace(/^-/, "");
|
|
2951
2997
|
const projSettingsDir = path11.join(settingsDir, normalizedKey);
|
|
2952
2998
|
const settingsPath = path11.join(projSettingsDir, "settings.json");
|
|
@@ -2994,7 +3040,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
2994
3040
|
let legacyFallbackWarned = false;
|
|
2995
3041
|
if (!useExeAgent && !useBinSymlink) {
|
|
2996
3042
|
const identityPath = path11.join(
|
|
2997
|
-
|
|
3043
|
+
os6.homedir(),
|
|
2998
3044
|
".exe-os",
|
|
2999
3045
|
"identity",
|
|
3000
3046
|
`${employeeName}.md`
|
|
@@ -3024,7 +3070,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3024
3070
|
}
|
|
3025
3071
|
let sessionContextFlag = "";
|
|
3026
3072
|
try {
|
|
3027
|
-
const ctxDir = path11.join(
|
|
3073
|
+
const ctxDir = path11.join(os6.homedir(), ".exe-os", "session-cache");
|
|
3028
3074
|
mkdirSync6(ctxDir, { recursive: true });
|
|
3029
3075
|
const ctxFile = path11.join(ctxDir, `session-context-${sessionName}.md`);
|
|
3030
3076
|
const ctxContent = [
|
|
@@ -3135,11 +3181,11 @@ var init_tmux_routing = __esm({
|
|
|
3135
3181
|
init_provider_table();
|
|
3136
3182
|
init_intercom_queue();
|
|
3137
3183
|
init_plan_limits();
|
|
3138
|
-
SPAWN_LOCK_DIR = path11.join(
|
|
3139
|
-
SESSION_CACHE = path11.join(
|
|
3184
|
+
SPAWN_LOCK_DIR = path11.join(os6.homedir(), ".exe-os", "spawn-locks");
|
|
3185
|
+
SESSION_CACHE = path11.join(os6.homedir(), ".exe-os", "session-cache");
|
|
3140
3186
|
BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
|
|
3141
3187
|
INTERCOM_DEBOUNCE_MS = 3e4;
|
|
3142
|
-
INTERCOM_LOG2 = path11.join(
|
|
3188
|
+
INTERCOM_LOG2 = path11.join(os6.homedir(), ".exe-os", "intercom.log");
|
|
3143
3189
|
DEBOUNCE_FILE = path11.join(SESSION_CACHE, "intercom-debounce.json");
|
|
3144
3190
|
DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
|
|
3145
3191
|
BUSY_PATTERN = /[✻✽✶✳·].*…|Running…/;
|
|
@@ -4740,6 +4786,7 @@ var init_compress = __esm({
|
|
|
4740
4786
|
// src/lib/cloud-sync.ts
|
|
4741
4787
|
var cloud_sync_exports = {};
|
|
4742
4788
|
__export(cloud_sync_exports, {
|
|
4789
|
+
assertSecureEndpoint: () => assertSecureEndpoint,
|
|
4743
4790
|
buildRosterBlob: () => buildRosterBlob,
|
|
4744
4791
|
cloudPull: () => cloudPull,
|
|
4745
4792
|
cloudPullBehaviors: () => cloudPullBehaviors,
|
|
@@ -4759,9 +4806,10 @@ __export(cloud_sync_exports, {
|
|
|
4759
4806
|
cloudPushTasks: () => cloudPushTasks,
|
|
4760
4807
|
cloudSync: () => cloudSync,
|
|
4761
4808
|
mergeConfig: () => mergeConfig,
|
|
4762
|
-
mergeRosterFromRemote: () => mergeRosterFromRemote
|
|
4809
|
+
mergeRosterFromRemote: () => mergeRosterFromRemote,
|
|
4810
|
+
recordRosterDeletion: () => recordRosterDeletion
|
|
4763
4811
|
});
|
|
4764
|
-
import { readFileSync as readFileSync12, writeFileSync as writeFileSync7, existsSync as existsSync14, readdirSync as readdirSync6, mkdirSync as mkdirSync8, appendFileSync as appendFileSync2 } from "fs";
|
|
4812
|
+
import { readFileSync as readFileSync12, writeFileSync as writeFileSync7, existsSync as existsSync14, readdirSync as readdirSync6, mkdirSync as mkdirSync8, appendFileSync as appendFileSync2, unlinkSync as unlinkSync6 } from "fs";
|
|
4765
4813
|
import path18 from "path";
|
|
4766
4814
|
import { homedir } from "os";
|
|
4767
4815
|
function logError(msg) {
|
|
@@ -4772,16 +4820,47 @@ function logError(msg) {
|
|
|
4772
4820
|
} catch {
|
|
4773
4821
|
}
|
|
4774
4822
|
}
|
|
4823
|
+
async function withRosterLock(fn) {
|
|
4824
|
+
if (existsSync14(ROSTER_LOCK_PATH)) {
|
|
4825
|
+
try {
|
|
4826
|
+
const ts = parseInt(readFileSync12(ROSTER_LOCK_PATH, "utf-8"), 10);
|
|
4827
|
+
if (Date.now() - ts < LOCK_STALE_MS) {
|
|
4828
|
+
throw new Error("Roster merge already in progress \u2014 another sync is running");
|
|
4829
|
+
}
|
|
4830
|
+
} catch (err) {
|
|
4831
|
+
if (err instanceof Error && err.message.includes("already in progress")) throw err;
|
|
4832
|
+
}
|
|
4833
|
+
}
|
|
4834
|
+
writeFileSync7(ROSTER_LOCK_PATH, String(Date.now()));
|
|
4835
|
+
try {
|
|
4836
|
+
return await fn();
|
|
4837
|
+
} finally {
|
|
4838
|
+
try {
|
|
4839
|
+
unlinkSync6(ROSTER_LOCK_PATH);
|
|
4840
|
+
} catch {
|
|
4841
|
+
}
|
|
4842
|
+
}
|
|
4843
|
+
}
|
|
4775
4844
|
async function fetchWithRetry(url, init) {
|
|
4776
|
-
const
|
|
4777
|
-
|
|
4778
|
-
|
|
4779
|
-
|
|
4780
|
-
|
|
4781
|
-
|
|
4782
|
-
|
|
4845
|
+
const MAX_RETRIES2 = 3;
|
|
4846
|
+
const BASE_DELAY_MS2 = 200;
|
|
4847
|
+
let lastError;
|
|
4848
|
+
for (let attempt = 0; attempt <= MAX_RETRIES2; attempt++) {
|
|
4849
|
+
try {
|
|
4850
|
+
const signal = AbortSignal.timeout(FETCH_TIMEOUT_MS);
|
|
4851
|
+
const resp = await fetch(url, { ...init, signal });
|
|
4852
|
+
if (resp.status >= 500 && attempt < MAX_RETRIES2) {
|
|
4853
|
+
await new Promise((r) => setTimeout(r, BASE_DELAY_MS2 * Math.pow(2, attempt)));
|
|
4854
|
+
continue;
|
|
4855
|
+
}
|
|
4856
|
+
return resp;
|
|
4857
|
+
} catch (err) {
|
|
4858
|
+
lastError = err;
|
|
4859
|
+
if (attempt === MAX_RETRIES2) throw err;
|
|
4860
|
+
await new Promise((r) => setTimeout(r, BASE_DELAY_MS2 * Math.pow(2, attempt)));
|
|
4861
|
+
}
|
|
4783
4862
|
}
|
|
4784
|
-
|
|
4863
|
+
throw lastError;
|
|
4785
4864
|
}
|
|
4786
4865
|
function assertSecureEndpoint(endpoint) {
|
|
4787
4866
|
if (endpoint.startsWith("https://")) return;
|
|
@@ -4809,10 +4888,15 @@ async function cloudPush(records, maxVersion, config) {
|
|
|
4809
4888
|
headers: {
|
|
4810
4889
|
Authorization: `Bearer ${config.apiKey}`,
|
|
4811
4890
|
"Content-Type": "application/json",
|
|
4812
|
-
"X-Device-Id": loadDeviceId()
|
|
4891
|
+
"X-Device-Id": loadDeviceId(),
|
|
4892
|
+
"X-Expected-Version": String(maxVersion)
|
|
4813
4893
|
},
|
|
4814
4894
|
body: JSON.stringify({ version: maxVersion, blob })
|
|
4815
4895
|
});
|
|
4896
|
+
if (resp.status === 409) {
|
|
4897
|
+
logError("[cloud-sync] PUSH VERSION CONFLICT \u2014 re-pull required before next push");
|
|
4898
|
+
return false;
|
|
4899
|
+
}
|
|
4816
4900
|
return resp.ok;
|
|
4817
4901
|
} catch (err) {
|
|
4818
4902
|
logError(`[cloud-sync] PUSH FAILED: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -4899,18 +4983,21 @@ async function cloudSync(config) {
|
|
|
4899
4983
|
"SELECT value FROM sync_meta WHERE key = 'last_cloud_push_version'"
|
|
4900
4984
|
);
|
|
4901
4985
|
const lastPushVersion = pushMeta.rows.length > 0 ? Number(pushMeta.rows[0].value) : 0;
|
|
4902
|
-
const recordsResult = await client.execute({
|
|
4903
|
-
sql: `SELECT id, agent_id, agent_role, session_id, timestamp,
|
|
4904
|
-
tool_name, project_name, has_error, raw_text, version,
|
|
4905
|
-
author_device_id, scope
|
|
4906
|
-
FROM memories
|
|
4907
|
-
WHERE version > ?
|
|
4908
|
-
AND (scope IS NULL OR scope != 'personal')
|
|
4909
|
-
ORDER BY version ASC`,
|
|
4910
|
-
args: [lastPushVersion]
|
|
4911
|
-
});
|
|
4912
4986
|
let pushed = 0;
|
|
4913
|
-
|
|
4987
|
+
let batchCursor = lastPushVersion;
|
|
4988
|
+
while (true) {
|
|
4989
|
+
const recordsResult = await client.execute({
|
|
4990
|
+
sql: `SELECT id, agent_id, agent_role, session_id, timestamp,
|
|
4991
|
+
tool_name, project_name, has_error, raw_text, version,
|
|
4992
|
+
author_device_id, scope
|
|
4993
|
+
FROM memories
|
|
4994
|
+
WHERE version > ?
|
|
4995
|
+
AND (scope IS NULL OR scope != 'personal')
|
|
4996
|
+
ORDER BY version ASC
|
|
4997
|
+
LIMIT ?`,
|
|
4998
|
+
args: [batchCursor, PUSH_BATCH_SIZE]
|
|
4999
|
+
});
|
|
5000
|
+
if (recordsResult.rows.length === 0) break;
|
|
4914
5001
|
const records = recordsResult.rows.map((row) => ({
|
|
4915
5002
|
id: row.id,
|
|
4916
5003
|
agent_id: row.agent_id,
|
|
@@ -4927,13 +5014,14 @@ async function cloudSync(config) {
|
|
|
4927
5014
|
}));
|
|
4928
5015
|
const maxVersion = Number(records[records.length - 1].version);
|
|
4929
5016
|
const pushOk = await cloudPush(records, maxVersion, config);
|
|
4930
|
-
if (pushOk)
|
|
4931
|
-
|
|
4932
|
-
|
|
4933
|
-
|
|
4934
|
-
|
|
4935
|
-
|
|
4936
|
-
|
|
5017
|
+
if (!pushOk) break;
|
|
5018
|
+
await client.execute({
|
|
5019
|
+
sql: "INSERT OR REPLACE INTO sync_meta (key, value) VALUES ('last_cloud_push_version', ?)",
|
|
5020
|
+
args: [String(maxVersion)]
|
|
5021
|
+
});
|
|
5022
|
+
pushed += records.length;
|
|
5023
|
+
batchCursor = maxVersion;
|
|
5024
|
+
if (recordsResult.rows.length < PUSH_BATCH_SIZE) break;
|
|
4937
5025
|
}
|
|
4938
5026
|
try {
|
|
4939
5027
|
await cloudPushRoster(config);
|
|
@@ -5015,6 +5103,27 @@ async function cloudSync(config) {
|
|
|
5015
5103
|
documents: documentsResult
|
|
5016
5104
|
};
|
|
5017
5105
|
}
|
|
5106
|
+
function recordRosterDeletion(name) {
|
|
5107
|
+
let deletions = [];
|
|
5108
|
+
try {
|
|
5109
|
+
if (existsSync14(ROSTER_DELETIONS_PATH)) {
|
|
5110
|
+
deletions = JSON.parse(readFileSync12(ROSTER_DELETIONS_PATH, "utf-8"));
|
|
5111
|
+
}
|
|
5112
|
+
} catch {
|
|
5113
|
+
}
|
|
5114
|
+
if (!deletions.includes(name)) deletions.push(name);
|
|
5115
|
+
writeFileSync7(ROSTER_DELETIONS_PATH, JSON.stringify(deletions));
|
|
5116
|
+
}
|
|
5117
|
+
function consumeRosterDeletions() {
|
|
5118
|
+
try {
|
|
5119
|
+
if (!existsSync14(ROSTER_DELETIONS_PATH)) return [];
|
|
5120
|
+
const deletions = JSON.parse(readFileSync12(ROSTER_DELETIONS_PATH, "utf-8"));
|
|
5121
|
+
writeFileSync7(ROSTER_DELETIONS_PATH, "[]");
|
|
5122
|
+
return deletions;
|
|
5123
|
+
} catch {
|
|
5124
|
+
return [];
|
|
5125
|
+
}
|
|
5126
|
+
}
|
|
5018
5127
|
function buildRosterBlob(paths) {
|
|
5019
5128
|
const rosterPath = paths?.rosterPath ?? path18.join(EXE_AI_DIR, "exe-employees.json");
|
|
5020
5129
|
const identityDir = paths?.identityDir ?? path18.join(EXE_AI_DIR, "identity");
|
|
@@ -5042,9 +5151,10 @@ function buildRosterBlob(paths) {
|
|
|
5042
5151
|
} catch {
|
|
5043
5152
|
}
|
|
5044
5153
|
}
|
|
5045
|
-
const
|
|
5154
|
+
const deletedNames = consumeRosterDeletions();
|
|
5155
|
+
const content = JSON.stringify({ roster, identities, config, deletedNames });
|
|
5046
5156
|
const hash = Buffer.from(content).length;
|
|
5047
|
-
return { roster, identities, config, version: hash };
|
|
5157
|
+
return { roster, identities, config, deletedNames, version: hash };
|
|
5048
5158
|
}
|
|
5049
5159
|
async function cloudPushRoster(config) {
|
|
5050
5160
|
assertSecureEndpoint(config.endpoint);
|
|
@@ -5127,38 +5237,50 @@ function mergeConfig(remoteConfig, configPath) {
|
|
|
5127
5237
|
writeFileSync7(cfgPath, JSON.stringify(merged, null, 2), "utf-8");
|
|
5128
5238
|
}
|
|
5129
5239
|
async function mergeRosterFromRemote(remote, paths) {
|
|
5130
|
-
|
|
5131
|
-
|
|
5132
|
-
|
|
5133
|
-
|
|
5134
|
-
|
|
5135
|
-
|
|
5136
|
-
|
|
5137
|
-
|
|
5138
|
-
|
|
5139
|
-
|
|
5140
|
-
|
|
5141
|
-
if (
|
|
5142
|
-
|
|
5143
|
-
|
|
5144
|
-
|
|
5240
|
+
return withRosterLock(async () => {
|
|
5241
|
+
const rosterPath = paths?.rosterPath ?? void 0;
|
|
5242
|
+
const identityDir = paths?.identityDir ?? path18.join(EXE_AI_DIR, "identity");
|
|
5243
|
+
const localEmployees = await loadEmployees(rosterPath);
|
|
5244
|
+
const localNames = new Set(localEmployees.map((e) => e.name));
|
|
5245
|
+
let added = 0;
|
|
5246
|
+
for (const remoteEmp of remote.roster) {
|
|
5247
|
+
if (localNames.has(remoteEmp.name)) continue;
|
|
5248
|
+
localEmployees.push(remoteEmp);
|
|
5249
|
+
localNames.add(remoteEmp.name);
|
|
5250
|
+
added++;
|
|
5251
|
+
if (remote.identities[`${remoteEmp.name}.md`]) {
|
|
5252
|
+
if (!existsSync14(identityDir)) mkdirSync8(identityDir, { recursive: true });
|
|
5253
|
+
const idPath = path18.join(identityDir, `${remoteEmp.name}.md`);
|
|
5254
|
+
if (!existsSync14(idPath)) {
|
|
5255
|
+
writeFileSync7(idPath, remote.identities[`${remoteEmp.name}.md`], "utf-8");
|
|
5256
|
+
}
|
|
5257
|
+
}
|
|
5258
|
+
try {
|
|
5259
|
+
registerBinSymlinks(remoteEmp.name);
|
|
5260
|
+
} catch {
|
|
5145
5261
|
}
|
|
5146
5262
|
}
|
|
5147
|
-
|
|
5148
|
-
|
|
5149
|
-
|
|
5263
|
+
let removed = 0;
|
|
5264
|
+
if (remote.deletedNames && remote.deletedNames.length > 0) {
|
|
5265
|
+
const toRemove = new Set(remote.deletedNames);
|
|
5266
|
+
const filtered = localEmployees.filter((e) => !toRemove.has(e.name));
|
|
5267
|
+
removed = localEmployees.length - filtered.length;
|
|
5268
|
+
if (removed > 0) {
|
|
5269
|
+
localEmployees.length = 0;
|
|
5270
|
+
localEmployees.push(...filtered);
|
|
5271
|
+
}
|
|
5150
5272
|
}
|
|
5151
|
-
|
|
5152
|
-
|
|
5153
|
-
await saveEmployees(localEmployees, rosterPath);
|
|
5154
|
-
}
|
|
5155
|
-
if (remote.config && Object.keys(remote.config).length > 0) {
|
|
5156
|
-
try {
|
|
5157
|
-
mergeConfig(remote.config, paths?.configPath);
|
|
5158
|
-
} catch {
|
|
5273
|
+
if (added > 0 || removed > 0) {
|
|
5274
|
+
await saveEmployees(localEmployees, rosterPath);
|
|
5159
5275
|
}
|
|
5160
|
-
|
|
5161
|
-
|
|
5276
|
+
if (remote.config && Object.keys(remote.config).length > 0) {
|
|
5277
|
+
try {
|
|
5278
|
+
mergeConfig(remote.config, paths?.configPath);
|
|
5279
|
+
} catch {
|
|
5280
|
+
}
|
|
5281
|
+
}
|
|
5282
|
+
return { added };
|
|
5283
|
+
});
|
|
5162
5284
|
}
|
|
5163
5285
|
async function cloudPushBlob(route, data, metaKey, config) {
|
|
5164
5286
|
if (data.length === 0) return { ok: true };
|
|
@@ -5226,7 +5348,7 @@ async function cloudPullBlob(route, config) {
|
|
|
5226
5348
|
}
|
|
5227
5349
|
async function cloudPushBehaviors(config) {
|
|
5228
5350
|
const client = getClient();
|
|
5229
|
-
const result = await client.execute("SELECT * FROM behaviors");
|
|
5351
|
+
const result = await client.execute("SELECT * FROM behaviors LIMIT 10000");
|
|
5230
5352
|
const rows = result.rows;
|
|
5231
5353
|
const { ok } = await cloudPushBlob(
|
|
5232
5354
|
"/sync/push-behaviors",
|
|
@@ -5274,13 +5396,13 @@ async function cloudPullBehaviors(config) {
|
|
|
5274
5396
|
async function cloudPushGraphRAG(config) {
|
|
5275
5397
|
const client = getClient();
|
|
5276
5398
|
const [entities, relationships, aliases, entityMems, relMems, hyperedges, hyperedgeNodes] = await Promise.all([
|
|
5277
|
-
client.execute("SELECT * FROM entities"),
|
|
5278
|
-
client.execute("SELECT * FROM relationships"),
|
|
5279
|
-
client.execute("SELECT * FROM entity_aliases"),
|
|
5280
|
-
client.execute("SELECT * FROM entity_memories"),
|
|
5281
|
-
client.execute("SELECT * FROM relationship_memories"),
|
|
5282
|
-
client.execute("SELECT * FROM hyperedges"),
|
|
5283
|
-
client.execute("SELECT * FROM hyperedge_nodes")
|
|
5399
|
+
client.execute("SELECT * FROM entities LIMIT 50000"),
|
|
5400
|
+
client.execute("SELECT * FROM relationships LIMIT 50000"),
|
|
5401
|
+
client.execute("SELECT * FROM entity_aliases LIMIT 50000"),
|
|
5402
|
+
client.execute("SELECT * FROM entity_memories LIMIT 50000"),
|
|
5403
|
+
client.execute("SELECT * FROM relationship_memories LIMIT 50000"),
|
|
5404
|
+
client.execute("SELECT * FROM hyperedges LIMIT 50000"),
|
|
5405
|
+
client.execute("SELECT * FROM hyperedge_nodes LIMIT 50000")
|
|
5284
5406
|
]);
|
|
5285
5407
|
const blob = {
|
|
5286
5408
|
entities: entities.rows,
|
|
@@ -5382,7 +5504,7 @@ async function cloudPullGraphRAG(config) {
|
|
|
5382
5504
|
}
|
|
5383
5505
|
async function cloudPushTasks(config) {
|
|
5384
5506
|
const client = getClient();
|
|
5385
|
-
const result = await client.execute("SELECT * FROM tasks");
|
|
5507
|
+
const result = await client.execute("SELECT * FROM tasks LIMIT 10000");
|
|
5386
5508
|
const rows = result.rows;
|
|
5387
5509
|
const { ok } = await cloudPushBlob(
|
|
5388
5510
|
"/sync/push-tasks",
|
|
@@ -5428,7 +5550,7 @@ async function cloudPullTasks(config) {
|
|
|
5428
5550
|
}
|
|
5429
5551
|
async function cloudPushConversations(config) {
|
|
5430
5552
|
const client = getClient();
|
|
5431
|
-
const result = await client.execute("SELECT * FROM conversations");
|
|
5553
|
+
const result = await client.execute("SELECT * FROM conversations LIMIT 50000");
|
|
5432
5554
|
const rows = result.rows;
|
|
5433
5555
|
const { ok } = await cloudPushBlob(
|
|
5434
5556
|
"/sync/push-conversations",
|
|
@@ -5478,8 +5600,8 @@ async function cloudPullConversations(config) {
|
|
|
5478
5600
|
async function cloudPushDocuments(config) {
|
|
5479
5601
|
const client = getClient();
|
|
5480
5602
|
const [workspaces, documents] = await Promise.all([
|
|
5481
|
-
client.execute("SELECT * FROM workspaces"),
|
|
5482
|
-
client.execute("SELECT * FROM documents")
|
|
5603
|
+
client.execute("SELECT * FROM workspaces LIMIT 1000"),
|
|
5604
|
+
client.execute("SELECT * FROM documents LIMIT 10000")
|
|
5483
5605
|
]);
|
|
5484
5606
|
const blob = {
|
|
5485
5607
|
workspaces: workspaces.rows,
|
|
@@ -5532,7 +5654,7 @@ async function cloudPullDocuments(config) {
|
|
|
5532
5654
|
}
|
|
5533
5655
|
return { pulled };
|
|
5534
5656
|
}
|
|
5535
|
-
var LOCALHOST_PATTERNS, FETCH_TIMEOUT_MS;
|
|
5657
|
+
var LOCALHOST_PATTERNS, FETCH_TIMEOUT_MS, PUSH_BATCH_SIZE, ROSTER_LOCK_PATH, LOCK_STALE_MS, ROSTER_DELETIONS_PATH;
|
|
5536
5658
|
var init_cloud_sync = __esm({
|
|
5537
5659
|
"src/lib/cloud-sync.ts"() {
|
|
5538
5660
|
"use strict";
|
|
@@ -5545,6 +5667,10 @@ var init_cloud_sync = __esm({
|
|
|
5545
5667
|
init_employees();
|
|
5546
5668
|
LOCALHOST_PATTERNS = /^(localhost|127\.0\.0\.1|\[::1\])$/i;
|
|
5547
5669
|
FETCH_TIMEOUT_MS = 3e4;
|
|
5670
|
+
PUSH_BATCH_SIZE = 5e3;
|
|
5671
|
+
ROSTER_LOCK_PATH = path18.join(EXE_AI_DIR, "roster-merge.lock");
|
|
5672
|
+
LOCK_STALE_MS = 3e4;
|
|
5673
|
+
ROSTER_DELETIONS_PATH = path18.join(EXE_AI_DIR, "roster-deletions.json");
|
|
5548
5674
|
}
|
|
5549
5675
|
});
|
|
5550
5676
|
|
|
@@ -5728,8 +5854,8 @@ var init_schedules = __esm({
|
|
|
5728
5854
|
init_employees();
|
|
5729
5855
|
import path19 from "path";
|
|
5730
5856
|
import { mkdir as mkdir5, writeFile as writeFile6 } from "fs/promises";
|
|
5731
|
-
import { existsSync as existsSync15, readFileSync as readFileSync13, readdirSync as readdirSync7, unlinkSync as
|
|
5732
|
-
import
|
|
5857
|
+
import { existsSync as existsSync15, readFileSync as readFileSync13, readdirSync as readdirSync7, unlinkSync as unlinkSync7 } from "fs";
|
|
5858
|
+
import os7 from "os";
|
|
5733
5859
|
|
|
5734
5860
|
// src/lib/employee-templates.ts
|
|
5735
5861
|
var DEFAULT_EXE = {
|
|
@@ -6285,7 +6411,7 @@ async function boot(options) {
|
|
|
6285
6411
|
for (const f of readdirSync7(exeExeDir)) {
|
|
6286
6412
|
if (f.startsWith("review-") && f.endsWith(".md")) {
|
|
6287
6413
|
try {
|
|
6288
|
-
|
|
6414
|
+
unlinkSync7(path19.join(exeExeDir, f));
|
|
6289
6415
|
} catch {
|
|
6290
6416
|
}
|
|
6291
6417
|
}
|
|
@@ -6795,7 +6921,7 @@ async function boot(options) {
|
|
|
6795
6921
|
]);
|
|
6796
6922
|
try {
|
|
6797
6923
|
const configPath = path19.join(
|
|
6798
|
-
process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path19.join(
|
|
6924
|
+
process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path19.join(os7.homedir(), ".exe-os"),
|
|
6799
6925
|
"config.json"
|
|
6800
6926
|
);
|
|
6801
6927
|
if (existsSync15(configPath)) {
|
|
@@ -6887,8 +7013,8 @@ async function boot(options) {
|
|
|
6887
7013
|
try {
|
|
6888
7014
|
const flagPath = path19.join(EXE_AI_DIR, "session-cache", "needs-backfill");
|
|
6889
7015
|
if (existsSync15(flagPath)) {
|
|
6890
|
-
const { unlinkSync:
|
|
6891
|
-
|
|
7016
|
+
const { unlinkSync: unlinkSync8 } = await import("fs");
|
|
7017
|
+
unlinkSync8(flagPath);
|
|
6892
7018
|
}
|
|
6893
7019
|
} catch {
|
|
6894
7020
|
}
|
|
@@ -6989,7 +7115,7 @@ ${brief}`;
|
|
|
6989
7115
|
console.log(brief);
|
|
6990
7116
|
try {
|
|
6991
7117
|
const configPath2 = path19.join(
|
|
6992
|
-
process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path19.join(
|
|
7118
|
+
process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path19.join(os7.homedir(), ".exe-os"),
|
|
6993
7119
|
"config.json"
|
|
6994
7120
|
);
|
|
6995
7121
|
if (existsSync15(configPath2)) {
|