@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-call.js
CHANGED
|
@@ -10,7 +10,7 @@ var __export = (target, all) => {
|
|
|
10
10
|
};
|
|
11
11
|
|
|
12
12
|
// src/lib/config.ts
|
|
13
|
-
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
13
|
+
import { readFile, writeFile, mkdir, chmod } from "fs/promises";
|
|
14
14
|
import { readFileSync, existsSync, renameSync } from "fs";
|
|
15
15
|
import path from "path";
|
|
16
16
|
import os from "os";
|
|
@@ -193,15 +193,20 @@ function addEmployee(employees, employee) {
|
|
|
193
193
|
}
|
|
194
194
|
return [...employees, normalized];
|
|
195
195
|
}
|
|
196
|
+
function findExeBin() {
|
|
197
|
+
try {
|
|
198
|
+
return execSync(process.platform === "win32" ? "where exe-os" : "which exe-os", { encoding: "utf8" }).trim();
|
|
199
|
+
} catch {
|
|
200
|
+
return null;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
196
203
|
function registerBinSymlinks(name) {
|
|
197
204
|
const created = [];
|
|
198
205
|
const skipped = [];
|
|
199
206
|
const errors = [];
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
} catch {
|
|
204
|
-
errors.push("Could not find 'exe' in PATH");
|
|
207
|
+
const exeBinPath = findExeBin();
|
|
208
|
+
if (!exeBinPath) {
|
|
209
|
+
errors.push("Could not find 'exe-os' in PATH");
|
|
205
210
|
return { created, skipped, errors };
|
|
206
211
|
}
|
|
207
212
|
const binDir = path2.dirname(exeBinPath);
|
package/dist/bin/exe-cloud.js
CHANGED
|
@@ -16,15 +16,15 @@ var __export = (target, all) => {
|
|
|
16
16
|
};
|
|
17
17
|
|
|
18
18
|
// src/lib/config.ts
|
|
19
|
-
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
19
|
+
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2, chmod as chmod2 } from "fs/promises";
|
|
20
20
|
import { readFileSync, existsSync as existsSync2, renameSync } from "fs";
|
|
21
21
|
import path2 from "path";
|
|
22
|
-
import
|
|
22
|
+
import os2 from "os";
|
|
23
23
|
function resolveDataDir() {
|
|
24
24
|
if (process.env.EXE_OS_DIR) return process.env.EXE_OS_DIR;
|
|
25
25
|
if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
|
|
26
|
-
const newDir = path2.join(
|
|
27
|
-
const legacyDir = path2.join(
|
|
26
|
+
const newDir = path2.join(os2.homedir(), ".exe-os");
|
|
27
|
+
const legacyDir = path2.join(os2.homedir(), ".exe-mem");
|
|
28
28
|
if (!existsSync2(newDir) && existsSync2(legacyDir)) {
|
|
29
29
|
try {
|
|
30
30
|
renameSync(legacyDir, newDir);
|
|
@@ -111,7 +111,7 @@ async function loadConfig() {
|
|
|
111
111
|
normalizeAutoUpdate(migratedCfg);
|
|
112
112
|
const config = { ...DEFAULT_CONFIG, dbPath: path2.join(dir, "memories.db"), ...migratedCfg };
|
|
113
113
|
if (config.dbPath.startsWith("~")) {
|
|
114
|
-
config.dbPath = config.dbPath.replace(/^~/,
|
|
114
|
+
config.dbPath = config.dbPath.replace(/^~/, os2.homedir());
|
|
115
115
|
}
|
|
116
116
|
return config;
|
|
117
117
|
} catch {
|
|
@@ -123,6 +123,9 @@ async function saveConfig(config) {
|
|
|
123
123
|
await mkdir2(dir, { recursive: true });
|
|
124
124
|
const configPath = path2.join(dir, "config.json");
|
|
125
125
|
await writeFile2(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
126
|
+
if (config.cloud?.apiKey) {
|
|
127
|
+
await chmod2(configPath, 384);
|
|
128
|
+
}
|
|
126
129
|
}
|
|
127
130
|
var EXE_AI_DIR, DB_PATH, MODELS_DIR, CONFIG_PATH, LEGACY_LANCE_PATH, CURRENT_CONFIG_VERSION, DEFAULT_CONFIG, CONFIG_MIGRATIONS;
|
|
128
131
|
var init_config = __esm({
|
|
@@ -227,22 +230,30 @@ __export(license_exports, {
|
|
|
227
230
|
stopLicenseRevalidation: () => stopLicenseRevalidation,
|
|
228
231
|
validateLicense: () => validateLicense
|
|
229
232
|
});
|
|
230
|
-
import { readFileSync as
|
|
233
|
+
import { readFileSync as readFileSync3, writeFileSync, existsSync as existsSync4, mkdirSync } from "fs";
|
|
231
234
|
import { randomUUID } from "crypto";
|
|
232
|
-
import
|
|
235
|
+
import path4 from "path";
|
|
233
236
|
import { jwtVerify, importSPKI } from "jose";
|
|
237
|
+
async function fetchRetry(url, init) {
|
|
238
|
+
try {
|
|
239
|
+
return await fetch(url, init);
|
|
240
|
+
} catch {
|
|
241
|
+
await new Promise((r) => setTimeout(r, RETRY_DELAY_MS));
|
|
242
|
+
return fetch(url, { ...init, signal: AbortSignal.timeout(1e4) });
|
|
243
|
+
}
|
|
244
|
+
}
|
|
234
245
|
function loadDeviceId() {
|
|
235
|
-
const deviceJsonPath =
|
|
246
|
+
const deviceJsonPath = path4.join(EXE_AI_DIR, "device.json");
|
|
236
247
|
try {
|
|
237
|
-
if (
|
|
238
|
-
const data = JSON.parse(
|
|
248
|
+
if (existsSync4(deviceJsonPath)) {
|
|
249
|
+
const data = JSON.parse(readFileSync3(deviceJsonPath, "utf8"));
|
|
239
250
|
if (data.deviceId) return data.deviceId;
|
|
240
251
|
}
|
|
241
252
|
} catch {
|
|
242
253
|
}
|
|
243
254
|
try {
|
|
244
|
-
if (
|
|
245
|
-
const id2 =
|
|
255
|
+
if (existsSync4(DEVICE_ID_PATH)) {
|
|
256
|
+
const id2 = readFileSync3(DEVICE_ID_PATH, "utf8").trim();
|
|
246
257
|
if (id2) return id2;
|
|
247
258
|
}
|
|
248
259
|
} catch {
|
|
@@ -254,15 +265,15 @@ function loadDeviceId() {
|
|
|
254
265
|
}
|
|
255
266
|
function loadLicense() {
|
|
256
267
|
try {
|
|
257
|
-
if (!
|
|
258
|
-
return
|
|
268
|
+
if (!existsSync4(LICENSE_PATH)) return null;
|
|
269
|
+
return readFileSync3(LICENSE_PATH, "utf8").trim();
|
|
259
270
|
} catch {
|
|
260
271
|
return null;
|
|
261
272
|
}
|
|
262
273
|
}
|
|
263
274
|
function saveLicense(apiKey) {
|
|
264
275
|
mkdirSync(EXE_AI_DIR, { recursive: true });
|
|
265
|
-
writeFileSync(LICENSE_PATH, apiKey.trim(), "utf8");
|
|
276
|
+
writeFileSync(LICENSE_PATH, apiKey.trim(), { encoding: "utf8", mode: 384 });
|
|
266
277
|
}
|
|
267
278
|
async function verifyLicenseJwt(token) {
|
|
268
279
|
try {
|
|
@@ -288,8 +299,8 @@ async function verifyLicenseJwt(token) {
|
|
|
288
299
|
}
|
|
289
300
|
async function getCachedLicense() {
|
|
290
301
|
try {
|
|
291
|
-
if (!
|
|
292
|
-
const raw = JSON.parse(
|
|
302
|
+
if (!existsSync4(CACHE_PATH)) return null;
|
|
303
|
+
const raw = JSON.parse(readFileSync3(CACHE_PATH, "utf8"));
|
|
293
304
|
if (!raw.token || typeof raw.token !== "string") return null;
|
|
294
305
|
return await verifyLicenseJwt(raw.token);
|
|
295
306
|
} catch {
|
|
@@ -298,8 +309,8 @@ async function getCachedLicense() {
|
|
|
298
309
|
}
|
|
299
310
|
function readCachedToken() {
|
|
300
311
|
try {
|
|
301
|
-
if (!
|
|
302
|
-
const raw = JSON.parse(
|
|
312
|
+
if (!existsSync4(CACHE_PATH)) return null;
|
|
313
|
+
const raw = JSON.parse(readFileSync3(CACHE_PATH, "utf8"));
|
|
303
314
|
return typeof raw.token === "string" ? raw.token : null;
|
|
304
315
|
} catch {
|
|
305
316
|
return null;
|
|
@@ -314,7 +325,7 @@ function cacheResponse(token) {
|
|
|
314
325
|
async function validateLicense(apiKey, deviceId) {
|
|
315
326
|
const did = deviceId ?? loadDeviceId();
|
|
316
327
|
try {
|
|
317
|
-
const res = await
|
|
328
|
+
const res = await fetchRetry(`${API_BASE}/auth/activate`, {
|
|
318
329
|
method: "POST",
|
|
319
330
|
headers: { "Content-Type": "application/json" },
|
|
320
331
|
body: JSON.stringify({ apiKey, deviceId: did }),
|
|
@@ -405,7 +416,7 @@ async function assertVpsLicense(opts) {
|
|
|
405
416
|
let explicitRejection = false;
|
|
406
417
|
let transientFailure = false;
|
|
407
418
|
try {
|
|
408
|
-
const res = await
|
|
419
|
+
const res = await fetchRetry(`${API_BASE}/auth/activate`, {
|
|
409
420
|
method: "POST",
|
|
410
421
|
headers: { "Content-Type": "application/json" },
|
|
411
422
|
body: JSON.stringify({ apiKey, deviceId }),
|
|
@@ -507,15 +518,16 @@ function stopLicenseRevalidation() {
|
|
|
507
518
|
_revalTimer = null;
|
|
508
519
|
}
|
|
509
520
|
}
|
|
510
|
-
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;
|
|
521
|
+
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;
|
|
511
522
|
var init_license = __esm({
|
|
512
523
|
"src/lib/license.ts"() {
|
|
513
524
|
"use strict";
|
|
514
525
|
init_config();
|
|
515
|
-
LICENSE_PATH =
|
|
516
|
-
CACHE_PATH =
|
|
517
|
-
DEVICE_ID_PATH =
|
|
526
|
+
LICENSE_PATH = path4.join(EXE_AI_DIR, "license.key");
|
|
527
|
+
CACHE_PATH = path4.join(EXE_AI_DIR, "license-cache.json");
|
|
528
|
+
DEVICE_ID_PATH = path4.join(EXE_AI_DIR, "device-id");
|
|
518
529
|
API_BASE = "https://askexe.com/cloud";
|
|
530
|
+
RETRY_DELAY_MS = 500;
|
|
519
531
|
LICENSE_PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----
|
|
520
532
|
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeHztAMOpR/ZMh+rWuOASjEZ54CGY
|
|
521
533
|
4uj+UqeKCcvtgNHKmOK278HJaJcANe9xAeji8AFYu27q3WtzCi04pHudow==
|
|
@@ -549,11 +561,12 @@ import { createInterface } from "readline";
|
|
|
549
561
|
import { readFile, writeFile, unlink, mkdir, chmod } from "fs/promises";
|
|
550
562
|
import { existsSync } from "fs";
|
|
551
563
|
import path from "path";
|
|
564
|
+
import os from "os";
|
|
552
565
|
import crypto from "crypto";
|
|
553
566
|
var SERVICE = "exe-mem";
|
|
554
567
|
var ACCOUNT = "master-key";
|
|
555
568
|
function getKeyDir() {
|
|
556
|
-
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path.join(
|
|
569
|
+
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path.join(os.homedir(), ".exe-os");
|
|
557
570
|
}
|
|
558
571
|
function getKeyPath() {
|
|
559
572
|
return path.join(getKeyDir(), "master.key");
|
|
@@ -696,6 +709,58 @@ function isMainModule(importMetaUrl) {
|
|
|
696
709
|
}
|
|
697
710
|
}
|
|
698
711
|
|
|
712
|
+
// src/lib/cloud-sync.ts
|
|
713
|
+
import { readFileSync as readFileSync5, writeFileSync as writeFileSync2, existsSync as existsSync6, readdirSync, mkdirSync as mkdirSync2, appendFileSync, unlinkSync } from "fs";
|
|
714
|
+
import path6 from "path";
|
|
715
|
+
import { homedir } from "os";
|
|
716
|
+
|
|
717
|
+
// src/lib/database.ts
|
|
718
|
+
import { createClient } from "@libsql/client";
|
|
719
|
+
|
|
720
|
+
// src/lib/crypto.ts
|
|
721
|
+
import crypto3 from "crypto";
|
|
722
|
+
|
|
723
|
+
// src/lib/compress.ts
|
|
724
|
+
import { brotliCompressSync, brotliDecompressSync, constants } from "zlib";
|
|
725
|
+
|
|
726
|
+
// src/lib/plan-limits.ts
|
|
727
|
+
import { readFileSync as readFileSync4, existsSync as existsSync5 } from "fs";
|
|
728
|
+
import path5 from "path";
|
|
729
|
+
|
|
730
|
+
// src/lib/employees.ts
|
|
731
|
+
init_config();
|
|
732
|
+
import { readFile as readFile3, writeFile as writeFile3, mkdir as mkdir3 } from "fs/promises";
|
|
733
|
+
import { existsSync as existsSync3, symlinkSync, readlinkSync, readFileSync as readFileSync2 } from "fs";
|
|
734
|
+
import { execSync } from "child_process";
|
|
735
|
+
import path3 from "path";
|
|
736
|
+
var EMPLOYEES_PATH = path3.join(EXE_AI_DIR, "exe-employees.json");
|
|
737
|
+
|
|
738
|
+
// src/lib/plan-limits.ts
|
|
739
|
+
init_license();
|
|
740
|
+
init_config();
|
|
741
|
+
var CACHE_PATH2 = path5.join(EXE_AI_DIR, "license-cache.json");
|
|
742
|
+
|
|
743
|
+
// src/lib/cloud-sync.ts
|
|
744
|
+
init_license();
|
|
745
|
+
init_config();
|
|
746
|
+
var LOCALHOST_PATTERNS = /^(localhost|127\.0\.0\.1|\[::1\])$/i;
|
|
747
|
+
var ROSTER_LOCK_PATH = path6.join(EXE_AI_DIR, "roster-merge.lock");
|
|
748
|
+
function assertSecureEndpoint(endpoint) {
|
|
749
|
+
if (endpoint.startsWith("https://")) return;
|
|
750
|
+
if (endpoint.startsWith("http://")) {
|
|
751
|
+
try {
|
|
752
|
+
const parsed = new URL(endpoint);
|
|
753
|
+
if (LOCALHOST_PATTERNS.test(parsed.hostname)) return;
|
|
754
|
+
} catch {
|
|
755
|
+
return;
|
|
756
|
+
}
|
|
757
|
+
throw new Error(
|
|
758
|
+
`Insecure cloud endpoint rejected: "${endpoint}". Use https:// for remote hosts. Plain http:// is only allowed for localhost.`
|
|
759
|
+
);
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
var ROSTER_DELETIONS_PATH = path6.join(EXE_AI_DIR, "roster-deletions.json");
|
|
763
|
+
|
|
699
764
|
// src/bin/exe-cloud.ts
|
|
700
765
|
var BAR = "\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550";
|
|
701
766
|
function ask(rl, question) {
|
|
@@ -743,6 +808,7 @@ async function setupMode() {
|
|
|
743
808
|
const orgId = deriveOrgId(masterKey);
|
|
744
809
|
const authTokenHash = hashAuthToken(deriveWsAuthToken(masterKey));
|
|
745
810
|
try {
|
|
811
|
+
assertSecureEndpoint(config.cloud.endpoint);
|
|
746
812
|
const regResp = await fetch(`${config.cloud.endpoint}/api/register-org`, {
|
|
747
813
|
method: "POST",
|
|
748
814
|
headers: { Authorization: `Bearer ${config.cloud.apiKey}`, "Content-Type": "application/json" },
|
|
@@ -764,6 +830,7 @@ async function setupMode() {
|
|
|
764
830
|
const endpoint = await ask(rl, " Endpoint [https://askexe.com/cloud]: ") || "https://askexe.com/cloud";
|
|
765
831
|
console.log(" Validating...");
|
|
766
832
|
try {
|
|
833
|
+
assertSecureEndpoint(endpoint);
|
|
767
834
|
const resp = await fetch(`${endpoint}/auth/verify`, {
|
|
768
835
|
method: "POST",
|
|
769
836
|
headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" }
|
|
@@ -774,7 +841,8 @@ async function setupMode() {
|
|
|
774
841
|
try {
|
|
775
842
|
const { mirrorLicenseKey: mirrorLicenseKey2 } = await Promise.resolve().then(() => (init_license(), license_exports));
|
|
776
843
|
mirrorLicenseKey2(apiKey);
|
|
777
|
-
} catch {
|
|
844
|
+
} catch (err) {
|
|
845
|
+
console.log(` \u26A0 License mirror failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
778
846
|
}
|
|
779
847
|
console.log(" \u2713 Cloud sync configured.\n");
|
|
780
848
|
const masterKey = await getMasterKey();
|
|
@@ -783,6 +851,7 @@ async function setupMode() {
|
|
|
783
851
|
const orgId = deriveOrgId(masterKey);
|
|
784
852
|
const authTokenHash = hashAuthToken(deriveWsAuthToken(masterKey));
|
|
785
853
|
try {
|
|
854
|
+
assertSecureEndpoint(endpoint);
|
|
786
855
|
const regResp = await fetch(`${endpoint}/api/register-org`, {
|
|
787
856
|
method: "POST",
|
|
788
857
|
headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" },
|
|
@@ -830,9 +899,11 @@ async function syncMode() {
|
|
|
830
899
|
console.log(" 24-word recovery phrase:");
|
|
831
900
|
console.log(` ${mnemonic}
|
|
832
901
|
`);
|
|
902
|
+
console.log(" \u26A0 Clear your terminal history after copying.\n");
|
|
833
903
|
if (config.cloud?.apiKey) {
|
|
904
|
+
const maskedKey = config.cloud.apiKey.slice(0, 10) + "..." + config.cloud.apiKey.slice(-4);
|
|
834
905
|
console.log(" Cloud API key:");
|
|
835
|
-
console.log(` ${
|
|
906
|
+
console.log(` ${maskedKey}
|
|
836
907
|
`);
|
|
837
908
|
console.log(" Endpoint:");
|
|
838
909
|
console.log(` ${config.cloud.endpoint}
|
package/dist/bin/exe-dispatch.js
CHANGED
|
@@ -335,7 +335,7 @@ var init_database = __esm({
|
|
|
335
335
|
});
|
|
336
336
|
|
|
337
337
|
// src/lib/config.ts
|
|
338
|
-
import { readFile, writeFile, mkdir } from "fs/promises";
|
|
338
|
+
import { readFile, writeFile, mkdir, chmod } from "fs/promises";
|
|
339
339
|
import { readFileSync as readFileSync3, existsSync as existsSync3, renameSync as renameSync2 } from "fs";
|
|
340
340
|
import path3 from "path";
|
|
341
341
|
import os3 from "os";
|
package/dist/bin/exe-doctor.js
CHANGED
|
@@ -10,15 +10,15 @@ var __export = (target, all) => {
|
|
|
10
10
|
};
|
|
11
11
|
|
|
12
12
|
// src/lib/config.ts
|
|
13
|
-
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
13
|
+
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2, chmod as chmod2 } from "fs/promises";
|
|
14
14
|
import { readFileSync, existsSync as existsSync2, renameSync } from "fs";
|
|
15
15
|
import path2 from "path";
|
|
16
|
-
import
|
|
16
|
+
import os2 from "os";
|
|
17
17
|
function resolveDataDir() {
|
|
18
18
|
if (process.env.EXE_OS_DIR) return process.env.EXE_OS_DIR;
|
|
19
19
|
if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
|
|
20
|
-
const newDir = path2.join(
|
|
21
|
-
const legacyDir = path2.join(
|
|
20
|
+
const newDir = path2.join(os2.homedir(), ".exe-os");
|
|
21
|
+
const legacyDir = path2.join(os2.homedir(), ".exe-mem");
|
|
22
22
|
if (!existsSync2(newDir) && existsSync2(legacyDir)) {
|
|
23
23
|
try {
|
|
24
24
|
renameSync(legacyDir, newDir);
|
|
@@ -105,7 +105,7 @@ async function loadConfig() {
|
|
|
105
105
|
normalizeAutoUpdate(migratedCfg);
|
|
106
106
|
const config = { ...DEFAULT_CONFIG, dbPath: path2.join(dir, "memories.db"), ...migratedCfg };
|
|
107
107
|
if (config.dbPath.startsWith("~")) {
|
|
108
|
-
config.dbPath = config.dbPath.replace(/^~/,
|
|
108
|
+
config.dbPath = config.dbPath.replace(/^~/, os2.homedir());
|
|
109
109
|
}
|
|
110
110
|
return config;
|
|
111
111
|
} catch {
|
|
@@ -526,6 +526,7 @@ async function ensureSchema() {
|
|
|
526
526
|
const client = getRawClient();
|
|
527
527
|
await client.execute("PRAGMA journal_mode = WAL");
|
|
528
528
|
await client.execute("PRAGMA busy_timeout = 30000");
|
|
529
|
+
await client.execute("PRAGMA wal_autocheckpoint = 1000");
|
|
529
530
|
try {
|
|
530
531
|
await client.execute("PRAGMA libsql_vector_search_ef = 128");
|
|
531
532
|
} catch {
|
|
@@ -1319,11 +1320,12 @@ async function ensureSchema() {
|
|
|
1319
1320
|
import { readFile, writeFile, unlink, mkdir, chmod } from "fs/promises";
|
|
1320
1321
|
import { existsSync } from "fs";
|
|
1321
1322
|
import path from "path";
|
|
1323
|
+
import os from "os";
|
|
1322
1324
|
import crypto from "crypto";
|
|
1323
1325
|
var SERVICE = "exe-mem";
|
|
1324
1326
|
var ACCOUNT = "master-key";
|
|
1325
1327
|
function getKeyDir() {
|
|
1326
|
-
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path.join(
|
|
1328
|
+
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path.join(os.homedir(), ".exe-os");
|
|
1327
1329
|
}
|
|
1328
1330
|
function getKeyPath() {
|
|
1329
1331
|
return path.join(getKeyDir(), "master.key");
|
|
@@ -1360,6 +1362,30 @@ async function getMasterKey() {
|
|
|
1360
1362
|
|
|
1361
1363
|
// src/lib/store.ts
|
|
1362
1364
|
init_config();
|
|
1365
|
+
var INIT_MAX_RETRIES = 3;
|
|
1366
|
+
var INIT_RETRY_DELAY_MS = 1e3;
|
|
1367
|
+
function isBusyError2(err) {
|
|
1368
|
+
if (err instanceof Error) {
|
|
1369
|
+
const msg = err.message.toLowerCase();
|
|
1370
|
+
return msg.includes("sqlite_busy") || msg.includes("database is locked");
|
|
1371
|
+
}
|
|
1372
|
+
return false;
|
|
1373
|
+
}
|
|
1374
|
+
async function retryOnBusy2(fn, label) {
|
|
1375
|
+
for (let attempt = 0; attempt <= INIT_MAX_RETRIES; attempt++) {
|
|
1376
|
+
try {
|
|
1377
|
+
return await fn();
|
|
1378
|
+
} catch (err) {
|
|
1379
|
+
if (!isBusyError2(err) || attempt === INIT_MAX_RETRIES) throw err;
|
|
1380
|
+
process.stderr.write(
|
|
1381
|
+
`[store] SQLITE_BUSY during ${label}, retry ${attempt + 1}/${INIT_MAX_RETRIES}
|
|
1382
|
+
`
|
|
1383
|
+
);
|
|
1384
|
+
await new Promise((r) => setTimeout(r, INIT_RETRY_DELAY_MS * (attempt + 1)));
|
|
1385
|
+
}
|
|
1386
|
+
}
|
|
1387
|
+
throw new Error("unreachable");
|
|
1388
|
+
}
|
|
1363
1389
|
var _pendingRecords = [];
|
|
1364
1390
|
var _batchSize = 20;
|
|
1365
1391
|
var _flushIntervalMs = 1e4;
|
|
@@ -1394,14 +1420,17 @@ async function initStore(options) {
|
|
|
1394
1420
|
dbPath,
|
|
1395
1421
|
encryptionKey: hexKey
|
|
1396
1422
|
});
|
|
1397
|
-
await ensureSchema();
|
|
1423
|
+
await retryOnBusy2(() => ensureSchema(), "ensureSchema");
|
|
1398
1424
|
try {
|
|
1399
1425
|
const { initShardManager: initShardManager2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
|
|
1400
1426
|
initShardManager2(hexKey);
|
|
1401
1427
|
} catch {
|
|
1402
1428
|
}
|
|
1403
1429
|
const client = getClient();
|
|
1404
|
-
const vResult = await
|
|
1430
|
+
const vResult = await retryOnBusy2(
|
|
1431
|
+
() => client.execute("SELECT MAX(version) as max_v FROM memories"),
|
|
1432
|
+
"version-query"
|
|
1433
|
+
);
|
|
1405
1434
|
_nextVersion = (Number(vResult.rows[0]?.max_v) || 0) + 1;
|
|
1406
1435
|
}
|
|
1407
1436
|
|
|
@@ -10,15 +10,15 @@ var __export = (target, all) => {
|
|
|
10
10
|
};
|
|
11
11
|
|
|
12
12
|
// src/lib/config.ts
|
|
13
|
-
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
13
|
+
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2, chmod as chmod2 } from "fs/promises";
|
|
14
14
|
import { readFileSync, existsSync as existsSync2, renameSync } from "fs";
|
|
15
15
|
import path2 from "path";
|
|
16
|
-
import
|
|
16
|
+
import os2 from "os";
|
|
17
17
|
function resolveDataDir() {
|
|
18
18
|
if (process.env.EXE_OS_DIR) return process.env.EXE_OS_DIR;
|
|
19
19
|
if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
|
|
20
|
-
const newDir = path2.join(
|
|
21
|
-
const legacyDir = path2.join(
|
|
20
|
+
const newDir = path2.join(os2.homedir(), ".exe-os");
|
|
21
|
+
const legacyDir = path2.join(os2.homedir(), ".exe-mem");
|
|
22
22
|
if (!existsSync2(newDir) && existsSync2(legacyDir)) {
|
|
23
23
|
try {
|
|
24
24
|
renameSync(legacyDir, newDir);
|
|
@@ -105,7 +105,7 @@ async function loadConfig() {
|
|
|
105
105
|
normalizeAutoUpdate(migratedCfg);
|
|
106
106
|
const config = { ...DEFAULT_CONFIG, dbPath: path2.join(dir, "memories.db"), ...migratedCfg };
|
|
107
107
|
if (config.dbPath.startsWith("~")) {
|
|
108
|
-
config.dbPath = config.dbPath.replace(/^~/,
|
|
108
|
+
config.dbPath = config.dbPath.replace(/^~/, os2.homedir());
|
|
109
109
|
}
|
|
110
110
|
return config;
|
|
111
111
|
} catch {
|
|
@@ -526,6 +526,7 @@ async function ensureSchema() {
|
|
|
526
526
|
const client = getRawClient();
|
|
527
527
|
await client.execute("PRAGMA journal_mode = WAL");
|
|
528
528
|
await client.execute("PRAGMA busy_timeout = 30000");
|
|
529
|
+
await client.execute("PRAGMA wal_autocheckpoint = 1000");
|
|
529
530
|
try {
|
|
530
531
|
await client.execute("PRAGMA libsql_vector_search_ef = 128");
|
|
531
532
|
} catch {
|
|
@@ -1327,11 +1328,12 @@ async function disposeDatabase() {
|
|
|
1327
1328
|
import { readFile, writeFile, unlink, mkdir, chmod } from "fs/promises";
|
|
1328
1329
|
import { existsSync } from "fs";
|
|
1329
1330
|
import path from "path";
|
|
1331
|
+
import os from "os";
|
|
1330
1332
|
import crypto from "crypto";
|
|
1331
1333
|
var SERVICE = "exe-mem";
|
|
1332
1334
|
var ACCOUNT = "master-key";
|
|
1333
1335
|
function getKeyDir() {
|
|
1334
|
-
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path.join(
|
|
1336
|
+
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path.join(os.homedir(), ".exe-os");
|
|
1335
1337
|
}
|
|
1336
1338
|
function getKeyPath() {
|
|
1337
1339
|
return path.join(getKeyDir(), "master.key");
|
|
@@ -1368,6 +1370,30 @@ async function getMasterKey() {
|
|
|
1368
1370
|
|
|
1369
1371
|
// src/lib/store.ts
|
|
1370
1372
|
init_config();
|
|
1373
|
+
var INIT_MAX_RETRIES = 3;
|
|
1374
|
+
var INIT_RETRY_DELAY_MS = 1e3;
|
|
1375
|
+
function isBusyError2(err) {
|
|
1376
|
+
if (err instanceof Error) {
|
|
1377
|
+
const msg = err.message.toLowerCase();
|
|
1378
|
+
return msg.includes("sqlite_busy") || msg.includes("database is locked");
|
|
1379
|
+
}
|
|
1380
|
+
return false;
|
|
1381
|
+
}
|
|
1382
|
+
async function retryOnBusy2(fn, label) {
|
|
1383
|
+
for (let attempt = 0; attempt <= INIT_MAX_RETRIES; attempt++) {
|
|
1384
|
+
try {
|
|
1385
|
+
return await fn();
|
|
1386
|
+
} catch (err) {
|
|
1387
|
+
if (!isBusyError2(err) || attempt === INIT_MAX_RETRIES) throw err;
|
|
1388
|
+
process.stderr.write(
|
|
1389
|
+
`[store] SQLITE_BUSY during ${label}, retry ${attempt + 1}/${INIT_MAX_RETRIES}
|
|
1390
|
+
`
|
|
1391
|
+
);
|
|
1392
|
+
await new Promise((r) => setTimeout(r, INIT_RETRY_DELAY_MS * (attempt + 1)));
|
|
1393
|
+
}
|
|
1394
|
+
}
|
|
1395
|
+
throw new Error("unreachable");
|
|
1396
|
+
}
|
|
1371
1397
|
var _pendingRecords = [];
|
|
1372
1398
|
var _batchSize = 20;
|
|
1373
1399
|
var _flushIntervalMs = 1e4;
|
|
@@ -1402,14 +1428,17 @@ async function initStore(options) {
|
|
|
1402
1428
|
dbPath,
|
|
1403
1429
|
encryptionKey: hexKey
|
|
1404
1430
|
});
|
|
1405
|
-
await ensureSchema();
|
|
1431
|
+
await retryOnBusy2(() => ensureSchema(), "ensureSchema");
|
|
1406
1432
|
try {
|
|
1407
1433
|
const { initShardManager: initShardManager2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
|
|
1408
1434
|
initShardManager2(hexKey);
|
|
1409
1435
|
} catch {
|
|
1410
1436
|
}
|
|
1411
1437
|
const client = getClient();
|
|
1412
|
-
const vResult = await
|
|
1438
|
+
const vResult = await retryOnBusy2(
|
|
1439
|
+
() => client.execute("SELECT MAX(version) as max_v FROM memories"),
|
|
1440
|
+
"version-query"
|
|
1441
|
+
);
|
|
1413
1442
|
_nextVersion = (Number(vResult.rows[0]?.max_v) || 0) + 1;
|
|
1414
1443
|
}
|
|
1415
1444
|
async function flushBatch() {
|
|
@@ -1561,7 +1590,7 @@ function vectorToBlob(vector) {
|
|
|
1561
1590
|
}
|
|
1562
1591
|
|
|
1563
1592
|
// src/lib/behaviors-export.ts
|
|
1564
|
-
import
|
|
1593
|
+
import os3 from "os";
|
|
1565
1594
|
import path4 from "path";
|
|
1566
1595
|
import {
|
|
1567
1596
|
existsSync as existsSync4,
|
|
@@ -1604,7 +1633,7 @@ async function listBehaviors(agentId2, projectName2, limit = 30) {
|
|
|
1604
1633
|
|
|
1605
1634
|
// src/lib/behaviors-export.ts
|
|
1606
1635
|
var BEHAVIORS_EXPORT_DIR = path4.join(
|
|
1607
|
-
|
|
1636
|
+
os3.homedir(),
|
|
1608
1637
|
".exe-os",
|
|
1609
1638
|
"behaviors-export"
|
|
1610
1639
|
);
|
package/dist/bin/exe-forget.js
CHANGED
|
@@ -104,6 +104,7 @@ async function ensureSchema() {
|
|
|
104
104
|
const client = getRawClient();
|
|
105
105
|
await client.execute("PRAGMA journal_mode = WAL");
|
|
106
106
|
await client.execute("PRAGMA busy_timeout = 30000");
|
|
107
|
+
await client.execute("PRAGMA wal_autocheckpoint = 1000");
|
|
107
108
|
try {
|
|
108
109
|
await client.execute("PRAGMA libsql_vector_search_ef = 128");
|
|
109
110
|
} catch {
|
|
@@ -907,9 +908,10 @@ var init_database = __esm({
|
|
|
907
908
|
import { readFile, writeFile, unlink, mkdir, chmod } from "fs/promises";
|
|
908
909
|
import { existsSync } from "fs";
|
|
909
910
|
import path from "path";
|
|
911
|
+
import os from "os";
|
|
910
912
|
import crypto from "crypto";
|
|
911
913
|
function getKeyDir() {
|
|
912
|
-
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path.join(
|
|
914
|
+
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path.join(os.homedir(), ".exe-os");
|
|
913
915
|
}
|
|
914
916
|
function getKeyPath() {
|
|
915
917
|
return path.join(getKeyDir(), "master.key");
|
|
@@ -953,15 +955,15 @@ var init_keychain = __esm({
|
|
|
953
955
|
});
|
|
954
956
|
|
|
955
957
|
// src/lib/config.ts
|
|
956
|
-
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
958
|
+
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2, chmod as chmod2 } from "fs/promises";
|
|
957
959
|
import { readFileSync, existsSync as existsSync2, renameSync } from "fs";
|
|
958
960
|
import path2 from "path";
|
|
959
|
-
import
|
|
961
|
+
import os2 from "os";
|
|
960
962
|
function resolveDataDir() {
|
|
961
963
|
if (process.env.EXE_OS_DIR) return process.env.EXE_OS_DIR;
|
|
962
964
|
if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
|
|
963
|
-
const newDir = path2.join(
|
|
964
|
-
const legacyDir = path2.join(
|
|
965
|
+
const newDir = path2.join(os2.homedir(), ".exe-os");
|
|
966
|
+
const legacyDir = path2.join(os2.homedir(), ".exe-mem");
|
|
965
967
|
if (!existsSync2(newDir) && existsSync2(legacyDir)) {
|
|
966
968
|
try {
|
|
967
969
|
renameSync(legacyDir, newDir);
|
|
@@ -1048,7 +1050,7 @@ async function loadConfig() {
|
|
|
1048
1050
|
normalizeAutoUpdate(migratedCfg);
|
|
1049
1051
|
const config = { ...DEFAULT_CONFIG, dbPath: path2.join(dir, "memories.db"), ...migratedCfg };
|
|
1050
1052
|
if (config.dbPath.startsWith("~")) {
|
|
1051
|
-
config.dbPath = config.dbPath.replace(/^~/,
|
|
1053
|
+
config.dbPath = config.dbPath.replace(/^~/, os2.homedir());
|
|
1052
1054
|
}
|
|
1053
1055
|
return config;
|
|
1054
1056
|
} catch {
|
|
@@ -1383,6 +1385,28 @@ var init_shard_manager = __esm({
|
|
|
1383
1385
|
});
|
|
1384
1386
|
|
|
1385
1387
|
// src/lib/store.ts
|
|
1388
|
+
function isBusyError2(err) {
|
|
1389
|
+
if (err instanceof Error) {
|
|
1390
|
+
const msg = err.message.toLowerCase();
|
|
1391
|
+
return msg.includes("sqlite_busy") || msg.includes("database is locked");
|
|
1392
|
+
}
|
|
1393
|
+
return false;
|
|
1394
|
+
}
|
|
1395
|
+
async function retryOnBusy2(fn, label) {
|
|
1396
|
+
for (let attempt = 0; attempt <= INIT_MAX_RETRIES; attempt++) {
|
|
1397
|
+
try {
|
|
1398
|
+
return await fn();
|
|
1399
|
+
} catch (err) {
|
|
1400
|
+
if (!isBusyError2(err) || attempt === INIT_MAX_RETRIES) throw err;
|
|
1401
|
+
process.stderr.write(
|
|
1402
|
+
`[store] SQLITE_BUSY during ${label}, retry ${attempt + 1}/${INIT_MAX_RETRIES}
|
|
1403
|
+
`
|
|
1404
|
+
);
|
|
1405
|
+
await new Promise((r) => setTimeout(r, INIT_RETRY_DELAY_MS * (attempt + 1)));
|
|
1406
|
+
}
|
|
1407
|
+
}
|
|
1408
|
+
throw new Error("unreachable");
|
|
1409
|
+
}
|
|
1386
1410
|
async function initStore(options) {
|
|
1387
1411
|
if (_flushTimer !== null) {
|
|
1388
1412
|
clearInterval(_flushTimer);
|
|
@@ -1411,14 +1435,17 @@ async function initStore(options) {
|
|
|
1411
1435
|
dbPath,
|
|
1412
1436
|
encryptionKey: hexKey
|
|
1413
1437
|
});
|
|
1414
|
-
await ensureSchema();
|
|
1438
|
+
await retryOnBusy2(() => ensureSchema(), "ensureSchema");
|
|
1415
1439
|
try {
|
|
1416
1440
|
const { initShardManager: initShardManager2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
|
|
1417
1441
|
initShardManager2(hexKey);
|
|
1418
1442
|
} catch {
|
|
1419
1443
|
}
|
|
1420
1444
|
const client = getClient();
|
|
1421
|
-
const vResult = await
|
|
1445
|
+
const vResult = await retryOnBusy2(
|
|
1446
|
+
() => client.execute("SELECT MAX(version) as max_v FROM memories"),
|
|
1447
|
+
"version-query"
|
|
1448
|
+
);
|
|
1422
1449
|
_nextVersion = (Number(vResult.rows[0]?.max_v) || 0) + 1;
|
|
1423
1450
|
}
|
|
1424
1451
|
function buildWikiScopeFilter(options, columnPrefix) {
|
|
@@ -1473,7 +1500,7 @@ async function attachDocumentMetadata(records) {
|
|
|
1473
1500
|
}
|
|
1474
1501
|
return records;
|
|
1475
1502
|
}
|
|
1476
|
-
var _pendingRecords, _batchSize, _flushIntervalMs, _flushTimer, _flushing, _nextVersion;
|
|
1503
|
+
var INIT_MAX_RETRIES, INIT_RETRY_DELAY_MS, _pendingRecords, _batchSize, _flushIntervalMs, _flushTimer, _flushing, _nextVersion;
|
|
1477
1504
|
var init_store = __esm({
|
|
1478
1505
|
"src/lib/store.ts"() {
|
|
1479
1506
|
"use strict";
|
|
@@ -1481,6 +1508,8 @@ var init_store = __esm({
|
|
|
1481
1508
|
init_database();
|
|
1482
1509
|
init_keychain();
|
|
1483
1510
|
init_config();
|
|
1511
|
+
INIT_MAX_RETRIES = 3;
|
|
1512
|
+
INIT_RETRY_DELAY_MS = 1e3;
|
|
1484
1513
|
_pendingRecords = [];
|
|
1485
1514
|
_batchSize = 20;
|
|
1486
1515
|
_flushIntervalMs = 1e4;
|