@askexenow/exe-os 0.9.30 → 0.9.32
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/dist/bin/backfill-conversations.js +135 -7
- package/dist/bin/backfill-responses.js +135 -7
- package/dist/bin/backfill-vectors.js +135 -7
- package/dist/bin/cleanup-stale-review-tasks.js +139 -11
- package/dist/bin/cli.js +812 -486
- package/dist/bin/exe-assign.js +135 -7
- package/dist/bin/exe-boot.js +422 -113
- package/dist/bin/exe-cloud.js +160 -9
- package/dist/bin/exe-dispatch.js +136 -8
- package/dist/bin/exe-doctor.js +255 -13
- package/dist/bin/exe-export-behaviors.js +136 -8
- package/dist/bin/exe-forget.js +136 -8
- package/dist/bin/exe-gateway.js +171 -24
- package/dist/bin/exe-heartbeat.js +141 -13
- package/dist/bin/exe-kill.js +140 -12
- package/dist/bin/exe-launch-agent.js +143 -15
- package/dist/bin/exe-link.js +357 -48
- package/dist/bin/exe-pending-messages.js +136 -8
- package/dist/bin/exe-pending-notifications.js +136 -8
- package/dist/bin/exe-pending-reviews.js +138 -10
- package/dist/bin/exe-review.js +136 -8
- package/dist/bin/exe-search.js +155 -20
- package/dist/bin/exe-session-cleanup.js +166 -38
- package/dist/bin/exe-start-codex.js +142 -14
- package/dist/bin/exe-start-opencode.js +140 -12
- package/dist/bin/exe-status.js +148 -20
- package/dist/bin/exe-team.js +136 -8
- package/dist/bin/git-sweep.js +138 -10
- package/dist/bin/graph-backfill.js +135 -7
- package/dist/bin/graph-export.js +136 -8
- package/dist/bin/intercom-check.js +153 -25
- package/dist/bin/scan-tasks.js +138 -10
- package/dist/bin/setup.js +447 -121
- package/dist/bin/shard-migrate.js +135 -7
- package/dist/gateway/index.js +151 -23
- package/dist/hooks/bug-report-worker.js +151 -23
- package/dist/hooks/codex-stop-task-finalizer.js +145 -17
- package/dist/hooks/commit-complete.js +138 -10
- package/dist/hooks/error-recall.js +159 -24
- package/dist/hooks/ingest.js +142 -14
- package/dist/hooks/instructions-loaded.js +136 -8
- package/dist/hooks/notification.js +136 -8
- package/dist/hooks/post-compact.js +136 -8
- package/dist/hooks/post-tool-combined.js +159 -24
- package/dist/hooks/pre-compact.js +136 -8
- package/dist/hooks/pre-tool-use.js +144 -16
- package/dist/hooks/prompt-submit.js +195 -55
- package/dist/hooks/session-end.js +141 -13
- package/dist/hooks/session-start.js +165 -30
- package/dist/hooks/stop.js +136 -8
- package/dist/hooks/subagent-stop.js +136 -8
- package/dist/hooks/summary-worker.js +374 -65
- package/dist/index.js +136 -8
- package/dist/lib/cloud-sync.js +355 -46
- package/dist/lib/consolidation.js +1 -0
- package/dist/lib/exe-daemon.js +469 -127
- package/dist/lib/hybrid-search.js +155 -20
- package/dist/lib/keychain.js +191 -7
- package/dist/lib/schedules.js +138 -10
- package/dist/lib/store.js +135 -7
- package/dist/mcp/server.js +706 -213
- package/dist/runtime/index.js +136 -8
- package/dist/tui/App.js +208 -31
- package/package.json +1 -1
package/dist/bin/setup.js
CHANGED
|
@@ -304,6 +304,7 @@ __export(keychain_exports, {
|
|
|
304
304
|
});
|
|
305
305
|
import { readFile as readFile2, writeFile as writeFile2, unlink, mkdir as mkdir2, chmod as chmod2 } from "fs/promises";
|
|
306
306
|
import { existsSync as existsSync3 } from "fs";
|
|
307
|
+
import { execSync } from "child_process";
|
|
307
308
|
import path2 from "path";
|
|
308
309
|
import os2 from "os";
|
|
309
310
|
function getKeyDir() {
|
|
@@ -312,6 +313,83 @@ function getKeyDir() {
|
|
|
312
313
|
function getKeyPath() {
|
|
313
314
|
return path2.join(getKeyDir(), "master.key");
|
|
314
315
|
}
|
|
316
|
+
function macKeychainGet() {
|
|
317
|
+
if (process.platform !== "darwin") return null;
|
|
318
|
+
try {
|
|
319
|
+
return execSync(
|
|
320
|
+
`security find-generic-password -s "${SERVICE}" -a "${ACCOUNT}" -w 2>/dev/null`,
|
|
321
|
+
{ encoding: "utf-8", timeout: 5e3 }
|
|
322
|
+
).trim();
|
|
323
|
+
} catch {
|
|
324
|
+
return null;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
function macKeychainSet(value) {
|
|
328
|
+
if (process.platform !== "darwin") return false;
|
|
329
|
+
try {
|
|
330
|
+
try {
|
|
331
|
+
execSync(
|
|
332
|
+
`security delete-generic-password -s "${SERVICE}" -a "${ACCOUNT}" 2>/dev/null`,
|
|
333
|
+
{ timeout: 5e3 }
|
|
334
|
+
);
|
|
335
|
+
} catch {
|
|
336
|
+
}
|
|
337
|
+
execSync(
|
|
338
|
+
`security add-generic-password -s "${SERVICE}" -a "${ACCOUNT}" -w "${value}"`,
|
|
339
|
+
{ timeout: 5e3 }
|
|
340
|
+
);
|
|
341
|
+
return true;
|
|
342
|
+
} catch {
|
|
343
|
+
return false;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
function macKeychainDelete() {
|
|
347
|
+
if (process.platform !== "darwin") return false;
|
|
348
|
+
try {
|
|
349
|
+
execSync(
|
|
350
|
+
`security delete-generic-password -s "${SERVICE}" -a "${ACCOUNT}" 2>/dev/null`,
|
|
351
|
+
{ timeout: 5e3 }
|
|
352
|
+
);
|
|
353
|
+
return true;
|
|
354
|
+
} catch {
|
|
355
|
+
return false;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
function linuxSecretGet() {
|
|
359
|
+
if (process.platform !== "linux") return null;
|
|
360
|
+
try {
|
|
361
|
+
return execSync(
|
|
362
|
+
`secret-tool lookup service "${SERVICE}" account "${ACCOUNT}" 2>/dev/null`,
|
|
363
|
+
{ encoding: "utf-8", timeout: 5e3 }
|
|
364
|
+
).trim();
|
|
365
|
+
} catch {
|
|
366
|
+
return null;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
function linuxSecretSet(value) {
|
|
370
|
+
if (process.platform !== "linux") return false;
|
|
371
|
+
try {
|
|
372
|
+
execSync(
|
|
373
|
+
`echo -n "${value}" | secret-tool store --label="exe-os master key" service "${SERVICE}" account "${ACCOUNT}"`,
|
|
374
|
+
{ timeout: 5e3 }
|
|
375
|
+
);
|
|
376
|
+
return true;
|
|
377
|
+
} catch {
|
|
378
|
+
return false;
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
function linuxSecretDelete() {
|
|
382
|
+
if (process.platform !== "linux") return false;
|
|
383
|
+
try {
|
|
384
|
+
execSync(
|
|
385
|
+
`secret-tool clear service "${SERVICE}" account "${ACCOUNT}" 2>/dev/null`,
|
|
386
|
+
{ timeout: 5e3 }
|
|
387
|
+
);
|
|
388
|
+
return true;
|
|
389
|
+
} catch {
|
|
390
|
+
return false;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
315
393
|
async function tryKeytar() {
|
|
316
394
|
try {
|
|
317
395
|
return await import("keytar");
|
|
@@ -319,13 +397,72 @@ async function tryKeytar() {
|
|
|
319
397
|
return null;
|
|
320
398
|
}
|
|
321
399
|
}
|
|
400
|
+
function deriveMachineKey() {
|
|
401
|
+
try {
|
|
402
|
+
const crypto5 = __require("crypto");
|
|
403
|
+
const material = [
|
|
404
|
+
os2.hostname(),
|
|
405
|
+
os2.userInfo().username,
|
|
406
|
+
os2.arch(),
|
|
407
|
+
os2.platform(),
|
|
408
|
+
// Machine ID on Linux (stable across reboots)
|
|
409
|
+
process.platform === "linux" ? readMachineId() : ""
|
|
410
|
+
].join("|");
|
|
411
|
+
return crypto5.createHash("sha256").update(material).digest();
|
|
412
|
+
} catch {
|
|
413
|
+
return null;
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
function readMachineId() {
|
|
417
|
+
try {
|
|
418
|
+
const { readFileSync: readFileSync13 } = __require("fs");
|
|
419
|
+
return readFileSync13("/etc/machine-id", "utf-8").trim();
|
|
420
|
+
} catch {
|
|
421
|
+
return "";
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
function encryptWithMachineKey(plaintext, machineKey) {
|
|
425
|
+
const crypto5 = __require("crypto");
|
|
426
|
+
const iv = crypto5.randomBytes(12);
|
|
427
|
+
const cipher = crypto5.createCipheriv("aes-256-gcm", machineKey, iv);
|
|
428
|
+
let encrypted = cipher.update(plaintext, "utf-8", "base64");
|
|
429
|
+
encrypted += cipher.final("base64");
|
|
430
|
+
const authTag = cipher.getAuthTag().toString("base64");
|
|
431
|
+
return `${ENCRYPTED_PREFIX}${iv.toString("base64")}:${authTag}:${encrypted}`;
|
|
432
|
+
}
|
|
433
|
+
function decryptWithMachineKey(encrypted, machineKey) {
|
|
434
|
+
if (!encrypted.startsWith(ENCRYPTED_PREFIX)) return null;
|
|
435
|
+
try {
|
|
436
|
+
const crypto5 = __require("crypto");
|
|
437
|
+
const parts = encrypted.slice(ENCRYPTED_PREFIX.length).split(":");
|
|
438
|
+
if (parts.length !== 3) return null;
|
|
439
|
+
const [ivB64, tagB64, cipherB64] = parts;
|
|
440
|
+
const iv = Buffer.from(ivB64, "base64");
|
|
441
|
+
const authTag = Buffer.from(tagB64, "base64");
|
|
442
|
+
const decipher = crypto5.createDecipheriv("aes-256-gcm", machineKey, iv);
|
|
443
|
+
decipher.setAuthTag(authTag);
|
|
444
|
+
let decrypted = decipher.update(cipherB64, "base64", "utf-8");
|
|
445
|
+
decrypted += decipher.final("utf-8");
|
|
446
|
+
return decrypted;
|
|
447
|
+
} catch {
|
|
448
|
+
return null;
|
|
449
|
+
}
|
|
450
|
+
}
|
|
322
451
|
async function getMasterKey() {
|
|
452
|
+
const nativeValue = macKeychainGet() ?? linuxSecretGet();
|
|
453
|
+
if (nativeValue) {
|
|
454
|
+
return Buffer.from(nativeValue, "base64");
|
|
455
|
+
}
|
|
323
456
|
const keytar = await tryKeytar();
|
|
324
457
|
if (keytar) {
|
|
325
458
|
try {
|
|
326
|
-
const
|
|
327
|
-
if (
|
|
328
|
-
|
|
459
|
+
const keytarValue = await keytar.getPassword(SERVICE, ACCOUNT);
|
|
460
|
+
if (keytarValue) {
|
|
461
|
+
const migrated = macKeychainSet(keytarValue) || linuxSecretSet(keytarValue);
|
|
462
|
+
if (migrated) {
|
|
463
|
+
process.stderr.write("[keychain] Migrated key from keytar to native keychain.\n");
|
|
464
|
+
}
|
|
465
|
+
return Buffer.from(keytarValue, "base64");
|
|
329
466
|
}
|
|
330
467
|
} catch {
|
|
331
468
|
}
|
|
@@ -339,8 +476,31 @@ async function getMasterKey() {
|
|
|
339
476
|
return null;
|
|
340
477
|
}
|
|
341
478
|
try {
|
|
342
|
-
const content = await readFile2(keyPath, "utf-8");
|
|
343
|
-
|
|
479
|
+
const content = (await readFile2(keyPath, "utf-8")).trim();
|
|
480
|
+
let b64Value;
|
|
481
|
+
if (content.startsWith(ENCRYPTED_PREFIX)) {
|
|
482
|
+
const machineKey = deriveMachineKey();
|
|
483
|
+
if (!machineKey) {
|
|
484
|
+
process.stderr.write("[keychain] Cannot derive machine key to decrypt stored key.\n");
|
|
485
|
+
return null;
|
|
486
|
+
}
|
|
487
|
+
const decrypted = decryptWithMachineKey(content, machineKey);
|
|
488
|
+
if (!decrypted) {
|
|
489
|
+
process.stderr.write(
|
|
490
|
+
"[keychain] Key decryption failed \u2014 machine may have changed.\n Use your 24-word recovery phrase: exe-os link import\n"
|
|
491
|
+
);
|
|
492
|
+
return null;
|
|
493
|
+
}
|
|
494
|
+
b64Value = decrypted;
|
|
495
|
+
} else {
|
|
496
|
+
b64Value = content;
|
|
497
|
+
}
|
|
498
|
+
const key = Buffer.from(b64Value, "base64");
|
|
499
|
+
const migrated = macKeychainSet(b64Value) || linuxSecretSet(b64Value);
|
|
500
|
+
if (migrated) {
|
|
501
|
+
process.stderr.write("[keychain] Migrated key from file to native keychain.\n");
|
|
502
|
+
}
|
|
503
|
+
return key;
|
|
344
504
|
} catch (err) {
|
|
345
505
|
process.stderr.write(
|
|
346
506
|
`[keychain] Key read failed at ${keyPath}: ${err instanceof Error ? err.message : String(err)}
|
|
@@ -351,6 +511,9 @@ async function getMasterKey() {
|
|
|
351
511
|
}
|
|
352
512
|
async function setMasterKey(key) {
|
|
353
513
|
const b64 = key.toString("base64");
|
|
514
|
+
if (macKeychainSet(b64) || linuxSecretSet(b64)) {
|
|
515
|
+
return;
|
|
516
|
+
}
|
|
354
517
|
const keytar = await tryKeytar();
|
|
355
518
|
if (keytar) {
|
|
356
519
|
try {
|
|
@@ -362,10 +525,23 @@ async function setMasterKey(key) {
|
|
|
362
525
|
const dir = getKeyDir();
|
|
363
526
|
await mkdir2(dir, { recursive: true });
|
|
364
527
|
const keyPath = getKeyPath();
|
|
365
|
-
|
|
366
|
-
|
|
528
|
+
const machineKey = deriveMachineKey();
|
|
529
|
+
if (machineKey) {
|
|
530
|
+
const encrypted = encryptWithMachineKey(b64, machineKey);
|
|
531
|
+
await writeFile2(keyPath, encrypted + "\n", "utf-8");
|
|
532
|
+
await chmod2(keyPath, 384);
|
|
533
|
+
process.stderr.write("[keychain] Key stored encrypted (machine-bound).\n");
|
|
534
|
+
} else {
|
|
535
|
+
await writeFile2(keyPath, b64 + "\n", "utf-8");
|
|
536
|
+
await chmod2(keyPath, 384);
|
|
537
|
+
process.stderr.write(
|
|
538
|
+
"[keychain] WARNING: Key stored in plaintext file \u2014 no OS keychain available.\n"
|
|
539
|
+
);
|
|
540
|
+
}
|
|
367
541
|
}
|
|
368
542
|
async function deleteMasterKey() {
|
|
543
|
+
macKeychainDelete();
|
|
544
|
+
linuxSecretDelete();
|
|
369
545
|
const keytar = await tryKeytar();
|
|
370
546
|
if (keytar) {
|
|
371
547
|
try {
|
|
@@ -407,12 +583,13 @@ async function importMnemonic(mnemonic) {
|
|
|
407
583
|
const entropy = mnemonicToEntropy(trimmed);
|
|
408
584
|
return Buffer.from(entropy, "hex");
|
|
409
585
|
}
|
|
410
|
-
var SERVICE, ACCOUNT;
|
|
586
|
+
var SERVICE, ACCOUNT, ENCRYPTED_PREFIX;
|
|
411
587
|
var init_keychain = __esm({
|
|
412
588
|
"src/lib/keychain.ts"() {
|
|
413
589
|
"use strict";
|
|
414
590
|
SERVICE = "exe-mem";
|
|
415
591
|
ACCOUNT = "master-key";
|
|
592
|
+
ENCRYPTED_PREFIX = "enc:";
|
|
416
593
|
}
|
|
417
594
|
});
|
|
418
595
|
|
|
@@ -530,8 +707,8 @@ function findPackageRoot() {
|
|
|
530
707
|
function getAvailableMemoryGB() {
|
|
531
708
|
if (process.platform === "darwin") {
|
|
532
709
|
try {
|
|
533
|
-
const { execSync:
|
|
534
|
-
const vmstat =
|
|
710
|
+
const { execSync: execSync3 } = __require("child_process");
|
|
711
|
+
const vmstat = execSync3("vm_stat", { encoding: "utf8" });
|
|
535
712
|
const pageSize = 16384;
|
|
536
713
|
const pageSizeMatch = vmstat.match(/page size of (\d+) bytes/);
|
|
537
714
|
const actualPageSize = pageSizeMatch ? parseInt(pageSizeMatch[1], 10) : pageSize;
|
|
@@ -931,10 +1108,10 @@ async function disposeEmbedder() {
|
|
|
931
1108
|
async function embedDirect(text) {
|
|
932
1109
|
const llamaCpp = await import("node-llama-cpp");
|
|
933
1110
|
const { MODELS_DIR: MODELS_DIR2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
934
|
-
const { existsSync:
|
|
935
|
-
const
|
|
936
|
-
const modelPath =
|
|
937
|
-
if (!
|
|
1111
|
+
const { existsSync: existsSync17 } = await import("fs");
|
|
1112
|
+
const path17 = await import("path");
|
|
1113
|
+
const modelPath = path17.join(MODELS_DIR2, "jina-embeddings-v5-small-q4_k_m.gguf");
|
|
1114
|
+
if (!existsSync17(modelPath)) {
|
|
938
1115
|
throw new Error(`Embedding model not found at ${modelPath}. Run '/exe-setup' to download it.`);
|
|
939
1116
|
}
|
|
940
1117
|
const llama = await llamaCpp.getLlama();
|
|
@@ -1223,8 +1400,8 @@ async function validateLicense(apiKey, deviceId) {
|
|
|
1223
1400
|
}
|
|
1224
1401
|
function getCacheAgeMs() {
|
|
1225
1402
|
try {
|
|
1226
|
-
const { statSync:
|
|
1227
|
-
const s =
|
|
1403
|
+
const { statSync: statSync3 } = __require("fs");
|
|
1404
|
+
const s = statSync3(CACHE_PATH);
|
|
1228
1405
|
return Date.now() - s.mtimeMs;
|
|
1229
1406
|
} catch {
|
|
1230
1407
|
return Infinity;
|
|
@@ -1687,7 +1864,7 @@ __export(employees_exports, {
|
|
|
1687
1864
|
});
|
|
1688
1865
|
import { readFile as readFile3, writeFile as writeFile3, mkdir as mkdir4 } from "fs/promises";
|
|
1689
1866
|
import { existsSync as existsSync9, symlinkSync, readlinkSync, readFileSync as readFileSync6, renameSync as renameSync3, unlinkSync as unlinkSync3, writeFileSync as writeFileSync4 } from "fs";
|
|
1690
|
-
import { execSync } from "child_process";
|
|
1867
|
+
import { execSync as execSync2 } from "child_process";
|
|
1691
1868
|
import path8 from "path";
|
|
1692
1869
|
import os5 from "os";
|
|
1693
1870
|
function normalizeRole(role) {
|
|
@@ -1862,7 +2039,7 @@ async function normalizeRosterCase(rosterPath) {
|
|
|
1862
2039
|
}
|
|
1863
2040
|
function findExeBin() {
|
|
1864
2041
|
try {
|
|
1865
|
-
return
|
|
2042
|
+
return execSync2(process.platform === "win32" ? "where exe-os" : "which exe-os", { encoding: "utf8" }).trim();
|
|
1866
2043
|
} catch {
|
|
1867
2044
|
return null;
|
|
1868
2045
|
}
|
|
@@ -4062,6 +4239,109 @@ var init_crdt_sync = __esm({
|
|
|
4062
4239
|
}
|
|
4063
4240
|
});
|
|
4064
4241
|
|
|
4242
|
+
// src/lib/db-backup.ts
|
|
4243
|
+
var db_backup_exports = {};
|
|
4244
|
+
__export(db_backup_exports, {
|
|
4245
|
+
createBackup: () => createBackup,
|
|
4246
|
+
findActiveDb: () => findActiveDb,
|
|
4247
|
+
getBackupDir: () => getBackupDir,
|
|
4248
|
+
getLatestBackup: () => getLatestBackup,
|
|
4249
|
+
hasBackupToday: () => hasBackupToday,
|
|
4250
|
+
listBackups: () => listBackups,
|
|
4251
|
+
rotateBackups: () => rotateBackups
|
|
4252
|
+
});
|
|
4253
|
+
import { copyFileSync, existsSync as existsSync11, mkdirSync as mkdirSync4, readdirSync, unlinkSync as unlinkSync5, statSync as statSync2 } from "fs";
|
|
4254
|
+
import path11 from "path";
|
|
4255
|
+
function findActiveDb() {
|
|
4256
|
+
for (const name of DB_NAMES) {
|
|
4257
|
+
const p = path11.join(EXE_AI_DIR, name);
|
|
4258
|
+
if (existsSync11(p)) return p;
|
|
4259
|
+
}
|
|
4260
|
+
return null;
|
|
4261
|
+
}
|
|
4262
|
+
function createBackup(reason = "manual") {
|
|
4263
|
+
const dbPath = findActiveDb();
|
|
4264
|
+
if (!dbPath) return null;
|
|
4265
|
+
mkdirSync4(BACKUP_DIR, { recursive: true });
|
|
4266
|
+
const dbName = path11.basename(dbPath, ".db");
|
|
4267
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
4268
|
+
const backupName = `${dbName}-${reason}-${timestamp}.db`;
|
|
4269
|
+
const backupPath = path11.join(BACKUP_DIR, backupName);
|
|
4270
|
+
copyFileSync(dbPath, backupPath);
|
|
4271
|
+
const walPath = dbPath + "-wal";
|
|
4272
|
+
if (existsSync11(walPath)) {
|
|
4273
|
+
try {
|
|
4274
|
+
copyFileSync(walPath, backupPath + "-wal");
|
|
4275
|
+
} catch {
|
|
4276
|
+
}
|
|
4277
|
+
}
|
|
4278
|
+
const shmPath = dbPath + "-shm";
|
|
4279
|
+
if (existsSync11(shmPath)) {
|
|
4280
|
+
try {
|
|
4281
|
+
copyFileSync(shmPath, backupPath + "-shm");
|
|
4282
|
+
} catch {
|
|
4283
|
+
}
|
|
4284
|
+
}
|
|
4285
|
+
return backupPath;
|
|
4286
|
+
}
|
|
4287
|
+
function rotateBackups(keepDays = DEFAULT_KEEP_DAYS) {
|
|
4288
|
+
if (!existsSync11(BACKUP_DIR)) return 0;
|
|
4289
|
+
const cutoff = Date.now() - keepDays * 24 * 60 * 60 * 1e3;
|
|
4290
|
+
let deleted = 0;
|
|
4291
|
+
try {
|
|
4292
|
+
const files = readdirSync(BACKUP_DIR);
|
|
4293
|
+
for (const file of files) {
|
|
4294
|
+
if (!file.endsWith(".db") && !file.endsWith(".db-wal") && !file.endsWith(".db-shm")) continue;
|
|
4295
|
+
const filePath = path11.join(BACKUP_DIR, file);
|
|
4296
|
+
try {
|
|
4297
|
+
const stat = statSync2(filePath);
|
|
4298
|
+
if (stat.mtimeMs < cutoff) {
|
|
4299
|
+
unlinkSync5(filePath);
|
|
4300
|
+
deleted++;
|
|
4301
|
+
}
|
|
4302
|
+
} catch {
|
|
4303
|
+
}
|
|
4304
|
+
}
|
|
4305
|
+
} catch {
|
|
4306
|
+
}
|
|
4307
|
+
return deleted;
|
|
4308
|
+
}
|
|
4309
|
+
function listBackups() {
|
|
4310
|
+
if (!existsSync11(BACKUP_DIR)) return [];
|
|
4311
|
+
try {
|
|
4312
|
+
const files = readdirSync(BACKUP_DIR).filter((f) => f.endsWith(".db") && !f.endsWith("-wal") && !f.endsWith("-shm"));
|
|
4313
|
+
return files.map((name) => {
|
|
4314
|
+
const p = path11.join(BACKUP_DIR, name);
|
|
4315
|
+
const stat = statSync2(p);
|
|
4316
|
+
return { path: p, name, size: stat.size, date: stat.mtime };
|
|
4317
|
+
}).sort((a, b) => b.date.getTime() - a.date.getTime());
|
|
4318
|
+
} catch {
|
|
4319
|
+
return [];
|
|
4320
|
+
}
|
|
4321
|
+
}
|
|
4322
|
+
function hasBackupToday(reason) {
|
|
4323
|
+
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
4324
|
+
const backups = listBackups();
|
|
4325
|
+
return backups.some((b) => b.name.includes(reason) && b.name.includes(today.replace(/-/g, "-")));
|
|
4326
|
+
}
|
|
4327
|
+
function getLatestBackup() {
|
|
4328
|
+
const backups = listBackups();
|
|
4329
|
+
return backups.length > 0 ? backups[0].path : null;
|
|
4330
|
+
}
|
|
4331
|
+
function getBackupDir() {
|
|
4332
|
+
return BACKUP_DIR;
|
|
4333
|
+
}
|
|
4334
|
+
var BACKUP_DIR, DEFAULT_KEEP_DAYS, DB_NAMES;
|
|
4335
|
+
var init_db_backup = __esm({
|
|
4336
|
+
"src/lib/db-backup.ts"() {
|
|
4337
|
+
"use strict";
|
|
4338
|
+
init_config();
|
|
4339
|
+
BACKUP_DIR = path11.join(EXE_AI_DIR, "backups");
|
|
4340
|
+
DEFAULT_KEEP_DAYS = 3;
|
|
4341
|
+
DB_NAMES = ["memories.db", "exe-mem.db", "exe-os.db", "exe.db"];
|
|
4342
|
+
}
|
|
4343
|
+
});
|
|
4344
|
+
|
|
4065
4345
|
// src/lib/cloud-sync.ts
|
|
4066
4346
|
var cloud_sync_exports = {};
|
|
4067
4347
|
__export(cloud_sync_exports, {
|
|
@@ -4091,16 +4371,16 @@ __export(cloud_sync_exports, {
|
|
|
4091
4371
|
pushToPostgres: () => pushToPostgres,
|
|
4092
4372
|
recordRosterDeletion: () => recordRosterDeletion
|
|
4093
4373
|
});
|
|
4094
|
-
import { readFileSync as readFileSync8, writeFileSync as writeFileSync6, existsSync as
|
|
4374
|
+
import { readFileSync as readFileSync8, writeFileSync as writeFileSync6, existsSync as existsSync12, readdirSync as readdirSync2, mkdirSync as mkdirSync5, appendFileSync, unlinkSync as unlinkSync6, openSync as openSync2, closeSync as closeSync2 } from "fs";
|
|
4095
4375
|
import crypto3 from "crypto";
|
|
4096
|
-
import
|
|
4376
|
+
import path12 from "path";
|
|
4097
4377
|
import { homedir as homedir2 } from "os";
|
|
4098
4378
|
function sqlSafe(v) {
|
|
4099
4379
|
return v === void 0 ? null : v;
|
|
4100
4380
|
}
|
|
4101
4381
|
function logError(msg) {
|
|
4102
4382
|
try {
|
|
4103
|
-
const logPath =
|
|
4383
|
+
const logPath = path12.join(homedir2(), ".exe-os", "workers.log");
|
|
4104
4384
|
appendFileSync(logPath, `${(/* @__PURE__ */ new Date()).toISOString()} ${msg}
|
|
4105
4385
|
`);
|
|
4106
4386
|
} catch {
|
|
@@ -4109,10 +4389,10 @@ function logError(msg) {
|
|
|
4109
4389
|
function loadPgClient() {
|
|
4110
4390
|
if (_pgFailed) return null;
|
|
4111
4391
|
const postgresUrl = process.env.DATABASE_URL;
|
|
4112
|
-
const configPath =
|
|
4392
|
+
const configPath = path12.join(EXE_AI_DIR, "config.json");
|
|
4113
4393
|
let cloudPostgresUrl;
|
|
4114
4394
|
try {
|
|
4115
|
-
if (
|
|
4395
|
+
if (existsSync12(configPath)) {
|
|
4116
4396
|
const cfg = JSON.parse(readFileSync8(configPath, "utf8"));
|
|
4117
4397
|
cloudPostgresUrl = cfg.cloud?.postgresUrl;
|
|
4118
4398
|
if (cfg.cloud?.syncToPostgres === false) {
|
|
@@ -4131,8 +4411,8 @@ function loadPgClient() {
|
|
|
4131
4411
|
_pgPromise = (async () => {
|
|
4132
4412
|
const { createRequire: createRequire3 } = await import("module");
|
|
4133
4413
|
const { pathToFileURL: pathToFileURL3 } = await import("url");
|
|
4134
|
-
const exeDbRoot = process.env.EXE_DB_ROOT ??
|
|
4135
|
-
const req = createRequire3(
|
|
4414
|
+
const exeDbRoot = process.env.EXE_DB_ROOT ?? path12.join(homedir2(), "exe-db");
|
|
4415
|
+
const req = createRequire3(path12.join(exeDbRoot, "package.json"));
|
|
4136
4416
|
const entry = req.resolve("@prisma/client");
|
|
4137
4417
|
const mod = await import(pathToFileURL3(entry).href);
|
|
4138
4418
|
const Ctor = mod.PrismaClient ?? mod.default?.PrismaClient;
|
|
@@ -4185,7 +4465,7 @@ async function withRosterLock(fn) {
|
|
|
4185
4465
|
if (Date.now() - ts < LOCK_STALE_MS) {
|
|
4186
4466
|
throw new Error("Roster merge already in progress \u2014 another sync is running");
|
|
4187
4467
|
}
|
|
4188
|
-
|
|
4468
|
+
unlinkSync6(ROSTER_LOCK_PATH);
|
|
4189
4469
|
const fd = openSync2(ROSTER_LOCK_PATH, "wx");
|
|
4190
4470
|
closeSync2(fd);
|
|
4191
4471
|
writeFileSync6(ROSTER_LOCK_PATH, String(Date.now()));
|
|
@@ -4201,7 +4481,7 @@ async function withRosterLock(fn) {
|
|
|
4201
4481
|
return await fn();
|
|
4202
4482
|
} finally {
|
|
4203
4483
|
try {
|
|
4204
|
-
|
|
4484
|
+
unlinkSync6(ROSTER_LOCK_PATH);
|
|
4205
4485
|
} catch {
|
|
4206
4486
|
}
|
|
4207
4487
|
}
|
|
@@ -4572,13 +4852,42 @@ async function cloudSync(config) {
|
|
|
4572
4852
|
try {
|
|
4573
4853
|
const employees = await loadEmployees();
|
|
4574
4854
|
rosterResult.employees = employees.length;
|
|
4575
|
-
const idDir =
|
|
4576
|
-
if (
|
|
4577
|
-
rosterResult.identities =
|
|
4855
|
+
const idDir = path12.join(EXE_AI_DIR, "identity");
|
|
4856
|
+
if (existsSync12(idDir)) {
|
|
4857
|
+
rosterResult.identities = readdirSync2(idDir).filter((f) => f.endsWith(".md")).length;
|
|
4578
4858
|
}
|
|
4579
4859
|
} catch {
|
|
4580
4860
|
}
|
|
4581
4861
|
const totalMemories = await countRows("SELECT COUNT(*) as cnt FROM memories WHERE status = 'active' OR status IS NULL");
|
|
4862
|
+
try {
|
|
4863
|
+
const { getLatestBackup: getLatestBackup2 } = await Promise.resolve().then(() => (init_db_backup(), db_backup_exports));
|
|
4864
|
+
const { statSync: statFile } = await import("fs");
|
|
4865
|
+
const latestBackup = getLatestBackup2();
|
|
4866
|
+
if (latestBackup) {
|
|
4867
|
+
const backupSize = statFile(latestBackup).size;
|
|
4868
|
+
const MAX_CLOUD_BACKUP_BYTES = 50 * 1024 * 1024;
|
|
4869
|
+
if (backupSize <= MAX_CLOUD_BACKUP_BYTES) {
|
|
4870
|
+
const backupData = readFileSync8(latestBackup);
|
|
4871
|
+
const deviceId = loadDeviceId() ?? "unknown";
|
|
4872
|
+
const encrypted = encryptSyncBlob(backupData);
|
|
4873
|
+
const backupRes = await fetchWithRetry(`${config.endpoint}/sync/push-db-backup`, {
|
|
4874
|
+
method: "POST",
|
|
4875
|
+
headers: { "Content-Type": "application/json", Authorization: `Bearer ${config.apiKey}` },
|
|
4876
|
+
body: JSON.stringify({
|
|
4877
|
+
device_id: deviceId,
|
|
4878
|
+
filename: path12.basename(latestBackup),
|
|
4879
|
+
blob: encrypted,
|
|
4880
|
+
size: backupData.length
|
|
4881
|
+
})
|
|
4882
|
+
});
|
|
4883
|
+
if (backupRes && !backupRes.ok) {
|
|
4884
|
+
logError(`[cloud-sync] DB backup upload failed: ${backupRes.status}`);
|
|
4885
|
+
}
|
|
4886
|
+
}
|
|
4887
|
+
}
|
|
4888
|
+
} catch (err) {
|
|
4889
|
+
logError(`[cloud-sync] DB backup upload error: ${err instanceof Error ? err.message : String(err)}`);
|
|
4890
|
+
}
|
|
4582
4891
|
return {
|
|
4583
4892
|
pushed,
|
|
4584
4893
|
pulled,
|
|
@@ -4594,7 +4903,7 @@ async function cloudSync(config) {
|
|
|
4594
4903
|
function recordRosterDeletion(name) {
|
|
4595
4904
|
let deletions = [];
|
|
4596
4905
|
try {
|
|
4597
|
-
if (
|
|
4906
|
+
if (existsSync12(ROSTER_DELETIONS_PATH)) {
|
|
4598
4907
|
deletions = JSON.parse(readFileSync8(ROSTER_DELETIONS_PATH, "utf-8"));
|
|
4599
4908
|
}
|
|
4600
4909
|
} catch {
|
|
@@ -4604,7 +4913,7 @@ function recordRosterDeletion(name) {
|
|
|
4604
4913
|
}
|
|
4605
4914
|
function consumeRosterDeletions() {
|
|
4606
4915
|
try {
|
|
4607
|
-
if (!
|
|
4916
|
+
if (!existsSync12(ROSTER_DELETIONS_PATH)) return [];
|
|
4608
4917
|
const deletions = JSON.parse(readFileSync8(ROSTER_DELETIONS_PATH, "utf-8"));
|
|
4609
4918
|
writeFileSync6(ROSTER_DELETIONS_PATH, "[]");
|
|
4610
4919
|
return deletions;
|
|
@@ -4613,35 +4922,35 @@ function consumeRosterDeletions() {
|
|
|
4613
4922
|
}
|
|
4614
4923
|
}
|
|
4615
4924
|
function buildRosterBlob(paths) {
|
|
4616
|
-
const rosterPath = paths?.rosterPath ??
|
|
4617
|
-
const identityDir = paths?.identityDir ??
|
|
4618
|
-
const configPath = paths?.configPath ??
|
|
4925
|
+
const rosterPath = paths?.rosterPath ?? path12.join(EXE_AI_DIR, "exe-employees.json");
|
|
4926
|
+
const identityDir = paths?.identityDir ?? path12.join(EXE_AI_DIR, "identity");
|
|
4927
|
+
const configPath = paths?.configPath ?? path12.join(EXE_AI_DIR, "config.json");
|
|
4619
4928
|
let roster = [];
|
|
4620
|
-
if (
|
|
4929
|
+
if (existsSync12(rosterPath)) {
|
|
4621
4930
|
try {
|
|
4622
4931
|
roster = JSON.parse(readFileSync8(rosterPath, "utf-8"));
|
|
4623
4932
|
} catch {
|
|
4624
4933
|
}
|
|
4625
4934
|
}
|
|
4626
4935
|
const identities = {};
|
|
4627
|
-
if (
|
|
4628
|
-
for (const file of
|
|
4936
|
+
if (existsSync12(identityDir)) {
|
|
4937
|
+
for (const file of readdirSync2(identityDir).filter((f) => f.endsWith(".md"))) {
|
|
4629
4938
|
try {
|
|
4630
|
-
identities[file] = readFileSync8(
|
|
4939
|
+
identities[file] = readFileSync8(path12.join(identityDir, file), "utf-8");
|
|
4631
4940
|
} catch {
|
|
4632
4941
|
}
|
|
4633
4942
|
}
|
|
4634
4943
|
}
|
|
4635
4944
|
let config;
|
|
4636
|
-
if (
|
|
4945
|
+
if (existsSync12(configPath)) {
|
|
4637
4946
|
try {
|
|
4638
4947
|
config = JSON.parse(readFileSync8(configPath, "utf-8"));
|
|
4639
4948
|
} catch {
|
|
4640
4949
|
}
|
|
4641
4950
|
}
|
|
4642
4951
|
let agentConfig;
|
|
4643
|
-
const agentConfigPath =
|
|
4644
|
-
if (
|
|
4952
|
+
const agentConfigPath = path12.join(EXE_AI_DIR, "agent-config.json");
|
|
4953
|
+
if (existsSync12(agentConfigPath)) {
|
|
4645
4954
|
try {
|
|
4646
4955
|
agentConfig = JSON.parse(readFileSync8(agentConfigPath, "utf-8"));
|
|
4647
4956
|
} catch {
|
|
@@ -4719,16 +5028,16 @@ async function cloudPullRoster(config) {
|
|
|
4719
5028
|
}
|
|
4720
5029
|
}
|
|
4721
5030
|
function mergeConfig(remoteConfig, configPath) {
|
|
4722
|
-
const cfgPath = configPath ??
|
|
5031
|
+
const cfgPath = configPath ?? path12.join(EXE_AI_DIR, "config.json");
|
|
4723
5032
|
let local = {};
|
|
4724
|
-
if (
|
|
5033
|
+
if (existsSync12(cfgPath)) {
|
|
4725
5034
|
try {
|
|
4726
5035
|
local = JSON.parse(readFileSync8(cfgPath, "utf-8"));
|
|
4727
5036
|
} catch {
|
|
4728
5037
|
}
|
|
4729
5038
|
}
|
|
4730
5039
|
const merged = { ...remoteConfig, ...local };
|
|
4731
|
-
const dir =
|
|
5040
|
+
const dir = path12.dirname(cfgPath);
|
|
4732
5041
|
ensurePrivateDirSync(dir);
|
|
4733
5042
|
writeFileSync6(cfgPath, JSON.stringify(merged, null, 2), "utf-8");
|
|
4734
5043
|
enforcePrivateFileSync(cfgPath);
|
|
@@ -4736,7 +5045,7 @@ function mergeConfig(remoteConfig, configPath) {
|
|
|
4736
5045
|
async function mergeRosterFromRemote(remote, paths) {
|
|
4737
5046
|
return withRosterLock(async () => {
|
|
4738
5047
|
const rosterPath = paths?.rosterPath ?? void 0;
|
|
4739
|
-
const identityDir = paths?.identityDir ??
|
|
5048
|
+
const identityDir = paths?.identityDir ?? path12.join(EXE_AI_DIR, "identity");
|
|
4740
5049
|
const localEmployees = await loadEmployees(rosterPath);
|
|
4741
5050
|
const localNames = new Set(localEmployees.map((e) => e.name));
|
|
4742
5051
|
let added = 0;
|
|
@@ -4757,11 +5066,11 @@ async function mergeRosterFromRemote(remote, paths) {
|
|
|
4757
5066
|
) ?? lookupKey;
|
|
4758
5067
|
const remoteIdentity = remote.identities[matchedKey];
|
|
4759
5068
|
if (remoteIdentity) {
|
|
4760
|
-
if (!
|
|
4761
|
-
const idPath =
|
|
5069
|
+
if (!existsSync12(identityDir)) mkdirSync5(identityDir, { recursive: true });
|
|
5070
|
+
const idPath = path12.join(identityDir, `${remoteEmp.name}.md`);
|
|
4762
5071
|
let localIdentity = null;
|
|
4763
5072
|
try {
|
|
4764
|
-
localIdentity =
|
|
5073
|
+
localIdentity = existsSync12(idPath) ? readFileSync8(idPath, "utf-8") : null;
|
|
4765
5074
|
} catch {
|
|
4766
5075
|
}
|
|
4767
5076
|
if (localIdentity !== remoteIdentity) {
|
|
@@ -4791,16 +5100,16 @@ async function mergeRosterFromRemote(remote, paths) {
|
|
|
4791
5100
|
}
|
|
4792
5101
|
if (remote.agentConfig && Object.keys(remote.agentConfig).length > 0) {
|
|
4793
5102
|
try {
|
|
4794
|
-
const agentConfigPath =
|
|
5103
|
+
const agentConfigPath = path12.join(EXE_AI_DIR, "agent-config.json");
|
|
4795
5104
|
let local = {};
|
|
4796
|
-
if (
|
|
5105
|
+
if (existsSync12(agentConfigPath)) {
|
|
4797
5106
|
try {
|
|
4798
5107
|
local = JSON.parse(readFileSync8(agentConfigPath, "utf-8"));
|
|
4799
5108
|
} catch {
|
|
4800
5109
|
}
|
|
4801
5110
|
}
|
|
4802
5111
|
const merged = { ...remote.agentConfig, ...local };
|
|
4803
|
-
ensurePrivateDirSync(
|
|
5112
|
+
ensurePrivateDirSync(path12.dirname(agentConfigPath));
|
|
4804
5113
|
writeFileSync6(agentConfigPath, JSON.stringify(merged, null, 2) + "\n", "utf-8");
|
|
4805
5114
|
enforcePrivateFileSync(agentConfigPath);
|
|
4806
5115
|
} catch {
|
|
@@ -5241,11 +5550,11 @@ var init_cloud_sync = __esm({
|
|
|
5241
5550
|
LOCALHOST_PATTERNS = /^(localhost|127\.0\.0\.1|\[::1\])$/i;
|
|
5242
5551
|
FETCH_TIMEOUT_MS = 3e4;
|
|
5243
5552
|
PUSH_BATCH_SIZE = 5e3;
|
|
5244
|
-
ROSTER_LOCK_PATH =
|
|
5553
|
+
ROSTER_LOCK_PATH = path12.join(EXE_AI_DIR, "roster-merge.lock");
|
|
5245
5554
|
LOCK_STALE_MS = 3e4;
|
|
5246
5555
|
_pgPromise = null;
|
|
5247
5556
|
_pgFailed = false;
|
|
5248
|
-
ROSTER_DELETIONS_PATH =
|
|
5557
|
+
ROSTER_DELETIONS_PATH = path12.join(EXE_AI_DIR, "roster-deletions.json");
|
|
5249
5558
|
}
|
|
5250
5559
|
});
|
|
5251
5560
|
|
|
@@ -5255,12 +5564,12 @@ __export(preferences_exports, {
|
|
|
5255
5564
|
loadPreferences: () => loadPreferences,
|
|
5256
5565
|
savePreferences: () => savePreferences
|
|
5257
5566
|
});
|
|
5258
|
-
import { existsSync as
|
|
5259
|
-
import
|
|
5567
|
+
import { existsSync as existsSync13, readFileSync as readFileSync9, writeFileSync as writeFileSync7 } from "fs";
|
|
5568
|
+
import path13 from "path";
|
|
5260
5569
|
import os7 from "os";
|
|
5261
5570
|
function loadPreferences(homeDir = os7.homedir()) {
|
|
5262
|
-
const configPath =
|
|
5263
|
-
if (!
|
|
5571
|
+
const configPath = path13.join(homeDir, ".exe-os", "config.json");
|
|
5572
|
+
if (!existsSync13(configPath)) return {};
|
|
5264
5573
|
try {
|
|
5265
5574
|
const config = JSON.parse(readFileSync9(configPath, "utf-8"));
|
|
5266
5575
|
return config.preferences ?? {};
|
|
@@ -5269,11 +5578,11 @@ function loadPreferences(homeDir = os7.homedir()) {
|
|
|
5269
5578
|
}
|
|
5270
5579
|
}
|
|
5271
5580
|
function savePreferences(prefs, homeDir = os7.homedir()) {
|
|
5272
|
-
const configDir =
|
|
5273
|
-
const configPath =
|
|
5581
|
+
const configDir = path13.join(homeDir, ".exe-os");
|
|
5582
|
+
const configPath = path13.join(configDir, "config.json");
|
|
5274
5583
|
ensurePrivateDirSync(configDir);
|
|
5275
5584
|
let config = {};
|
|
5276
|
-
if (
|
|
5585
|
+
if (existsSync13(configPath)) {
|
|
5277
5586
|
try {
|
|
5278
5587
|
config = JSON.parse(readFileSync9(configPath, "utf-8"));
|
|
5279
5588
|
} catch {
|
|
@@ -6120,17 +6429,17 @@ __export(identity_exports, {
|
|
|
6120
6429
|
listIdentities: () => listIdentities,
|
|
6121
6430
|
updateIdentity: () => updateIdentity
|
|
6122
6431
|
});
|
|
6123
|
-
import { existsSync as
|
|
6124
|
-
import { readdirSync as
|
|
6125
|
-
import
|
|
6432
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync6, readFileSync as readFileSync10, writeFileSync as writeFileSync8 } from "fs";
|
|
6433
|
+
import { readdirSync as readdirSync3 } from "fs";
|
|
6434
|
+
import path14 from "path";
|
|
6126
6435
|
import { createHash as createHash2 } from "crypto";
|
|
6127
6436
|
function ensureDir() {
|
|
6128
|
-
if (!
|
|
6129
|
-
|
|
6437
|
+
if (!existsSync14(IDENTITY_DIR2)) {
|
|
6438
|
+
mkdirSync6(IDENTITY_DIR2, { recursive: true });
|
|
6130
6439
|
}
|
|
6131
6440
|
}
|
|
6132
6441
|
function identityPath(agentId) {
|
|
6133
|
-
return
|
|
6442
|
+
return path14.join(IDENTITY_DIR2, `${agentId}.md`);
|
|
6134
6443
|
}
|
|
6135
6444
|
function parseFrontmatter(raw) {
|
|
6136
6445
|
const match = raw.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
|
|
@@ -6171,7 +6480,7 @@ function contentHash(content) {
|
|
|
6171
6480
|
}
|
|
6172
6481
|
function getIdentity(agentId) {
|
|
6173
6482
|
const filePath = identityPath(agentId);
|
|
6174
|
-
if (!
|
|
6483
|
+
if (!existsSync14(filePath)) return null;
|
|
6175
6484
|
const raw = readFileSync10(filePath, "utf-8");
|
|
6176
6485
|
const { frontmatter, body } = parseFrontmatter(raw);
|
|
6177
6486
|
return {
|
|
@@ -6203,7 +6512,7 @@ async function updateIdentity(agentId, content, updatedBy) {
|
|
|
6203
6512
|
}
|
|
6204
6513
|
function listIdentities() {
|
|
6205
6514
|
ensureDir();
|
|
6206
|
-
const files =
|
|
6515
|
+
const files = readdirSync3(IDENTITY_DIR2).filter((f) => f.endsWith(".md"));
|
|
6207
6516
|
const results = [];
|
|
6208
6517
|
for (const file of files) {
|
|
6209
6518
|
const agentId = file.replace(".md", "");
|
|
@@ -6242,7 +6551,7 @@ var init_identity = __esm({
|
|
|
6242
6551
|
"use strict";
|
|
6243
6552
|
init_config();
|
|
6244
6553
|
init_database();
|
|
6245
|
-
IDENTITY_DIR2 =
|
|
6554
|
+
IDENTITY_DIR2 = path14.join(EXE_AI_DIR, "identity");
|
|
6246
6555
|
}
|
|
6247
6556
|
});
|
|
6248
6557
|
|
|
@@ -6793,28 +7102,28 @@ __export(session_wrappers_exports, {
|
|
|
6793
7102
|
generateSessionWrappers: () => generateSessionWrappers
|
|
6794
7103
|
});
|
|
6795
7104
|
import {
|
|
6796
|
-
existsSync as
|
|
7105
|
+
existsSync as existsSync15,
|
|
6797
7106
|
readFileSync as readFileSync11,
|
|
6798
7107
|
writeFileSync as writeFileSync9,
|
|
6799
|
-
mkdirSync as
|
|
7108
|
+
mkdirSync as mkdirSync7,
|
|
6800
7109
|
chmodSync as chmodSync2,
|
|
6801
|
-
readdirSync as
|
|
6802
|
-
unlinkSync as
|
|
7110
|
+
readdirSync as readdirSync4,
|
|
7111
|
+
unlinkSync as unlinkSync7
|
|
6803
7112
|
} from "fs";
|
|
6804
|
-
import
|
|
7113
|
+
import path15 from "path";
|
|
6805
7114
|
import { homedir as homedir3 } from "os";
|
|
6806
7115
|
function generateSessionWrappers(packageRoot, homeDir) {
|
|
6807
7116
|
const home = homeDir ?? homedir3();
|
|
6808
|
-
const binDir =
|
|
6809
|
-
const rosterPath =
|
|
6810
|
-
|
|
6811
|
-
const exeStartDst =
|
|
7117
|
+
const binDir = path15.join(home, ".exe-os", "bin");
|
|
7118
|
+
const rosterPath = path15.join(home, ".exe-os", "exe-employees.json");
|
|
7119
|
+
mkdirSync7(binDir, { recursive: true });
|
|
7120
|
+
const exeStartDst = path15.join(binDir, "exe-start");
|
|
6812
7121
|
const candidates = [
|
|
6813
|
-
|
|
6814
|
-
|
|
7122
|
+
path15.join(packageRoot, "dist", "bin", "exe-start.sh"),
|
|
7123
|
+
path15.join(packageRoot, "src", "bin", "exe-start.sh")
|
|
6815
7124
|
];
|
|
6816
7125
|
for (const src of candidates) {
|
|
6817
|
-
if (
|
|
7126
|
+
if (existsSync15(src)) {
|
|
6818
7127
|
writeFileSync9(exeStartDst, readFileSync11(src));
|
|
6819
7128
|
chmodSync2(exeStartDst, 493);
|
|
6820
7129
|
break;
|
|
@@ -6830,13 +7139,13 @@ function generateSessionWrappers(packageRoot, homeDir) {
|
|
|
6830
7139
|
return { created: 0, pathConfigured: false };
|
|
6831
7140
|
}
|
|
6832
7141
|
try {
|
|
6833
|
-
for (const f of
|
|
7142
|
+
for (const f of readdirSync4(binDir)) {
|
|
6834
7143
|
if (f === "exe-start") continue;
|
|
6835
|
-
const fPath =
|
|
7144
|
+
const fPath = path15.join(binDir, f);
|
|
6836
7145
|
try {
|
|
6837
7146
|
const content = readFileSync11(fPath, "utf8");
|
|
6838
7147
|
if (content.includes("exe-start")) {
|
|
6839
|
-
|
|
7148
|
+
unlinkSync7(fPath);
|
|
6840
7149
|
}
|
|
6841
7150
|
} catch {
|
|
6842
7151
|
}
|
|
@@ -6849,30 +7158,30 @@ exec "${exeStartDst}" "$0" "$@"
|
|
|
6849
7158
|
`;
|
|
6850
7159
|
for (const emp of employees) {
|
|
6851
7160
|
for (let n = 1; n <= MAX_N; n++) {
|
|
6852
|
-
const wrapperPath =
|
|
7161
|
+
const wrapperPath = path15.join(binDir, `${emp.name}${n}`);
|
|
6853
7162
|
writeFileSync9(wrapperPath, wrapperContent);
|
|
6854
7163
|
chmodSync2(wrapperPath, 493);
|
|
6855
7164
|
created++;
|
|
6856
|
-
const codexPath =
|
|
7165
|
+
const codexPath = path15.join(binDir, `${emp.name}${n}-codex`);
|
|
6857
7166
|
writeFileSync9(codexPath, wrapperContent);
|
|
6858
7167
|
chmodSync2(codexPath, 493);
|
|
6859
7168
|
created++;
|
|
6860
7169
|
}
|
|
6861
7170
|
}
|
|
6862
7171
|
const codexLauncherCandidates = [
|
|
6863
|
-
|
|
6864
|
-
|
|
7172
|
+
path15.join(packageRoot, "dist", "bin", "exe-start-codex.js"),
|
|
7173
|
+
path15.join(packageRoot, "src", "bin", "exe-start-codex.ts")
|
|
6865
7174
|
];
|
|
6866
7175
|
let codexLauncher = null;
|
|
6867
7176
|
for (const c of codexLauncherCandidates) {
|
|
6868
|
-
if (
|
|
7177
|
+
if (existsSync15(c)) {
|
|
6869
7178
|
codexLauncher = c;
|
|
6870
7179
|
break;
|
|
6871
7180
|
}
|
|
6872
7181
|
}
|
|
6873
7182
|
if (codexLauncher) {
|
|
6874
7183
|
for (const emp of employees) {
|
|
6875
|
-
const wrapperPath =
|
|
7184
|
+
const wrapperPath = path15.join(binDir, `${emp.name}-codex`);
|
|
6876
7185
|
const content = `#!/bin/bash
|
|
6877
7186
|
exec node "${codexLauncher}" --agent ${emp.name} "$@"
|
|
6878
7187
|
`;
|
|
@@ -6895,12 +7204,12 @@ export PATH="${binDir}:$PATH"
|
|
|
6895
7204
|
const shell = process.env.SHELL ?? "/bin/bash";
|
|
6896
7205
|
const profilePaths = [];
|
|
6897
7206
|
if (shell.includes("zsh")) {
|
|
6898
|
-
profilePaths.push(
|
|
7207
|
+
profilePaths.push(path15.join(home, ".zshrc"));
|
|
6899
7208
|
} else if (shell.includes("bash")) {
|
|
6900
|
-
profilePaths.push(
|
|
6901
|
-
profilePaths.push(
|
|
7209
|
+
profilePaths.push(path15.join(home, ".bashrc"));
|
|
7210
|
+
profilePaths.push(path15.join(home, ".bash_profile"));
|
|
6902
7211
|
} else {
|
|
6903
|
-
profilePaths.push(
|
|
7212
|
+
profilePaths.push(path15.join(home, ".profile"));
|
|
6904
7213
|
}
|
|
6905
7214
|
for (const profilePath of profilePaths) {
|
|
6906
7215
|
try {
|
|
@@ -6932,9 +7241,9 @@ var init_session_wrappers = __esm({
|
|
|
6932
7241
|
init_config();
|
|
6933
7242
|
init_keychain();
|
|
6934
7243
|
import crypto4 from "crypto";
|
|
6935
|
-
import { existsSync as
|
|
7244
|
+
import { existsSync as existsSync16, mkdirSync as mkdirSync8, readFileSync as readFileSync12, writeFileSync as writeFileSync10, unlinkSync as unlinkSync8 } from "fs";
|
|
6936
7245
|
import os8 from "os";
|
|
6937
|
-
import
|
|
7246
|
+
import path16 from "path";
|
|
6938
7247
|
import { createInterface } from "readline";
|
|
6939
7248
|
|
|
6940
7249
|
// src/lib/model-downloader.ts
|
|
@@ -7026,22 +7335,22 @@ async function fileHash(filePath) {
|
|
|
7026
7335
|
|
|
7027
7336
|
// src/lib/setup-wizard.ts
|
|
7028
7337
|
function findPackageRoot2() {
|
|
7029
|
-
let dir =
|
|
7030
|
-
const root =
|
|
7338
|
+
let dir = path16.dirname(new URL(import.meta.url).pathname);
|
|
7339
|
+
const root = path16.parse(dir).root;
|
|
7031
7340
|
while (dir !== root) {
|
|
7032
|
-
const pkgPath =
|
|
7033
|
-
if (
|
|
7341
|
+
const pkgPath = path16.join(dir, "package.json");
|
|
7342
|
+
if (existsSync16(pkgPath)) {
|
|
7034
7343
|
try {
|
|
7035
7344
|
const pkg = JSON.parse(readFileSync12(pkgPath, "utf-8"));
|
|
7036
7345
|
if (pkg.name === "@askexenow/exe-os" || pkg.name === "exe-os") return dir;
|
|
7037
7346
|
} catch {
|
|
7038
7347
|
}
|
|
7039
7348
|
}
|
|
7040
|
-
dir =
|
|
7349
|
+
dir = path16.dirname(dir);
|
|
7041
7350
|
}
|
|
7042
7351
|
return null;
|
|
7043
7352
|
}
|
|
7044
|
-
var SETUP_STATE_PATH =
|
|
7353
|
+
var SETUP_STATE_PATH = path16.join(os8.homedir(), ".exe-os", "setup-state.json");
|
|
7045
7354
|
function loadSetupState() {
|
|
7046
7355
|
try {
|
|
7047
7356
|
return JSON.parse(readFileSync12(SETUP_STATE_PATH, "utf8"));
|
|
@@ -7050,12 +7359,12 @@ function loadSetupState() {
|
|
|
7050
7359
|
}
|
|
7051
7360
|
}
|
|
7052
7361
|
function saveSetupState(state) {
|
|
7053
|
-
|
|
7362
|
+
mkdirSync8(path16.dirname(SETUP_STATE_PATH), { recursive: true });
|
|
7054
7363
|
writeFileSync10(SETUP_STATE_PATH, JSON.stringify(state, null, 2));
|
|
7055
7364
|
}
|
|
7056
7365
|
function clearSetupState() {
|
|
7057
7366
|
try {
|
|
7058
|
-
|
|
7367
|
+
unlinkSync8(SETUP_STATE_PATH);
|
|
7059
7368
|
} catch {
|
|
7060
7369
|
}
|
|
7061
7370
|
}
|
|
@@ -7072,8 +7381,8 @@ function ask(rl, prompt) {
|
|
|
7072
7381
|
function getAvailableMemoryGB2() {
|
|
7073
7382
|
if (process.platform === "darwin") {
|
|
7074
7383
|
try {
|
|
7075
|
-
const { execSync:
|
|
7076
|
-
const vmstat =
|
|
7384
|
+
const { execSync: execSync3 } = __require("child_process");
|
|
7385
|
+
const vmstat = execSync3("vm_stat", { encoding: "utf8" });
|
|
7077
7386
|
const pageSizeMatch = vmstat.match(/page size of (\d+) bytes/);
|
|
7078
7387
|
const pageSize = pageSizeMatch ? parseInt(pageSizeMatch[1], 10) : 16384;
|
|
7079
7388
|
const free = vmstat.match(/Pages free:\s+(\d+)/);
|
|
@@ -7101,10 +7410,10 @@ async function validateModel(log) {
|
|
|
7101
7410
|
if (totalGB <= 8 || isLowMemory()) {
|
|
7102
7411
|
log(`System memory: ${totalGB.toFixed(0)}GB total, ${freeGB.toFixed(1)}GB free`);
|
|
7103
7412
|
log("Skipping in-memory model validation (low memory \u2014 will validate on first use).");
|
|
7104
|
-
const modelPath =
|
|
7105
|
-
if (
|
|
7106
|
-
const { statSync:
|
|
7107
|
-
const size =
|
|
7413
|
+
const modelPath = path16.join(MODELS_DIR, LOCAL_FILENAME);
|
|
7414
|
+
if (existsSync16(modelPath)) {
|
|
7415
|
+
const { statSync: statSync3 } = await import("fs");
|
|
7416
|
+
const size = statSync3(modelPath).size;
|
|
7108
7417
|
if (size > 300 * 1e6) {
|
|
7109
7418
|
log(`Model file verified (${(size / 1e6).toFixed(0)} MB).`);
|
|
7110
7419
|
return;
|
|
@@ -7193,7 +7502,7 @@ async function runSetupWizard(opts = {}) {
|
|
|
7193
7502
|
if (state.completedSteps.length > 0) {
|
|
7194
7503
|
log(`Resuming setup from step ${Math.max(...state.completedSteps) + 1}...`);
|
|
7195
7504
|
}
|
|
7196
|
-
if (
|
|
7505
|
+
if (existsSync16(LEGACY_LANCE_PATH)) {
|
|
7197
7506
|
log("\u26A0 Found v1.0 LanceDB at ~/.exe-os/local.lance");
|
|
7198
7507
|
log(" v1.1 uses libSQL (SQLite). Your existing memories are not automatically migrated.");
|
|
7199
7508
|
log(" The old directory will not be modified or deleted.");
|
|
@@ -7208,6 +7517,23 @@ async function runSetupWizard(opts = {}) {
|
|
|
7208
7517
|
const key = crypto4.randomBytes(32);
|
|
7209
7518
|
await setMasterKey(key);
|
|
7210
7519
|
log("Encryption key generated and stored securely.");
|
|
7520
|
+
log("");
|
|
7521
|
+
const { exportMnemonic: exportMnemonic2 } = await Promise.resolve().then(() => (init_keychain(), keychain_exports));
|
|
7522
|
+
const mnemonic = await exportMnemonic2(key);
|
|
7523
|
+
log("=============================================================");
|
|
7524
|
+
log(" YOUR 24-WORD RECOVERY PHRASE");
|
|
7525
|
+
log("=============================================================");
|
|
7526
|
+
log("");
|
|
7527
|
+
log(" " + mnemonic);
|
|
7528
|
+
log("");
|
|
7529
|
+
log(" SAVE THIS NOW. Write it down or store it in your password");
|
|
7530
|
+
log(" manager. This phrase is the ONLY way to decrypt your memories");
|
|
7531
|
+
log(" if you lose this computer. We cannot recover it for you.");
|
|
7532
|
+
log("");
|
|
7533
|
+
log(" Like a Bitcoin wallet \u2014 lose the phrase, lose everything.");
|
|
7534
|
+
log("=============================================================");
|
|
7535
|
+
log("");
|
|
7536
|
+
await ask(rl, "Press Enter after you've saved your recovery phrase...");
|
|
7211
7537
|
}
|
|
7212
7538
|
state.completedSteps.push(1);
|
|
7213
7539
|
saveSetupState(state);
|
|
@@ -7357,7 +7683,7 @@ async function runSetupWizard(opts = {}) {
|
|
|
7357
7683
|
await saveConfig(config);
|
|
7358
7684
|
log("");
|
|
7359
7685
|
try {
|
|
7360
|
-
const claudeJsonPath =
|
|
7686
|
+
const claudeJsonPath = path16.join(os8.homedir(), ".claude.json");
|
|
7361
7687
|
let claudeJson = {};
|
|
7362
7688
|
try {
|
|
7363
7689
|
claudeJson = JSON.parse(readFileSync12(claudeJsonPath, "utf8"));
|
|
@@ -7383,7 +7709,7 @@ async function runSetupWizard(opts = {}) {
|
|
|
7383
7709
|
const prefs = { ...existingPrefs };
|
|
7384
7710
|
log("=== Config Defaults ===");
|
|
7385
7711
|
log("");
|
|
7386
|
-
const ghosttyDetected =
|
|
7712
|
+
const ghosttyDetected = existsSync16(path16.join(os8.homedir(), ".config", "ghostty")) || existsSync16(path16.join(os8.homedir(), "Library", "Application Support", "com.mitchellh.ghostty"));
|
|
7387
7713
|
if (ghosttyDetected) {
|
|
7388
7714
|
const ghosttyAnswer = await ask(rl, "Detected Ghostty terminal. Use exe-os Ghostty defaults? (Y/n) ");
|
|
7389
7715
|
prefs.ghostty = ghosttyAnswer.toLowerCase() !== "n";
|
|
@@ -7430,7 +7756,7 @@ async function runSetupWizard(opts = {}) {
|
|
|
7430
7756
|
let missingIdentities = [];
|
|
7431
7757
|
for (const emp of roster) {
|
|
7432
7758
|
const idPath = identityPath2(emp.name);
|
|
7433
|
-
if (!
|
|
7759
|
+
if (!existsSync16(idPath)) {
|
|
7434
7760
|
missingIdentities.push(emp.name);
|
|
7435
7761
|
}
|
|
7436
7762
|
}
|
|
@@ -7462,7 +7788,7 @@ async function runSetupWizard(opts = {}) {
|
|
|
7462
7788
|
}
|
|
7463
7789
|
missingIdentities = [];
|
|
7464
7790
|
for (const emp of roster) {
|
|
7465
|
-
if (!
|
|
7791
|
+
if (!existsSync16(identityPath2(emp.name))) {
|
|
7466
7792
|
missingIdentities.push(emp.name);
|
|
7467
7793
|
}
|
|
7468
7794
|
}
|
|
@@ -7527,7 +7853,7 @@ async function runSetupWizard(opts = {}) {
|
|
|
7527
7853
|
const cooIdentityContent = getIdentityTemplate("coo");
|
|
7528
7854
|
if (cooIdentityContent) {
|
|
7529
7855
|
const cooIdPath = identityPath2(cooName);
|
|
7530
|
-
|
|
7856
|
+
mkdirSync8(path16.dirname(cooIdPath), { recursive: true });
|
|
7531
7857
|
const replaced = cooIdentityContent.replace(/agent_id:\s*exe/g, `agent_id: ${cooName}`).replace(/\$\{agent_id\}/g, cooName);
|
|
7532
7858
|
writeFileSync10(cooIdPath, replaced, "utf-8");
|
|
7533
7859
|
}
|
|
@@ -7623,7 +7949,7 @@ async function runSetupWizard(opts = {}) {
|
|
|
7623
7949
|
const ctoIdentityContent = getIdentityTemplate("cto");
|
|
7624
7950
|
if (ctoIdentityContent) {
|
|
7625
7951
|
const ctoIdPath = identityPath2(ctoName);
|
|
7626
|
-
|
|
7952
|
+
mkdirSync8(path16.dirname(ctoIdPath), { recursive: true });
|
|
7627
7953
|
const replaced = ctoIdentityContent.replace(/agent_id:\s*\w+/g, `agent_id: ${ctoName}`).replace(/\$\{agent_id\}/g, ctoName);
|
|
7628
7954
|
writeFileSync10(ctoIdPath, replaced, "utf-8");
|
|
7629
7955
|
}
|
|
@@ -7646,7 +7972,7 @@ async function runSetupWizard(opts = {}) {
|
|
|
7646
7972
|
const cmoIdentityContent = getIdentityTemplate("cmo");
|
|
7647
7973
|
if (cmoIdentityContent) {
|
|
7648
7974
|
const cmoIdPath = identityPath2(cmoName);
|
|
7649
|
-
|
|
7975
|
+
mkdirSync8(path16.dirname(cmoIdPath), { recursive: true });
|
|
7650
7976
|
const replaced = cmoIdentityContent.replace(/agent_id:\s*\w+/g, `agent_id: ${cmoName}`).replace(/\$\{agent_id\}/g, cmoName);
|
|
7651
7977
|
writeFileSync10(cmoIdPath, replaced, "utf-8");
|
|
7652
7978
|
}
|
|
@@ -7670,7 +7996,7 @@ async function runSetupWizard(opts = {}) {
|
|
|
7670
7996
|
log(`Session shortcuts generated (${cooName}1, ${cooName}2, ...)`);
|
|
7671
7997
|
}
|
|
7672
7998
|
if (wrapResult.pathConfigured) {
|
|
7673
|
-
const binDir =
|
|
7999
|
+
const binDir = path16.join(os8.homedir(), ".exe-os", "bin");
|
|
7674
8000
|
process.env.PATH = `${binDir}:${process.env.PATH ?? ""}`;
|
|
7675
8001
|
pathJustConfigured = true;
|
|
7676
8002
|
}
|
|
@@ -7713,7 +8039,7 @@ async function runSetupWizard(opts = {}) {
|
|
|
7713
8039
|
const pkgRoot2 = findPackageRoot2();
|
|
7714
8040
|
if (pkgRoot2) {
|
|
7715
8041
|
try {
|
|
7716
|
-
version = JSON.parse(readFileSync12(
|
|
8042
|
+
version = JSON.parse(readFileSync12(path16.join(pkgRoot2, "package.json"), "utf-8")).version;
|
|
7717
8043
|
} catch {
|
|
7718
8044
|
}
|
|
7719
8045
|
}
|