@askexenow/exe-os 0.8.37 → 0.8.39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -8
- package/dist/bin/backfill-conversations.js +112 -70
- package/dist/bin/backfill-responses.js +53 -18
- package/dist/bin/backfill-vectors.js +43 -16
- package/dist/bin/cleanup-stale-review-tasks.js +38 -16
- package/dist/bin/cli.js +790 -468
- package/dist/bin/exe-agent.js +19 -4
- package/dist/bin/exe-assign.js +46 -13
- package/dist/bin/exe-boot.js +288 -129
- package/dist/bin/exe-call.js +20 -10
- package/dist/bin/exe-cloud.js +135 -30
- package/dist/bin/exe-dispatch.js +1 -1
- package/dist/bin/exe-doctor.js +38 -16
- package/dist/bin/exe-export-behaviors.js +43 -21
- package/dist/bin/exe-forget.js +39 -17
- package/dist/bin/exe-gateway.js +159 -50
- package/dist/bin/exe-heartbeat.js +53 -31
- package/dist/bin/exe-kill.js +40 -18
- package/dist/bin/exe-launch-agent.js +109 -36
- package/dist/bin/exe-link.js +196 -87
- package/dist/bin/exe-new-employee.js +56 -17
- package/dist/bin/exe-pending-messages.js +47 -25
- package/dist/bin/exe-pending-notifications.js +38 -16
- package/dist/bin/exe-pending-reviews.js +51 -29
- package/dist/bin/exe-rename.js +21 -7
- package/dist/bin/exe-review.js +41 -13
- package/dist/bin/exe-search.js +57 -21
- package/dist/bin/exe-session-cleanup.js +67 -31
- package/dist/bin/exe-settings.js +63 -2
- package/dist/bin/exe-status.js +35 -13
- package/dist/bin/exe-team.js +35 -13
- package/dist/bin/git-sweep.js +45 -17
- package/dist/bin/graph-backfill.js +38 -16
- package/dist/bin/graph-export.js +38 -16
- package/dist/bin/install.js +10 -1
- package/dist/bin/scan-tasks.js +47 -19
- package/dist/bin/setup.js +444 -259
- package/dist/bin/shard-migrate.js +38 -16
- package/dist/bin/wiki-sync.js +40 -17
- package/dist/gateway/index.js +113 -48
- package/dist/hooks/bug-report-worker.js +66 -39
- package/dist/hooks/commit-complete.js +45 -17
- package/dist/hooks/error-recall.js +60 -20
- package/dist/hooks/exe-heartbeat-hook.js +3 -2
- package/dist/hooks/ingest-worker.js +174 -45
- package/dist/hooks/ingest.js +74 -28
- package/dist/hooks/instructions-loaded.js +46 -17
- package/dist/hooks/notification.js +44 -15
- package/dist/hooks/post-compact.js +44 -15
- package/dist/hooks/pre-compact.js +42 -14
- package/dist/hooks/pre-tool-use.js +59 -22
- package/dist/hooks/prompt-ingest-worker.js +75 -14
- package/dist/hooks/prompt-submit.js +75 -32
- package/dist/hooks/response-ingest-worker.js +76 -15
- package/dist/hooks/session-end.js +54 -22
- package/dist/hooks/session-start.js +57 -20
- package/dist/hooks/stop.js +44 -15
- package/dist/hooks/subagent-stop.js +44 -15
- package/dist/hooks/summary-worker.js +339 -106
- package/dist/index.js +94 -23
- package/dist/lib/cloud-sync.js +191 -80
- package/dist/lib/config.js +4 -1
- package/dist/lib/consolidation.js +5 -4
- package/dist/lib/database.js +1 -0
- package/dist/lib/device-registry.js +2 -1
- package/dist/lib/embedder.js +9 -1
- package/dist/lib/employee-templates.js +5 -0
- package/dist/lib/employees.js +11 -6
- package/dist/lib/exe-daemon-client.js +6 -1
- package/dist/lib/exe-daemon.js +95 -36
- package/dist/lib/hybrid-search.js +57 -21
- package/dist/lib/identity-templates.js +16 -7
- package/dist/lib/identity.js +1 -1
- package/dist/lib/keychain.js +2 -1
- package/dist/lib/license.js +56 -6
- package/dist/lib/messaging.js +1 -1
- package/dist/lib/reminders.js +2 -2
- package/dist/lib/schedules.js +38 -16
- package/dist/lib/skill-learning.js +1 -1
- package/dist/lib/store.js +44 -16
- package/dist/lib/tasks.js +1 -1
- package/dist/lib/tmux-routing.js +1 -1
- package/dist/mcp/server.js +280 -155
- package/dist/mcp/tools/complete-reminder.js +1 -1
- package/dist/mcp/tools/create-task.js +14 -6
- package/dist/mcp/tools/deactivate-behavior.js +2 -2
- package/dist/mcp/tools/list-reminders.js +1 -1
- package/dist/mcp/tools/list-tasks.js +36 -28
- package/dist/mcp/tools/send-message.js +1 -1
- package/dist/mcp/tools/update-task.js +1 -1
- package/dist/runtime/index.js +42 -8
- package/dist/tui/App.js +220 -99
- package/package.json +5 -3
package/dist/lib/cloud-sync.js
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
2
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
3
|
+
}) : x)(function(x) {
|
|
4
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
5
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
6
|
+
});
|
|
7
|
+
|
|
1
8
|
// src/lib/cloud-sync.ts
|
|
2
|
-
import { readFileSync as readFileSync5, writeFileSync as writeFileSync2, existsSync as existsSync5, readdirSync, mkdirSync as mkdirSync2, appendFileSync } from "fs";
|
|
9
|
+
import { readFileSync as readFileSync5, writeFileSync as writeFileSync2, existsSync as existsSync5, readdirSync, mkdirSync as mkdirSync2, appendFileSync, unlinkSync } from "fs";
|
|
3
10
|
import path5 from "path";
|
|
4
11
|
import { homedir } from "os";
|
|
5
12
|
|
|
@@ -73,7 +80,7 @@ import { execSync } from "child_process";
|
|
|
73
80
|
import path2 from "path";
|
|
74
81
|
|
|
75
82
|
// src/lib/config.ts
|
|
76
|
-
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
83
|
+
import { readFile, writeFile, mkdir, chmod } from "fs/promises";
|
|
77
84
|
import { readFileSync, existsSync, renameSync } from "fs";
|
|
78
85
|
import path from "path";
|
|
79
86
|
import os from "os";
|
|
@@ -180,15 +187,20 @@ async function saveEmployees(employees, employeesPath = EMPLOYEES_PATH) {
|
|
|
180
187
|
await mkdir2(path2.dirname(employeesPath), { recursive: true });
|
|
181
188
|
await writeFile2(employeesPath, JSON.stringify(employees, null, 2) + "\n", "utf-8");
|
|
182
189
|
}
|
|
190
|
+
function findExeBin() {
|
|
191
|
+
try {
|
|
192
|
+
return execSync(process.platform === "win32" ? "where exe-os" : "which exe-os", { encoding: "utf8" }).trim();
|
|
193
|
+
} catch {
|
|
194
|
+
return null;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
183
197
|
function registerBinSymlinks(name) {
|
|
184
198
|
const created = [];
|
|
185
199
|
const skipped = [];
|
|
186
200
|
const errors = [];
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
} catch {
|
|
191
|
-
errors.push("Could not find 'exe' in PATH");
|
|
201
|
+
const exeBinPath = findExeBin();
|
|
202
|
+
if (!exeBinPath) {
|
|
203
|
+
errors.push("Could not find 'exe-os' in PATH");
|
|
192
204
|
return { created, skipped, errors };
|
|
193
205
|
}
|
|
194
206
|
const binDir = path2.dirname(exeBinPath);
|
|
@@ -225,6 +237,15 @@ var LICENSE_PATH = path3.join(EXE_AI_DIR, "license.key");
|
|
|
225
237
|
var CACHE_PATH = path3.join(EXE_AI_DIR, "license-cache.json");
|
|
226
238
|
var DEVICE_ID_PATH = path3.join(EXE_AI_DIR, "device-id");
|
|
227
239
|
var API_BASE = "https://askexe.com/cloud";
|
|
240
|
+
var RETRY_DELAY_MS = 500;
|
|
241
|
+
async function fetchRetry(url, init) {
|
|
242
|
+
try {
|
|
243
|
+
return await fetch(url, init);
|
|
244
|
+
} catch {
|
|
245
|
+
await new Promise((r) => setTimeout(r, RETRY_DELAY_MS));
|
|
246
|
+
return fetch(url, { ...init, signal: AbortSignal.timeout(1e4) });
|
|
247
|
+
}
|
|
248
|
+
}
|
|
228
249
|
var LICENSE_PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----
|
|
229
250
|
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeHztAMOpR/ZMh+rWuOASjEZ54CGY
|
|
230
251
|
4uj+UqeKCcvtgNHKmOK278HJaJcANe9xAeji8AFYu27q3WtzCi04pHudow==
|
|
@@ -316,7 +337,7 @@ function cacheResponse(token) {
|
|
|
316
337
|
async function validateLicense(apiKey, deviceId) {
|
|
317
338
|
const did = deviceId ?? loadDeviceId();
|
|
318
339
|
try {
|
|
319
|
-
const res = await
|
|
340
|
+
const res = await fetchRetry(`${API_BASE}/auth/activate`, {
|
|
320
341
|
method: "POST",
|
|
321
342
|
headers: { "Content-Type": "application/json" },
|
|
322
343
|
body: JSON.stringify({ apiKey, deviceId: did }),
|
|
@@ -351,14 +372,24 @@ async function validateLicense(apiKey, deviceId) {
|
|
|
351
372
|
} catch {
|
|
352
373
|
const cached = await getCachedLicense();
|
|
353
374
|
if (cached) return cached;
|
|
354
|
-
return FREE_LICENSE;
|
|
375
|
+
return { ...FREE_LICENSE, valid: false, error: "offline" };
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
var CACHE_MAX_AGE_MS = 36e5;
|
|
379
|
+
function getCacheAgeMs() {
|
|
380
|
+
try {
|
|
381
|
+
const { statSync } = __require("fs");
|
|
382
|
+
const s = statSync(CACHE_PATH);
|
|
383
|
+
return Date.now() - s.mtimeMs;
|
|
384
|
+
} catch {
|
|
385
|
+
return Infinity;
|
|
355
386
|
}
|
|
356
387
|
}
|
|
357
388
|
async function checkLicense() {
|
|
358
389
|
const key = loadLicense();
|
|
359
390
|
if (!key) return FREE_LICENSE;
|
|
360
391
|
const cached = await getCachedLicense();
|
|
361
|
-
if (cached) return cached;
|
|
392
|
+
if (cached && getCacheAgeMs() < CACHE_MAX_AGE_MS) return cached;
|
|
362
393
|
const deviceId = loadDeviceId();
|
|
363
394
|
return validateLicense(key, deviceId);
|
|
364
395
|
}
|
|
@@ -401,16 +432,50 @@ function logError(msg) {
|
|
|
401
432
|
}
|
|
402
433
|
var LOCALHOST_PATTERNS = /^(localhost|127\.0\.0\.1|\[::1\])$/i;
|
|
403
434
|
var FETCH_TIMEOUT_MS = 3e4;
|
|
435
|
+
var PUSH_BATCH_SIZE = 5e3;
|
|
436
|
+
var ROSTER_LOCK_PATH = path5.join(EXE_AI_DIR, "roster-merge.lock");
|
|
437
|
+
var LOCK_STALE_MS = 3e4;
|
|
438
|
+
async function withRosterLock(fn) {
|
|
439
|
+
if (existsSync5(ROSTER_LOCK_PATH)) {
|
|
440
|
+
try {
|
|
441
|
+
const ts = parseInt(readFileSync5(ROSTER_LOCK_PATH, "utf-8"), 10);
|
|
442
|
+
if (Date.now() - ts < LOCK_STALE_MS) {
|
|
443
|
+
throw new Error("Roster merge already in progress \u2014 another sync is running");
|
|
444
|
+
}
|
|
445
|
+
} catch (err) {
|
|
446
|
+
if (err instanceof Error && err.message.includes("already in progress")) throw err;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
writeFileSync2(ROSTER_LOCK_PATH, String(Date.now()));
|
|
450
|
+
try {
|
|
451
|
+
return await fn();
|
|
452
|
+
} finally {
|
|
453
|
+
try {
|
|
454
|
+
unlinkSync(ROSTER_LOCK_PATH);
|
|
455
|
+
} catch {
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
}
|
|
404
459
|
async function fetchWithRetry(url, init) {
|
|
405
|
-
const
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
460
|
+
const MAX_RETRIES = 3;
|
|
461
|
+
const BASE_DELAY_MS = 200;
|
|
462
|
+
let lastError;
|
|
463
|
+
for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
|
|
464
|
+
try {
|
|
465
|
+
const signal = AbortSignal.timeout(FETCH_TIMEOUT_MS);
|
|
466
|
+
const resp = await fetch(url, { ...init, signal });
|
|
467
|
+
if (resp.status >= 500 && attempt < MAX_RETRIES) {
|
|
468
|
+
await new Promise((r) => setTimeout(r, BASE_DELAY_MS * Math.pow(2, attempt)));
|
|
469
|
+
continue;
|
|
470
|
+
}
|
|
471
|
+
return resp;
|
|
472
|
+
} catch (err) {
|
|
473
|
+
lastError = err;
|
|
474
|
+
if (attempt === MAX_RETRIES) throw err;
|
|
475
|
+
await new Promise((r) => setTimeout(r, BASE_DELAY_MS * Math.pow(2, attempt)));
|
|
476
|
+
}
|
|
412
477
|
}
|
|
413
|
-
|
|
478
|
+
throw lastError;
|
|
414
479
|
}
|
|
415
480
|
function assertSecureEndpoint(endpoint) {
|
|
416
481
|
if (endpoint.startsWith("https://")) return;
|
|
@@ -438,10 +503,15 @@ async function cloudPush(records, maxVersion, config) {
|
|
|
438
503
|
headers: {
|
|
439
504
|
Authorization: `Bearer ${config.apiKey}`,
|
|
440
505
|
"Content-Type": "application/json",
|
|
441
|
-
"X-Device-Id": loadDeviceId()
|
|
506
|
+
"X-Device-Id": loadDeviceId(),
|
|
507
|
+
"X-Expected-Version": String(maxVersion)
|
|
442
508
|
},
|
|
443
509
|
body: JSON.stringify({ version: maxVersion, blob })
|
|
444
510
|
});
|
|
511
|
+
if (resp.status === 409) {
|
|
512
|
+
logError("[cloud-sync] PUSH VERSION CONFLICT \u2014 re-pull required before next push");
|
|
513
|
+
return false;
|
|
514
|
+
}
|
|
445
515
|
return resp.ok;
|
|
446
516
|
} catch (err) {
|
|
447
517
|
logError(`[cloud-sync] PUSH FAILED: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -528,18 +598,21 @@ async function cloudSync(config) {
|
|
|
528
598
|
"SELECT value FROM sync_meta WHERE key = 'last_cloud_push_version'"
|
|
529
599
|
);
|
|
530
600
|
const lastPushVersion = pushMeta.rows.length > 0 ? Number(pushMeta.rows[0].value) : 0;
|
|
531
|
-
const recordsResult = await client.execute({
|
|
532
|
-
sql: `SELECT id, agent_id, agent_role, session_id, timestamp,
|
|
533
|
-
tool_name, project_name, has_error, raw_text, version,
|
|
534
|
-
author_device_id, scope
|
|
535
|
-
FROM memories
|
|
536
|
-
WHERE version > ?
|
|
537
|
-
AND (scope IS NULL OR scope != 'personal')
|
|
538
|
-
ORDER BY version ASC`,
|
|
539
|
-
args: [lastPushVersion]
|
|
540
|
-
});
|
|
541
601
|
let pushed = 0;
|
|
542
|
-
|
|
602
|
+
let batchCursor = lastPushVersion;
|
|
603
|
+
while (true) {
|
|
604
|
+
const recordsResult = await client.execute({
|
|
605
|
+
sql: `SELECT id, agent_id, agent_role, session_id, timestamp,
|
|
606
|
+
tool_name, project_name, has_error, raw_text, version,
|
|
607
|
+
author_device_id, scope
|
|
608
|
+
FROM memories
|
|
609
|
+
WHERE version > ?
|
|
610
|
+
AND (scope IS NULL OR scope != 'personal')
|
|
611
|
+
ORDER BY version ASC
|
|
612
|
+
LIMIT ?`,
|
|
613
|
+
args: [batchCursor, PUSH_BATCH_SIZE]
|
|
614
|
+
});
|
|
615
|
+
if (recordsResult.rows.length === 0) break;
|
|
543
616
|
const records = recordsResult.rows.map((row) => ({
|
|
544
617
|
id: row.id,
|
|
545
618
|
agent_id: row.agent_id,
|
|
@@ -556,13 +629,14 @@ async function cloudSync(config) {
|
|
|
556
629
|
}));
|
|
557
630
|
const maxVersion = Number(records[records.length - 1].version);
|
|
558
631
|
const pushOk = await cloudPush(records, maxVersion, config);
|
|
559
|
-
if (pushOk)
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
632
|
+
if (!pushOk) break;
|
|
633
|
+
await client.execute({
|
|
634
|
+
sql: "INSERT OR REPLACE INTO sync_meta (key, value) VALUES ('last_cloud_push_version', ?)",
|
|
635
|
+
args: [String(maxVersion)]
|
|
636
|
+
});
|
|
637
|
+
pushed += records.length;
|
|
638
|
+
batchCursor = maxVersion;
|
|
639
|
+
if (recordsResult.rows.length < PUSH_BATCH_SIZE) break;
|
|
566
640
|
}
|
|
567
641
|
try {
|
|
568
642
|
await cloudPushRoster(config);
|
|
@@ -644,6 +718,28 @@ async function cloudSync(config) {
|
|
|
644
718
|
documents: documentsResult
|
|
645
719
|
};
|
|
646
720
|
}
|
|
721
|
+
var ROSTER_DELETIONS_PATH = path5.join(EXE_AI_DIR, "roster-deletions.json");
|
|
722
|
+
function recordRosterDeletion(name) {
|
|
723
|
+
let deletions = [];
|
|
724
|
+
try {
|
|
725
|
+
if (existsSync5(ROSTER_DELETIONS_PATH)) {
|
|
726
|
+
deletions = JSON.parse(readFileSync5(ROSTER_DELETIONS_PATH, "utf-8"));
|
|
727
|
+
}
|
|
728
|
+
} catch {
|
|
729
|
+
}
|
|
730
|
+
if (!deletions.includes(name)) deletions.push(name);
|
|
731
|
+
writeFileSync2(ROSTER_DELETIONS_PATH, JSON.stringify(deletions));
|
|
732
|
+
}
|
|
733
|
+
function consumeRosterDeletions() {
|
|
734
|
+
try {
|
|
735
|
+
if (!existsSync5(ROSTER_DELETIONS_PATH)) return [];
|
|
736
|
+
const deletions = JSON.parse(readFileSync5(ROSTER_DELETIONS_PATH, "utf-8"));
|
|
737
|
+
writeFileSync2(ROSTER_DELETIONS_PATH, "[]");
|
|
738
|
+
return deletions;
|
|
739
|
+
} catch {
|
|
740
|
+
return [];
|
|
741
|
+
}
|
|
742
|
+
}
|
|
647
743
|
function buildRosterBlob(paths) {
|
|
648
744
|
const rosterPath = paths?.rosterPath ?? path5.join(EXE_AI_DIR, "exe-employees.json");
|
|
649
745
|
const identityDir = paths?.identityDir ?? path5.join(EXE_AI_DIR, "identity");
|
|
@@ -671,9 +767,10 @@ function buildRosterBlob(paths) {
|
|
|
671
767
|
} catch {
|
|
672
768
|
}
|
|
673
769
|
}
|
|
674
|
-
const
|
|
770
|
+
const deletedNames = consumeRosterDeletions();
|
|
771
|
+
const content = JSON.stringify({ roster, identities, config, deletedNames });
|
|
675
772
|
const hash = Buffer.from(content).length;
|
|
676
|
-
return { roster, identities, config, version: hash };
|
|
773
|
+
return { roster, identities, config, deletedNames, version: hash };
|
|
677
774
|
}
|
|
678
775
|
async function cloudPushRoster(config) {
|
|
679
776
|
assertSecureEndpoint(config.endpoint);
|
|
@@ -756,38 +853,50 @@ function mergeConfig(remoteConfig, configPath) {
|
|
|
756
853
|
writeFileSync2(cfgPath, JSON.stringify(merged, null, 2), "utf-8");
|
|
757
854
|
}
|
|
758
855
|
async function mergeRosterFromRemote(remote, paths) {
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
if (
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
856
|
+
return withRosterLock(async () => {
|
|
857
|
+
const rosterPath = paths?.rosterPath ?? void 0;
|
|
858
|
+
const identityDir = paths?.identityDir ?? path5.join(EXE_AI_DIR, "identity");
|
|
859
|
+
const localEmployees = await loadEmployees(rosterPath);
|
|
860
|
+
const localNames = new Set(localEmployees.map((e) => e.name));
|
|
861
|
+
let added = 0;
|
|
862
|
+
for (const remoteEmp of remote.roster) {
|
|
863
|
+
if (localNames.has(remoteEmp.name)) continue;
|
|
864
|
+
localEmployees.push(remoteEmp);
|
|
865
|
+
localNames.add(remoteEmp.name);
|
|
866
|
+
added++;
|
|
867
|
+
if (remote.identities[`${remoteEmp.name}.md`]) {
|
|
868
|
+
if (!existsSync5(identityDir)) mkdirSync2(identityDir, { recursive: true });
|
|
869
|
+
const idPath = path5.join(identityDir, `${remoteEmp.name}.md`);
|
|
870
|
+
if (!existsSync5(idPath)) {
|
|
871
|
+
writeFileSync2(idPath, remote.identities[`${remoteEmp.name}.md`], "utf-8");
|
|
872
|
+
}
|
|
873
|
+
}
|
|
874
|
+
try {
|
|
875
|
+
registerBinSymlinks(remoteEmp.name);
|
|
876
|
+
} catch {
|
|
774
877
|
}
|
|
775
878
|
}
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
879
|
+
let removed = 0;
|
|
880
|
+
if (remote.deletedNames && remote.deletedNames.length > 0) {
|
|
881
|
+
const toRemove = new Set(remote.deletedNames);
|
|
882
|
+
const filtered = localEmployees.filter((e) => !toRemove.has(e.name));
|
|
883
|
+
removed = localEmployees.length - filtered.length;
|
|
884
|
+
if (removed > 0) {
|
|
885
|
+
localEmployees.length = 0;
|
|
886
|
+
localEmployees.push(...filtered);
|
|
887
|
+
}
|
|
779
888
|
}
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
await saveEmployees(localEmployees, rosterPath);
|
|
783
|
-
}
|
|
784
|
-
if (remote.config && Object.keys(remote.config).length > 0) {
|
|
785
|
-
try {
|
|
786
|
-
mergeConfig(remote.config, paths?.configPath);
|
|
787
|
-
} catch {
|
|
889
|
+
if (added > 0 || removed > 0) {
|
|
890
|
+
await saveEmployees(localEmployees, rosterPath);
|
|
788
891
|
}
|
|
789
|
-
|
|
790
|
-
|
|
892
|
+
if (remote.config && Object.keys(remote.config).length > 0) {
|
|
893
|
+
try {
|
|
894
|
+
mergeConfig(remote.config, paths?.configPath);
|
|
895
|
+
} catch {
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
return { added };
|
|
899
|
+
});
|
|
791
900
|
}
|
|
792
901
|
async function cloudPushBlob(route, data, metaKey, config) {
|
|
793
902
|
if (data.length === 0) return { ok: true };
|
|
@@ -855,7 +964,7 @@ async function cloudPullBlob(route, config) {
|
|
|
855
964
|
}
|
|
856
965
|
async function cloudPushBehaviors(config) {
|
|
857
966
|
const client = getClient();
|
|
858
|
-
const result = await client.execute("SELECT * FROM behaviors");
|
|
967
|
+
const result = await client.execute("SELECT * FROM behaviors LIMIT 10000");
|
|
859
968
|
const rows = result.rows;
|
|
860
969
|
const { ok } = await cloudPushBlob(
|
|
861
970
|
"/sync/push-behaviors",
|
|
@@ -903,13 +1012,13 @@ async function cloudPullBehaviors(config) {
|
|
|
903
1012
|
async function cloudPushGraphRAG(config) {
|
|
904
1013
|
const client = getClient();
|
|
905
1014
|
const [entities, relationships, aliases, entityMems, relMems, hyperedges, hyperedgeNodes] = await Promise.all([
|
|
906
|
-
client.execute("SELECT * FROM entities"),
|
|
907
|
-
client.execute("SELECT * FROM relationships"),
|
|
908
|
-
client.execute("SELECT * FROM entity_aliases"),
|
|
909
|
-
client.execute("SELECT * FROM entity_memories"),
|
|
910
|
-
client.execute("SELECT * FROM relationship_memories"),
|
|
911
|
-
client.execute("SELECT * FROM hyperedges"),
|
|
912
|
-
client.execute("SELECT * FROM hyperedge_nodes")
|
|
1015
|
+
client.execute("SELECT * FROM entities LIMIT 50000"),
|
|
1016
|
+
client.execute("SELECT * FROM relationships LIMIT 50000"),
|
|
1017
|
+
client.execute("SELECT * FROM entity_aliases LIMIT 50000"),
|
|
1018
|
+
client.execute("SELECT * FROM entity_memories LIMIT 50000"),
|
|
1019
|
+
client.execute("SELECT * FROM relationship_memories LIMIT 50000"),
|
|
1020
|
+
client.execute("SELECT * FROM hyperedges LIMIT 50000"),
|
|
1021
|
+
client.execute("SELECT * FROM hyperedge_nodes LIMIT 50000")
|
|
913
1022
|
]);
|
|
914
1023
|
const blob = {
|
|
915
1024
|
entities: entities.rows,
|
|
@@ -1011,7 +1120,7 @@ async function cloudPullGraphRAG(config) {
|
|
|
1011
1120
|
}
|
|
1012
1121
|
async function cloudPushTasks(config) {
|
|
1013
1122
|
const client = getClient();
|
|
1014
|
-
const result = await client.execute("SELECT * FROM tasks");
|
|
1123
|
+
const result = await client.execute("SELECT * FROM tasks LIMIT 10000");
|
|
1015
1124
|
const rows = result.rows;
|
|
1016
1125
|
const { ok } = await cloudPushBlob(
|
|
1017
1126
|
"/sync/push-tasks",
|
|
@@ -1057,7 +1166,7 @@ async function cloudPullTasks(config) {
|
|
|
1057
1166
|
}
|
|
1058
1167
|
async function cloudPushConversations(config) {
|
|
1059
1168
|
const client = getClient();
|
|
1060
|
-
const result = await client.execute("SELECT * FROM conversations");
|
|
1169
|
+
const result = await client.execute("SELECT * FROM conversations LIMIT 50000");
|
|
1061
1170
|
const rows = result.rows;
|
|
1062
1171
|
const { ok } = await cloudPushBlob(
|
|
1063
1172
|
"/sync/push-conversations",
|
|
@@ -1107,8 +1216,8 @@ async function cloudPullConversations(config) {
|
|
|
1107
1216
|
async function cloudPushDocuments(config) {
|
|
1108
1217
|
const client = getClient();
|
|
1109
1218
|
const [workspaces, documents] = await Promise.all([
|
|
1110
|
-
client.execute("SELECT * FROM workspaces"),
|
|
1111
|
-
client.execute("SELECT * FROM documents")
|
|
1219
|
+
client.execute("SELECT * FROM workspaces LIMIT 1000"),
|
|
1220
|
+
client.execute("SELECT * FROM documents LIMIT 10000")
|
|
1112
1221
|
]);
|
|
1113
1222
|
const blob = {
|
|
1114
1223
|
workspaces: workspaces.rows,
|
|
@@ -1162,6 +1271,7 @@ async function cloudPullDocuments(config) {
|
|
|
1162
1271
|
return { pulled };
|
|
1163
1272
|
}
|
|
1164
1273
|
export {
|
|
1274
|
+
assertSecureEndpoint,
|
|
1165
1275
|
buildRosterBlob,
|
|
1166
1276
|
cloudPull,
|
|
1167
1277
|
cloudPullBehaviors,
|
|
@@ -1181,5 +1291,6 @@ export {
|
|
|
1181
1291
|
cloudPushTasks,
|
|
1182
1292
|
cloudSync,
|
|
1183
1293
|
mergeConfig,
|
|
1184
|
-
mergeRosterFromRemote
|
|
1294
|
+
mergeRosterFromRemote,
|
|
1295
|
+
recordRosterDeletion
|
|
1185
1296
|
};
|
package/dist/lib/config.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/lib/config.ts
|
|
2
|
-
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
2
|
+
import { readFile, writeFile, mkdir, chmod } from "fs/promises";
|
|
3
3
|
import { readFileSync, existsSync, renameSync } from "fs";
|
|
4
4
|
import path from "path";
|
|
5
5
|
import os from "os";
|
|
@@ -204,6 +204,9 @@ async function saveConfig(config) {
|
|
|
204
204
|
await mkdir(dir, { recursive: true });
|
|
205
205
|
const configPath = path.join(dir, "config.json");
|
|
206
206
|
await writeFile(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
207
|
+
if (config.cloud?.apiKey) {
|
|
208
|
+
await chmod(configPath, 384);
|
|
209
|
+
}
|
|
207
210
|
}
|
|
208
211
|
async function loadConfigFrom(configPath) {
|
|
209
212
|
const raw = await readFile(configPath, "utf-8");
|
|
@@ -4,15 +4,15 @@ var __esm = (fn, res) => function __init() {
|
|
|
4
4
|
};
|
|
5
5
|
|
|
6
6
|
// src/lib/config.ts
|
|
7
|
-
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
7
|
+
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2, chmod as chmod2 } from "fs/promises";
|
|
8
8
|
import { readFileSync, existsSync as existsSync2, renameSync } from "fs";
|
|
9
9
|
import path2 from "path";
|
|
10
|
-
import
|
|
10
|
+
import os2 from "os";
|
|
11
11
|
function resolveDataDir() {
|
|
12
12
|
if (process.env.EXE_OS_DIR) return process.env.EXE_OS_DIR;
|
|
13
13
|
if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
|
|
14
|
-
const newDir = path2.join(
|
|
15
|
-
const legacyDir = path2.join(
|
|
14
|
+
const newDir = path2.join(os2.homedir(), ".exe-os");
|
|
15
|
+
const legacyDir = path2.join(os2.homedir(), ".exe-mem");
|
|
16
16
|
if (!existsSync2(newDir) && existsSync2(legacyDir)) {
|
|
17
17
|
try {
|
|
18
18
|
renameSync(legacyDir, newDir);
|
|
@@ -110,6 +110,7 @@ import { createClient } from "@libsql/client";
|
|
|
110
110
|
import { readFile, writeFile, unlink, mkdir, chmod } from "fs/promises";
|
|
111
111
|
import { existsSync } from "fs";
|
|
112
112
|
import path from "path";
|
|
113
|
+
import os from "os";
|
|
113
114
|
import crypto from "crypto";
|
|
114
115
|
|
|
115
116
|
// src/lib/store.ts
|
package/dist/lib/database.js
CHANGED
|
@@ -88,6 +88,7 @@ async function ensureSchema() {
|
|
|
88
88
|
const client = getRawClient();
|
|
89
89
|
await client.execute("PRAGMA journal_mode = WAL");
|
|
90
90
|
await client.execute("PRAGMA busy_timeout = 30000");
|
|
91
|
+
await client.execute("PRAGMA wal_autocheckpoint = 1000");
|
|
91
92
|
try {
|
|
92
93
|
await client.execute("PRAGMA libsql_vector_search_ef = 128");
|
|
93
94
|
} catch {
|
|
@@ -110,6 +110,7 @@ async function ensureSchema() {
|
|
|
110
110
|
const client = getRawClient();
|
|
111
111
|
await client.execute("PRAGMA journal_mode = WAL");
|
|
112
112
|
await client.execute("PRAGMA busy_timeout = 30000");
|
|
113
|
+
await client.execute("PRAGMA wal_autocheckpoint = 1000");
|
|
113
114
|
try {
|
|
114
115
|
await client.execute("PRAGMA libsql_vector_search_ef = 128");
|
|
115
116
|
} catch {
|
|
@@ -924,7 +925,7 @@ import { readFileSync as readFileSync2, writeFileSync, mkdirSync, existsSync as
|
|
|
924
925
|
import path2 from "path";
|
|
925
926
|
|
|
926
927
|
// src/lib/config.ts
|
|
927
|
-
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
928
|
+
import { readFile, writeFile, mkdir, chmod } from "fs/promises";
|
|
928
929
|
import { readFileSync, existsSync, renameSync } from "fs";
|
|
929
930
|
import path from "path";
|
|
930
931
|
import os from "os";
|
package/dist/lib/embedder.js
CHANGED
|
@@ -24,7 +24,7 @@ __export(config_exports, {
|
|
|
24
24
|
migrateConfig: () => migrateConfig,
|
|
25
25
|
saveConfig: () => saveConfig
|
|
26
26
|
});
|
|
27
|
-
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
27
|
+
import { readFile, writeFile, mkdir, chmod } from "fs/promises";
|
|
28
28
|
import { readFileSync, existsSync, renameSync } from "fs";
|
|
29
29
|
import path from "path";
|
|
30
30
|
import os from "os";
|
|
@@ -150,6 +150,9 @@ async function saveConfig(config) {
|
|
|
150
150
|
await mkdir(dir, { recursive: true });
|
|
151
151
|
const configPath = path.join(dir, "config.json");
|
|
152
152
|
await writeFile(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
153
|
+
if (config.cloud?.apiKey) {
|
|
154
|
+
await chmod(configPath, 384);
|
|
155
|
+
}
|
|
153
156
|
}
|
|
154
157
|
async function loadConfigFrom(configPath) {
|
|
155
158
|
const raw = await readFile(configPath, "utf-8");
|
|
@@ -274,8 +277,13 @@ var _buffer = "";
|
|
|
274
277
|
var _requestCount = 0;
|
|
275
278
|
var HEALTH_CHECK_INTERVAL = 100;
|
|
276
279
|
var _pending = /* @__PURE__ */ new Map();
|
|
280
|
+
var MAX_BUFFER = 1e7;
|
|
277
281
|
function handleData(chunk) {
|
|
278
282
|
_buffer += chunk.toString();
|
|
283
|
+
if (_buffer.length > MAX_BUFFER) {
|
|
284
|
+
_buffer = "";
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
279
287
|
let newlineIdx;
|
|
280
288
|
while ((newlineIdx = _buffer.indexOf("\n")) !== -1) {
|
|
281
289
|
const line = _buffer.slice(0, newlineIdx).trim();
|
|
@@ -467,6 +467,10 @@ function buildCustomEmployeePrompt(name, role) {
|
|
|
467
467
|
function getTemplate(name) {
|
|
468
468
|
return TEMPLATES[name];
|
|
469
469
|
}
|
|
470
|
+
function getTemplateByRole(role) {
|
|
471
|
+
const lower = role.toLowerCase();
|
|
472
|
+
return Object.values(TEMPLATES).find((t) => t.role.toLowerCase() === lower);
|
|
473
|
+
}
|
|
470
474
|
function personalizePrompt(prompt, templateName, actualName) {
|
|
471
475
|
if (templateName === actualName) return prompt;
|
|
472
476
|
const escaped = templateName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
@@ -597,6 +601,7 @@ export {
|
|
|
597
601
|
buildCustomEmployeePrompt,
|
|
598
602
|
getSessionPrompt,
|
|
599
603
|
getTemplate,
|
|
604
|
+
getTemplateByRole,
|
|
600
605
|
personalizePrompt,
|
|
601
606
|
renderClientCOOTemplate
|
|
602
607
|
};
|
package/dist/lib/employees.js
CHANGED
|
@@ -5,7 +5,7 @@ import { execSync } from "child_process";
|
|
|
5
5
|
import path2 from "path";
|
|
6
6
|
|
|
7
7
|
// src/lib/config.ts
|
|
8
|
-
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
8
|
+
import { readFile, writeFile, mkdir, chmod } from "fs/promises";
|
|
9
9
|
import { readFileSync, existsSync, renameSync } from "fs";
|
|
10
10
|
import path from "path";
|
|
11
11
|
import os from "os";
|
|
@@ -165,15 +165,20 @@ function addEmployee(employees, employee) {
|
|
|
165
165
|
}
|
|
166
166
|
return [...employees, normalized];
|
|
167
167
|
}
|
|
168
|
+
function findExeBin() {
|
|
169
|
+
try {
|
|
170
|
+
return execSync(process.platform === "win32" ? "where exe-os" : "which exe-os", { encoding: "utf8" }).trim();
|
|
171
|
+
} catch {
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
168
175
|
function registerBinSymlinks(name) {
|
|
169
176
|
const created = [];
|
|
170
177
|
const skipped = [];
|
|
171
178
|
const errors = [];
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
} catch {
|
|
176
|
-
errors.push("Could not find 'exe' in PATH");
|
|
179
|
+
const exeBinPath = findExeBin();
|
|
180
|
+
if (!exeBinPath) {
|
|
181
|
+
errors.push("Could not find 'exe-os' in PATH");
|
|
177
182
|
return { created, skipped, errors };
|
|
178
183
|
}
|
|
179
184
|
const binDir = path2.dirname(exeBinPath);
|
|
@@ -7,7 +7,7 @@ import path2 from "path";
|
|
|
7
7
|
import { fileURLToPath } from "url";
|
|
8
8
|
|
|
9
9
|
// src/lib/config.ts
|
|
10
|
-
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
10
|
+
import { readFile, writeFile, mkdir, chmod } from "fs/promises";
|
|
11
11
|
import { readFileSync, existsSync, renameSync } from "fs";
|
|
12
12
|
import path from "path";
|
|
13
13
|
import os from "os";
|
|
@@ -110,8 +110,13 @@ var _buffer = "";
|
|
|
110
110
|
var _requestCount = 0;
|
|
111
111
|
var HEALTH_CHECK_INTERVAL = 100;
|
|
112
112
|
var _pending = /* @__PURE__ */ new Map();
|
|
113
|
+
var MAX_BUFFER = 1e7;
|
|
113
114
|
function handleData(chunk) {
|
|
114
115
|
_buffer += chunk.toString();
|
|
116
|
+
if (_buffer.length > MAX_BUFFER) {
|
|
117
|
+
_buffer = "";
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
115
120
|
let newlineIdx;
|
|
116
121
|
while ((newlineIdx = _buffer.indexOf("\n")) !== -1) {
|
|
117
122
|
const line = _buffer.slice(0, newlineIdx).trim();
|