@askexenow/exe-os 0.9.7 → 0.9.9
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 +953 -105
- package/dist/bin/backfill-responses.js +952 -104
- package/dist/bin/backfill-vectors.js +956 -108
- package/dist/bin/cleanup-stale-review-tasks.js +802 -58
- package/dist/bin/cli.js +2292 -1070
- package/dist/bin/exe-agent-config.js +157 -101
- package/dist/bin/exe-agent.js +55 -29
- package/dist/bin/exe-assign.js +940 -92
- package/dist/bin/exe-boot.js +1424 -442
- package/dist/bin/exe-call.js +240 -141
- package/dist/bin/exe-cloud.js +198 -70
- package/dist/bin/exe-dispatch.js +951 -192
- package/dist/bin/exe-doctor.js +791 -51
- package/dist/bin/exe-export-behaviors.js +790 -42
- package/dist/bin/exe-forget.js +771 -31
- package/dist/bin/exe-gateway.js +1592 -521
- package/dist/bin/exe-heartbeat.js +850 -109
- package/dist/bin/exe-kill.js +783 -35
- package/dist/bin/exe-launch-agent.js +1030 -107
- package/dist/bin/exe-link.js +916 -110
- package/dist/bin/exe-new-employee.js +526 -217
- package/dist/bin/exe-pending-messages.js +1046 -62
- package/dist/bin/exe-pending-notifications.js +1318 -111
- package/dist/bin/exe-pending-reviews.js +1040 -72
- package/dist/bin/exe-rename.js +772 -59
- package/dist/bin/exe-review.js +772 -32
- package/dist/bin/exe-search.js +982 -128
- package/dist/bin/exe-session-cleanup.js +1180 -306
- package/dist/bin/exe-settings.js +185 -105
- package/dist/bin/exe-start-codex.js +886 -132
- package/dist/bin/exe-start-opencode.js +873 -119
- package/dist/bin/exe-status.js +803 -59
- package/dist/bin/exe-team.js +772 -32
- package/dist/bin/git-sweep.js +1046 -223
- package/dist/bin/graph-backfill.js +779 -31
- package/dist/bin/graph-export.js +785 -37
- package/dist/bin/install.js +632 -200
- package/dist/bin/scan-tasks.js +1055 -232
- package/dist/bin/setup.js +1419 -320
- package/dist/bin/shard-migrate.js +783 -35
- package/dist/bin/update.js +138 -49
- package/dist/bin/wiki-sync.js +782 -34
- package/dist/gateway/index.js +1444 -449
- package/dist/hooks/bug-report-worker.js +1141 -269
- package/dist/hooks/codex-stop-task-finalizer.js +4678 -0
- package/dist/hooks/commit-complete.js +1044 -221
- package/dist/hooks/error-recall.js +989 -135
- package/dist/hooks/exe-heartbeat-hook.js +99 -75
- package/dist/hooks/ingest-worker.js +4176 -3226
- package/dist/hooks/ingest.js +920 -168
- package/dist/hooks/instructions-loaded.js +874 -70
- package/dist/hooks/notification.js +860 -56
- package/dist/hooks/post-compact.js +881 -73
- package/dist/hooks/pre-compact.js +1050 -227
- package/dist/hooks/pre-tool-use.js +1084 -159
- package/dist/hooks/prompt-ingest-worker.js +1089 -164
- package/dist/hooks/prompt-submit.js +1469 -515
- package/dist/hooks/response-ingest-worker.js +1104 -179
- package/dist/hooks/session-end.js +1085 -251
- package/dist/hooks/session-start.js +1241 -231
- package/dist/hooks/stop.js +935 -109
- package/dist/hooks/subagent-stop.js +881 -73
- package/dist/hooks/summary-worker.js +1323 -307
- package/dist/index.js +1449 -452
- package/dist/lib/agent-config.js +28 -6
- package/dist/lib/cloud-sync.js +909 -115
- package/dist/lib/config.js +30 -10
- package/dist/lib/consolidation.js +42 -9
- package/dist/lib/database.js +739 -33
- package/dist/lib/db-daemon-client.js +73 -19
- package/dist/lib/db.js +2359 -0
- package/dist/lib/device-registry.js +760 -47
- package/dist/lib/embedder.js +201 -73
- package/dist/lib/employee-templates.js +30 -4
- package/dist/lib/employees.js +290 -86
- package/dist/lib/exe-daemon-client.js +187 -83
- package/dist/lib/exe-daemon.js +1696 -616
- package/dist/lib/hybrid-search.js +982 -128
- package/dist/lib/identity.js +43 -13
- package/dist/lib/license.js +133 -48
- package/dist/lib/messaging.js +167 -80
- package/dist/lib/reminders.js +35 -5
- package/dist/lib/schedules.js +772 -32
- package/dist/lib/skill-learning.js +54 -7
- package/dist/lib/store.js +779 -31
- package/dist/lib/task-router.js +94 -73
- package/dist/lib/tasks.js +298 -225
- package/dist/lib/tmux-routing.js +246 -172
- package/dist/lib/token-spend.js +52 -14
- package/dist/mcp/server.js +2893 -850
- package/dist/mcp/tools/complete-reminder.js +35 -5
- package/dist/mcp/tools/create-reminder.js +35 -5
- package/dist/mcp/tools/create-task.js +507 -323
- package/dist/mcp/tools/deactivate-behavior.js +40 -10
- package/dist/mcp/tools/list-reminders.js +35 -5
- package/dist/mcp/tools/list-tasks.js +277 -104
- package/dist/mcp/tools/send-message.js +129 -56
- package/dist/mcp/tools/update-task.js +1864 -188
- package/dist/runtime/index.js +1083 -259
- package/dist/tui/App.js +1501 -434
- package/package.json +3 -2
package/dist/bin/exe-cloud.js
CHANGED
|
@@ -117,9 +117,34 @@ var init_keychain = __esm({
|
|
|
117
117
|
}
|
|
118
118
|
});
|
|
119
119
|
|
|
120
|
+
// src/lib/secure-files.ts
|
|
121
|
+
import { chmodSync, existsSync as existsSync2, mkdirSync } from "fs";
|
|
122
|
+
import { chmod as chmod2, mkdir as mkdir2 } from "fs/promises";
|
|
123
|
+
async function ensurePrivateDir(dirPath) {
|
|
124
|
+
await mkdir2(dirPath, { recursive: true, mode: PRIVATE_DIR_MODE });
|
|
125
|
+
try {
|
|
126
|
+
await chmod2(dirPath, PRIVATE_DIR_MODE);
|
|
127
|
+
} catch {
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
async function enforcePrivateFile(filePath) {
|
|
131
|
+
try {
|
|
132
|
+
await chmod2(filePath, PRIVATE_FILE_MODE);
|
|
133
|
+
} catch {
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
var PRIVATE_DIR_MODE, PRIVATE_FILE_MODE;
|
|
137
|
+
var init_secure_files = __esm({
|
|
138
|
+
"src/lib/secure-files.ts"() {
|
|
139
|
+
"use strict";
|
|
140
|
+
PRIVATE_DIR_MODE = 448;
|
|
141
|
+
PRIVATE_FILE_MODE = 384;
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
|
|
120
145
|
// src/lib/config.ts
|
|
121
|
-
import { readFile as readFile2, writeFile as writeFile2
|
|
122
|
-
import { readFileSync, existsSync as
|
|
146
|
+
import { readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
|
|
147
|
+
import { readFileSync, existsSync as existsSync3, renameSync } from "fs";
|
|
123
148
|
import path2 from "path";
|
|
124
149
|
import os2 from "os";
|
|
125
150
|
function resolveDataDir() {
|
|
@@ -127,7 +152,7 @@ function resolveDataDir() {
|
|
|
127
152
|
if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
|
|
128
153
|
const newDir = path2.join(os2.homedir(), ".exe-os");
|
|
129
154
|
const legacyDir = path2.join(os2.homedir(), ".exe-mem");
|
|
130
|
-
if (!
|
|
155
|
+
if (!existsSync3(newDir) && existsSync3(legacyDir)) {
|
|
131
156
|
try {
|
|
132
157
|
renameSync(legacyDir, newDir);
|
|
133
158
|
process.stderr.write(`[exe-os] Migrated data directory: ~/.exe-mem \u2192 ~/.exe-os
|
|
@@ -190,9 +215,9 @@ function normalizeAutoUpdate(raw) {
|
|
|
190
215
|
}
|
|
191
216
|
async function loadConfig() {
|
|
192
217
|
const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
|
|
193
|
-
await
|
|
218
|
+
await ensurePrivateDir(dir);
|
|
194
219
|
const configPath = path2.join(dir, "config.json");
|
|
195
|
-
if (!
|
|
220
|
+
if (!existsSync3(configPath)) {
|
|
196
221
|
return { ...DEFAULT_CONFIG, dbPath: path2.join(dir, "memories.db") };
|
|
197
222
|
}
|
|
198
223
|
const raw = await readFile2(configPath, "utf-8");
|
|
@@ -205,6 +230,7 @@ async function loadConfig() {
|
|
|
205
230
|
`);
|
|
206
231
|
try {
|
|
207
232
|
await writeFile2(configPath, JSON.stringify(migratedCfg, null, 2) + "\n");
|
|
233
|
+
await enforcePrivateFile(configPath);
|
|
208
234
|
} catch {
|
|
209
235
|
}
|
|
210
236
|
}
|
|
@@ -222,17 +248,16 @@ async function loadConfig() {
|
|
|
222
248
|
}
|
|
223
249
|
async function saveConfig(config) {
|
|
224
250
|
const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
|
|
225
|
-
await
|
|
251
|
+
await ensurePrivateDir(dir);
|
|
226
252
|
const configPath = path2.join(dir, "config.json");
|
|
227
253
|
await writeFile2(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
228
|
-
|
|
229
|
-
await chmod2(configPath, 384);
|
|
230
|
-
}
|
|
254
|
+
await enforcePrivateFile(configPath);
|
|
231
255
|
}
|
|
232
256
|
var EXE_AI_DIR, DB_PATH, MODELS_DIR, CONFIG_PATH, LEGACY_LANCE_PATH, CURRENT_CONFIG_VERSION, DEFAULT_CONFIG, CONFIG_MIGRATIONS;
|
|
233
257
|
var init_config = __esm({
|
|
234
258
|
"src/lib/config.ts"() {
|
|
235
259
|
"use strict";
|
|
260
|
+
init_secure_files();
|
|
236
261
|
EXE_AI_DIR = resolveDataDir();
|
|
237
262
|
DB_PATH = path2.join(EXE_AI_DIR, "memories.db");
|
|
238
263
|
MODELS_DIR = path2.join(EXE_AI_DIR, "models");
|
|
@@ -318,16 +343,38 @@ var init_db_retry = __esm({
|
|
|
318
343
|
|
|
319
344
|
// src/lib/employees.ts
|
|
320
345
|
import { readFile as readFile3, writeFile as writeFile3, mkdir as mkdir3 } from "fs/promises";
|
|
321
|
-
import { existsSync as
|
|
346
|
+
import { existsSync as existsSync4, symlinkSync, readlinkSync, readFileSync as readFileSync2, renameSync as renameSync2, unlinkSync, writeFileSync } from "fs";
|
|
322
347
|
import { execSync } from "child_process";
|
|
323
348
|
import path3 from "path";
|
|
324
349
|
import os3 from "os";
|
|
325
|
-
var EMPLOYEES_PATH;
|
|
350
|
+
var EMPLOYEES_PATH, IDENTITY_DIR;
|
|
326
351
|
var init_employees = __esm({
|
|
327
352
|
"src/lib/employees.ts"() {
|
|
328
353
|
"use strict";
|
|
329
354
|
init_config();
|
|
330
355
|
EMPLOYEES_PATH = path3.join(EXE_AI_DIR, "exe-employees.json");
|
|
356
|
+
IDENTITY_DIR = path3.join(EXE_AI_DIR, "identity");
|
|
357
|
+
}
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
// src/lib/database-adapter.ts
|
|
361
|
+
import os4 from "os";
|
|
362
|
+
import path4 from "path";
|
|
363
|
+
import { createRequire } from "module";
|
|
364
|
+
import { pathToFileURL } from "url";
|
|
365
|
+
var BOOLEAN_COLUMNS_BY_TABLE, BOOLEAN_COLUMN_NAMES;
|
|
366
|
+
var init_database_adapter = __esm({
|
|
367
|
+
"src/lib/database-adapter.ts"() {
|
|
368
|
+
"use strict";
|
|
369
|
+
BOOLEAN_COLUMNS_BY_TABLE = {
|
|
370
|
+
memories: /* @__PURE__ */ new Set(["has_error", "draft"]),
|
|
371
|
+
behaviors: /* @__PURE__ */ new Set(["active"]),
|
|
372
|
+
notifications: /* @__PURE__ */ new Set(["read"]),
|
|
373
|
+
users: /* @__PURE__ */ new Set(["has_personal_memory"])
|
|
374
|
+
};
|
|
375
|
+
BOOLEAN_COLUMN_NAMES = new Set(
|
|
376
|
+
Object.values(BOOLEAN_COLUMNS_BY_TABLE).flatMap((cols) => [...cols])
|
|
377
|
+
);
|
|
331
378
|
}
|
|
332
379
|
});
|
|
333
380
|
|
|
@@ -338,6 +385,7 @@ var init_database = __esm({
|
|
|
338
385
|
"use strict";
|
|
339
386
|
init_db_retry();
|
|
340
387
|
init_employees();
|
|
388
|
+
init_database_adapter();
|
|
341
389
|
}
|
|
342
390
|
});
|
|
343
391
|
|
|
@@ -358,9 +406,12 @@ __export(license_exports, {
|
|
|
358
406
|
stopLicenseRevalidation: () => stopLicenseRevalidation,
|
|
359
407
|
validateLicense: () => validateLicense
|
|
360
408
|
});
|
|
361
|
-
import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, existsSync as
|
|
409
|
+
import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, existsSync as existsSync5, mkdirSync as mkdirSync2 } from "fs";
|
|
362
410
|
import { randomUUID } from "crypto";
|
|
363
|
-
import
|
|
411
|
+
import { createRequire as createRequire2 } from "module";
|
|
412
|
+
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
413
|
+
import os5 from "os";
|
|
414
|
+
import path5 from "path";
|
|
364
415
|
import { jwtVerify, importSPKI } from "jose";
|
|
365
416
|
async function fetchRetry(url, init) {
|
|
366
417
|
try {
|
|
@@ -371,36 +422,36 @@ async function fetchRetry(url, init) {
|
|
|
371
422
|
}
|
|
372
423
|
}
|
|
373
424
|
function loadDeviceId() {
|
|
374
|
-
const deviceJsonPath =
|
|
425
|
+
const deviceJsonPath = path5.join(EXE_AI_DIR, "device.json");
|
|
375
426
|
try {
|
|
376
|
-
if (
|
|
427
|
+
if (existsSync5(deviceJsonPath)) {
|
|
377
428
|
const data = JSON.parse(readFileSync3(deviceJsonPath, "utf8"));
|
|
378
429
|
if (data.deviceId) return data.deviceId;
|
|
379
430
|
}
|
|
380
431
|
} catch {
|
|
381
432
|
}
|
|
382
433
|
try {
|
|
383
|
-
if (
|
|
434
|
+
if (existsSync5(DEVICE_ID_PATH)) {
|
|
384
435
|
const id2 = readFileSync3(DEVICE_ID_PATH, "utf8").trim();
|
|
385
436
|
if (id2) return id2;
|
|
386
437
|
}
|
|
387
438
|
} catch {
|
|
388
439
|
}
|
|
389
440
|
const id = randomUUID();
|
|
390
|
-
|
|
441
|
+
mkdirSync2(EXE_AI_DIR, { recursive: true });
|
|
391
442
|
writeFileSync2(DEVICE_ID_PATH, id, "utf8");
|
|
392
443
|
return id;
|
|
393
444
|
}
|
|
394
445
|
function loadLicense() {
|
|
395
446
|
try {
|
|
396
|
-
if (!
|
|
447
|
+
if (!existsSync5(LICENSE_PATH)) return null;
|
|
397
448
|
return readFileSync3(LICENSE_PATH, "utf8").trim();
|
|
398
449
|
} catch {
|
|
399
450
|
return null;
|
|
400
451
|
}
|
|
401
452
|
}
|
|
402
453
|
function saveLicense(apiKey) {
|
|
403
|
-
|
|
454
|
+
mkdirSync2(EXE_AI_DIR, { recursive: true });
|
|
404
455
|
writeFileSync2(LICENSE_PATH, apiKey.trim(), { encoding: "utf8", mode: 384 });
|
|
405
456
|
}
|
|
406
457
|
async function verifyLicenseJwt(token) {
|
|
@@ -427,7 +478,7 @@ async function verifyLicenseJwt(token) {
|
|
|
427
478
|
}
|
|
428
479
|
async function getCachedLicense() {
|
|
429
480
|
try {
|
|
430
|
-
if (!
|
|
481
|
+
if (!existsSync5(CACHE_PATH)) return null;
|
|
431
482
|
const raw = JSON.parse(readFileSync3(CACHE_PATH, "utf8"));
|
|
432
483
|
if (!raw.token || typeof raw.token !== "string") return null;
|
|
433
484
|
return await verifyLicenseJwt(raw.token);
|
|
@@ -437,7 +488,7 @@ async function getCachedLicense() {
|
|
|
437
488
|
}
|
|
438
489
|
function readCachedToken() {
|
|
439
490
|
try {
|
|
440
|
-
if (!
|
|
491
|
+
if (!existsSync5(CACHE_PATH)) return null;
|
|
441
492
|
const raw = JSON.parse(readFileSync3(CACHE_PATH, "utf8"));
|
|
442
493
|
return typeof raw.token === "string" ? raw.token : null;
|
|
443
494
|
} catch {
|
|
@@ -476,52 +527,126 @@ function cacheResponse(token) {
|
|
|
476
527
|
} catch {
|
|
477
528
|
}
|
|
478
529
|
}
|
|
479
|
-
|
|
480
|
-
|
|
530
|
+
function loadPrismaForLicense() {
|
|
531
|
+
if (_prismaFailed) return null;
|
|
532
|
+
const dbUrl = process.env.DATABASE_URL;
|
|
533
|
+
if (!dbUrl) {
|
|
534
|
+
const exeDbRoot = process.env.EXE_DB_ROOT ?? path5.join(os5.homedir(), "exe-db");
|
|
535
|
+
if (!existsSync5(path5.join(exeDbRoot, "package.json"))) {
|
|
536
|
+
_prismaFailed = true;
|
|
537
|
+
return null;
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
if (!_prismaPromise) {
|
|
541
|
+
_prismaPromise = (async () => {
|
|
542
|
+
const explicitPath = process.env.EXE_OS_PRISMA_CLIENT_PATH;
|
|
543
|
+
if (explicitPath) {
|
|
544
|
+
const mod2 = await import(pathToFileURL2(explicitPath).href);
|
|
545
|
+
const Ctor2 = mod2.PrismaClient ?? mod2.default?.PrismaClient;
|
|
546
|
+
if (!Ctor2) throw new Error(`No PrismaClient at ${explicitPath}`);
|
|
547
|
+
return new Ctor2();
|
|
548
|
+
}
|
|
549
|
+
const exeDbRoot = process.env.EXE_DB_ROOT ?? path5.join(os5.homedir(), "exe-db");
|
|
550
|
+
const req = createRequire2(path5.join(exeDbRoot, "package.json"));
|
|
551
|
+
const entry = req.resolve("@prisma/client");
|
|
552
|
+
const mod = await import(pathToFileURL2(entry).href);
|
|
553
|
+
const Ctor = mod.PrismaClient ?? mod.default?.PrismaClient;
|
|
554
|
+
if (!Ctor) throw new Error(`No PrismaClient in ${entry}`);
|
|
555
|
+
return new Ctor();
|
|
556
|
+
})().catch((err) => {
|
|
557
|
+
_prismaFailed = true;
|
|
558
|
+
_prismaPromise = null;
|
|
559
|
+
throw err;
|
|
560
|
+
});
|
|
561
|
+
}
|
|
562
|
+
return _prismaPromise;
|
|
563
|
+
}
|
|
564
|
+
async function validateViaPostgres(apiKey) {
|
|
565
|
+
const loader = loadPrismaForLicense();
|
|
566
|
+
if (!loader) return null;
|
|
567
|
+
try {
|
|
568
|
+
const prisma = await loader;
|
|
569
|
+
const rows = await prisma.$queryRawUnsafe(
|
|
570
|
+
`SELECT plan, email, status, device_limit, employee_limit, memory_limit, expires_at
|
|
571
|
+
FROM billing.licenses WHERE key = $1 LIMIT 1`,
|
|
572
|
+
apiKey
|
|
573
|
+
);
|
|
574
|
+
if (!rows || rows.length === 0) return null;
|
|
575
|
+
const row = rows[0];
|
|
576
|
+
if (row.status !== "active") return null;
|
|
577
|
+
if (row.expires_at && new Date(row.expires_at) < /* @__PURE__ */ new Date()) return null;
|
|
578
|
+
const plan = row.plan;
|
|
579
|
+
const limits = PLAN_LIMITS[plan] ?? PLAN_LIMITS.free;
|
|
580
|
+
return {
|
|
581
|
+
valid: true,
|
|
582
|
+
plan,
|
|
583
|
+
email: row.email,
|
|
584
|
+
expiresAt: row.expires_at ? new Date(row.expires_at).toISOString() : null,
|
|
585
|
+
deviceLimit: row.device_limit ?? limits.devices,
|
|
586
|
+
employeeLimit: row.employee_limit ?? limits.employees,
|
|
587
|
+
memoryLimit: row.memory_limit ?? limits.memories
|
|
588
|
+
};
|
|
589
|
+
} catch {
|
|
590
|
+
return null;
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
async function validateViaCFWorker(apiKey, deviceId) {
|
|
481
594
|
try {
|
|
482
595
|
const res = await fetchRetry(`${API_BASE}/auth/activate`, {
|
|
483
596
|
method: "POST",
|
|
484
597
|
headers: { "Content-Type": "application/json" },
|
|
485
|
-
body: JSON.stringify({ apiKey, deviceId
|
|
598
|
+
body: JSON.stringify({ apiKey, deviceId }),
|
|
486
599
|
signal: AbortSignal.timeout(1e4)
|
|
487
600
|
});
|
|
488
|
-
if (res.ok)
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
601
|
+
if (!res.ok) return null;
|
|
602
|
+
const data = await res.json();
|
|
603
|
+
if (data.error === "device_limit_exceeded") return null;
|
|
604
|
+
if (!data.valid) return null;
|
|
605
|
+
if (data.token) {
|
|
606
|
+
cacheResponse(data.token);
|
|
607
|
+
const verified = await verifyLicenseJwt(data.token);
|
|
608
|
+
if (verified) return verified;
|
|
609
|
+
}
|
|
610
|
+
const limits = PLAN_LIMITS[data.plan] ?? PLAN_LIMITS.free;
|
|
611
|
+
return {
|
|
612
|
+
valid: data.valid,
|
|
613
|
+
plan: data.plan,
|
|
614
|
+
email: data.email,
|
|
615
|
+
expiresAt: data.expiresAt,
|
|
616
|
+
deviceLimit: limits.devices,
|
|
617
|
+
employeeLimit: limits.employees,
|
|
618
|
+
memoryLimit: limits.memories
|
|
619
|
+
};
|
|
620
|
+
} catch {
|
|
621
|
+
return null;
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
async function validateLicense(apiKey, deviceId) {
|
|
625
|
+
const did = deviceId ?? loadDeviceId();
|
|
626
|
+
const pgResult = await validateViaPostgres(apiKey);
|
|
627
|
+
if (pgResult) {
|
|
628
|
+
try {
|
|
629
|
+
writeFileSync2(CACHE_PATH, JSON.stringify({ pgLicense: pgResult, ts: Date.now() }), "utf8");
|
|
630
|
+
} catch {
|
|
631
|
+
}
|
|
632
|
+
return pgResult;
|
|
633
|
+
}
|
|
634
|
+
const cfResult = await validateViaCFWorker(apiKey, did);
|
|
635
|
+
if (cfResult) return cfResult;
|
|
636
|
+
const cached = await getCachedLicense();
|
|
637
|
+
if (cached) return cached;
|
|
638
|
+
try {
|
|
639
|
+
if (existsSync5(CACHE_PATH)) {
|
|
640
|
+
const raw = JSON.parse(readFileSync3(CACHE_PATH, "utf8"));
|
|
641
|
+
if (raw.pgLicense && raw.ts && Date.now() - raw.ts < 7 * 24 * 60 * 60 * 1e3) {
|
|
642
|
+
return raw.pgLicense;
|
|
501
643
|
}
|
|
502
|
-
const limits = PLAN_LIMITS[data.plan] ?? PLAN_LIMITS.free;
|
|
503
|
-
return {
|
|
504
|
-
valid: data.valid,
|
|
505
|
-
plan: data.plan,
|
|
506
|
-
email: data.email,
|
|
507
|
-
expiresAt: data.expiresAt,
|
|
508
|
-
deviceLimit: limits.devices,
|
|
509
|
-
employeeLimit: limits.employees,
|
|
510
|
-
memoryLimit: limits.memories
|
|
511
|
-
};
|
|
512
644
|
}
|
|
513
|
-
const cached = await getCachedLicense();
|
|
514
|
-
if (cached) return cached;
|
|
515
|
-
const raw = getRawCachedPlan();
|
|
516
|
-
if (raw) return raw;
|
|
517
|
-
return { ...FREE_LICENSE, valid: false, plan: "free" };
|
|
518
645
|
} catch {
|
|
519
|
-
const cached = await getCachedLicense();
|
|
520
|
-
if (cached) return cached;
|
|
521
|
-
const rawFallback = getRawCachedPlan();
|
|
522
|
-
if (rawFallback) return rawFallback;
|
|
523
|
-
return { ...FREE_LICENSE, valid: false, error: "offline" };
|
|
524
646
|
}
|
|
647
|
+
const rawFallback = getRawCachedPlan();
|
|
648
|
+
if (rawFallback) return rawFallback;
|
|
649
|
+
return { ...FREE_LICENSE, valid: false };
|
|
525
650
|
}
|
|
526
651
|
function getCacheAgeMs() {
|
|
527
652
|
try {
|
|
@@ -536,8 +661,8 @@ async function checkLicense() {
|
|
|
536
661
|
let key = loadLicense();
|
|
537
662
|
if (!key) {
|
|
538
663
|
try {
|
|
539
|
-
const configPath =
|
|
540
|
-
if (
|
|
664
|
+
const configPath = path5.join(EXE_AI_DIR, "config.json");
|
|
665
|
+
if (existsSync5(configPath)) {
|
|
541
666
|
const raw = JSON.parse(readFileSync3(configPath, "utf8"));
|
|
542
667
|
const cloud = raw.cloud;
|
|
543
668
|
if (cloud?.apiKey) {
|
|
@@ -692,14 +817,14 @@ function stopLicenseRevalidation() {
|
|
|
692
817
|
_revalTimer = null;
|
|
693
818
|
}
|
|
694
819
|
}
|
|
695
|
-
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;
|
|
820
|
+
var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH, API_BASE, RETRY_DELAY_MS, LICENSE_PUBLIC_KEY_PEM, LICENSE_JWT_ALG, PLAN_LIMITS, FREE_LICENSE, _prismaPromise, _prismaFailed, CACHE_MAX_AGE_MS, _revalTimer;
|
|
696
821
|
var init_license = __esm({
|
|
697
822
|
"src/lib/license.ts"() {
|
|
698
823
|
"use strict";
|
|
699
824
|
init_config();
|
|
700
|
-
LICENSE_PATH =
|
|
701
|
-
CACHE_PATH =
|
|
702
|
-
DEVICE_ID_PATH =
|
|
825
|
+
LICENSE_PATH = path5.join(EXE_AI_DIR, "license.key");
|
|
826
|
+
CACHE_PATH = path5.join(EXE_AI_DIR, "license-cache.json");
|
|
827
|
+
DEVICE_ID_PATH = path5.join(EXE_AI_DIR, "device-id");
|
|
703
828
|
API_BASE = "https://askexe.com/cloud";
|
|
704
829
|
RETRY_DELAY_MS = 500;
|
|
705
830
|
LICENSE_PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----
|
|
@@ -723,6 +848,8 @@ MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeHztAMOpR/ZMh+rWuOASjEZ54CGY
|
|
|
723
848
|
employeeLimit: 1,
|
|
724
849
|
memoryLimit: 5e3
|
|
725
850
|
};
|
|
851
|
+
_prismaPromise = null;
|
|
852
|
+
_prismaFailed = false;
|
|
726
853
|
CACHE_MAX_AGE_MS = 36e5;
|
|
727
854
|
_revalTimer = null;
|
|
728
855
|
}
|
|
@@ -730,14 +857,14 @@ MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeHztAMOpR/ZMh+rWuOASjEZ54CGY
|
|
|
730
857
|
|
|
731
858
|
// src/lib/crdt-sync.ts
|
|
732
859
|
import * as Y from "yjs";
|
|
733
|
-
import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, existsSync as
|
|
734
|
-
import
|
|
860
|
+
import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, existsSync as existsSync6, mkdirSync as mkdirSync3, unlinkSync as unlinkSync2 } from "fs";
|
|
861
|
+
import path6 from "path";
|
|
735
862
|
import { homedir } from "os";
|
|
736
863
|
var DEFAULT_STATE_PATH;
|
|
737
864
|
var init_crdt_sync = __esm({
|
|
738
865
|
"src/lib/crdt-sync.ts"() {
|
|
739
866
|
"use strict";
|
|
740
|
-
DEFAULT_STATE_PATH =
|
|
867
|
+
DEFAULT_STATE_PATH = path6.join(homedir(), ".exe-os", "crdt-state.bin");
|
|
741
868
|
}
|
|
742
869
|
});
|
|
743
870
|
|
|
@@ -778,9 +905,9 @@ function isMainModule(importMetaUrl) {
|
|
|
778
905
|
|
|
779
906
|
// src/lib/cloud-sync.ts
|
|
780
907
|
init_database();
|
|
781
|
-
import { readFileSync as readFileSync5, writeFileSync as writeFileSync4, existsSync as
|
|
908
|
+
import { readFileSync as readFileSync5, writeFileSync as writeFileSync4, existsSync as existsSync7, readdirSync, mkdirSync as mkdirSync4, appendFileSync, unlinkSync as unlinkSync3, openSync, closeSync } from "fs";
|
|
782
909
|
import crypto3 from "crypto";
|
|
783
|
-
import
|
|
910
|
+
import path7 from "path";
|
|
784
911
|
import { homedir as homedir2 } from "os";
|
|
785
912
|
|
|
786
913
|
// src/lib/crypto.ts
|
|
@@ -794,8 +921,9 @@ init_license();
|
|
|
794
921
|
init_config();
|
|
795
922
|
init_crdt_sync();
|
|
796
923
|
init_employees();
|
|
924
|
+
init_secure_files();
|
|
797
925
|
var LOCALHOST_PATTERNS = /^(localhost|127\.0\.0\.1|\[::1\])$/i;
|
|
798
|
-
var ROSTER_LOCK_PATH =
|
|
926
|
+
var ROSTER_LOCK_PATH = path7.join(EXE_AI_DIR, "roster-merge.lock");
|
|
799
927
|
function assertSecureEndpoint(endpoint) {
|
|
800
928
|
if (endpoint.startsWith("https://")) return;
|
|
801
929
|
if (endpoint.startsWith("http://")) {
|
|
@@ -810,7 +938,7 @@ function assertSecureEndpoint(endpoint) {
|
|
|
810
938
|
);
|
|
811
939
|
}
|
|
812
940
|
}
|
|
813
|
-
var ROSTER_DELETIONS_PATH =
|
|
941
|
+
var ROSTER_DELETIONS_PATH = path7.join(EXE_AI_DIR, "roster-deletions.json");
|
|
814
942
|
|
|
815
943
|
// src/bin/exe-cloud.ts
|
|
816
944
|
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";
|