@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.
Files changed (101) hide show
  1. package/dist/bin/backfill-conversations.js +953 -105
  2. package/dist/bin/backfill-responses.js +952 -104
  3. package/dist/bin/backfill-vectors.js +956 -108
  4. package/dist/bin/cleanup-stale-review-tasks.js +802 -58
  5. package/dist/bin/cli.js +2292 -1070
  6. package/dist/bin/exe-agent-config.js +157 -101
  7. package/dist/bin/exe-agent.js +55 -29
  8. package/dist/bin/exe-assign.js +940 -92
  9. package/dist/bin/exe-boot.js +1424 -442
  10. package/dist/bin/exe-call.js +240 -141
  11. package/dist/bin/exe-cloud.js +198 -70
  12. package/dist/bin/exe-dispatch.js +951 -192
  13. package/dist/bin/exe-doctor.js +791 -51
  14. package/dist/bin/exe-export-behaviors.js +790 -42
  15. package/dist/bin/exe-forget.js +771 -31
  16. package/dist/bin/exe-gateway.js +1592 -521
  17. package/dist/bin/exe-heartbeat.js +850 -109
  18. package/dist/bin/exe-kill.js +783 -35
  19. package/dist/bin/exe-launch-agent.js +1030 -107
  20. package/dist/bin/exe-link.js +916 -110
  21. package/dist/bin/exe-new-employee.js +526 -217
  22. package/dist/bin/exe-pending-messages.js +1046 -62
  23. package/dist/bin/exe-pending-notifications.js +1318 -111
  24. package/dist/bin/exe-pending-reviews.js +1040 -72
  25. package/dist/bin/exe-rename.js +772 -59
  26. package/dist/bin/exe-review.js +772 -32
  27. package/dist/bin/exe-search.js +982 -128
  28. package/dist/bin/exe-session-cleanup.js +1180 -306
  29. package/dist/bin/exe-settings.js +185 -105
  30. package/dist/bin/exe-start-codex.js +886 -132
  31. package/dist/bin/exe-start-opencode.js +873 -119
  32. package/dist/bin/exe-status.js +803 -59
  33. package/dist/bin/exe-team.js +772 -32
  34. package/dist/bin/git-sweep.js +1046 -223
  35. package/dist/bin/graph-backfill.js +779 -31
  36. package/dist/bin/graph-export.js +785 -37
  37. package/dist/bin/install.js +632 -200
  38. package/dist/bin/scan-tasks.js +1055 -232
  39. package/dist/bin/setup.js +1419 -320
  40. package/dist/bin/shard-migrate.js +783 -35
  41. package/dist/bin/update.js +138 -49
  42. package/dist/bin/wiki-sync.js +782 -34
  43. package/dist/gateway/index.js +1444 -449
  44. package/dist/hooks/bug-report-worker.js +1141 -269
  45. package/dist/hooks/codex-stop-task-finalizer.js +4678 -0
  46. package/dist/hooks/commit-complete.js +1044 -221
  47. package/dist/hooks/error-recall.js +989 -135
  48. package/dist/hooks/exe-heartbeat-hook.js +99 -75
  49. package/dist/hooks/ingest-worker.js +4176 -3226
  50. package/dist/hooks/ingest.js +920 -168
  51. package/dist/hooks/instructions-loaded.js +874 -70
  52. package/dist/hooks/notification.js +860 -56
  53. package/dist/hooks/post-compact.js +881 -73
  54. package/dist/hooks/pre-compact.js +1050 -227
  55. package/dist/hooks/pre-tool-use.js +1084 -159
  56. package/dist/hooks/prompt-ingest-worker.js +1089 -164
  57. package/dist/hooks/prompt-submit.js +1469 -515
  58. package/dist/hooks/response-ingest-worker.js +1104 -179
  59. package/dist/hooks/session-end.js +1085 -251
  60. package/dist/hooks/session-start.js +1241 -231
  61. package/dist/hooks/stop.js +935 -109
  62. package/dist/hooks/subagent-stop.js +881 -73
  63. package/dist/hooks/summary-worker.js +1323 -307
  64. package/dist/index.js +1449 -452
  65. package/dist/lib/agent-config.js +28 -6
  66. package/dist/lib/cloud-sync.js +909 -115
  67. package/dist/lib/config.js +30 -10
  68. package/dist/lib/consolidation.js +42 -9
  69. package/dist/lib/database.js +739 -33
  70. package/dist/lib/db-daemon-client.js +73 -19
  71. package/dist/lib/db.js +2359 -0
  72. package/dist/lib/device-registry.js +760 -47
  73. package/dist/lib/embedder.js +201 -73
  74. package/dist/lib/employee-templates.js +30 -4
  75. package/dist/lib/employees.js +290 -86
  76. package/dist/lib/exe-daemon-client.js +187 -83
  77. package/dist/lib/exe-daemon.js +1696 -616
  78. package/dist/lib/hybrid-search.js +982 -128
  79. package/dist/lib/identity.js +43 -13
  80. package/dist/lib/license.js +133 -48
  81. package/dist/lib/messaging.js +167 -80
  82. package/dist/lib/reminders.js +35 -5
  83. package/dist/lib/schedules.js +772 -32
  84. package/dist/lib/skill-learning.js +54 -7
  85. package/dist/lib/store.js +779 -31
  86. package/dist/lib/task-router.js +94 -73
  87. package/dist/lib/tasks.js +298 -225
  88. package/dist/lib/tmux-routing.js +246 -172
  89. package/dist/lib/token-spend.js +52 -14
  90. package/dist/mcp/server.js +2893 -850
  91. package/dist/mcp/tools/complete-reminder.js +35 -5
  92. package/dist/mcp/tools/create-reminder.js +35 -5
  93. package/dist/mcp/tools/create-task.js +507 -323
  94. package/dist/mcp/tools/deactivate-behavior.js +40 -10
  95. package/dist/mcp/tools/list-reminders.js +35 -5
  96. package/dist/mcp/tools/list-tasks.js +277 -104
  97. package/dist/mcp/tools/send-message.js +129 -56
  98. package/dist/mcp/tools/update-task.js +1864 -188
  99. package/dist/runtime/index.js +1083 -259
  100. package/dist/tui/App.js +1501 -434
  101. package/package.json +3 -2
@@ -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, mkdir as mkdir2, chmod as chmod2 } from "fs/promises";
122
- import { readFileSync, existsSync as existsSync2, renameSync } from "fs";
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 (!existsSync2(newDir) && existsSync2(legacyDir)) {
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 mkdir2(dir, { recursive: true });
218
+ await ensurePrivateDir(dir);
194
219
  const configPath = path2.join(dir, "config.json");
195
- if (!existsSync2(configPath)) {
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 mkdir2(dir, { recursive: true });
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
- if (config.cloud?.apiKey) {
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 existsSync3, symlinkSync, readlinkSync, readFileSync as readFileSync2, renameSync as renameSync2, unlinkSync, writeFileSync } from "fs";
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 existsSync4, mkdirSync } from "fs";
409
+ import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, existsSync as existsSync5, mkdirSync as mkdirSync2 } from "fs";
362
410
  import { randomUUID } from "crypto";
363
- import path4 from "path";
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 = path4.join(EXE_AI_DIR, "device.json");
425
+ const deviceJsonPath = path5.join(EXE_AI_DIR, "device.json");
375
426
  try {
376
- if (existsSync4(deviceJsonPath)) {
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 (existsSync4(DEVICE_ID_PATH)) {
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
- mkdirSync(EXE_AI_DIR, { recursive: true });
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 (!existsSync4(LICENSE_PATH)) return null;
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
- mkdirSync(EXE_AI_DIR, { recursive: true });
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 (!existsSync4(CACHE_PATH)) return null;
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 (!existsSync4(CACHE_PATH)) return null;
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
- async function validateLicense(apiKey, deviceId) {
480
- const did = deviceId ?? loadDeviceId();
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: did }),
598
+ body: JSON.stringify({ apiKey, deviceId }),
486
599
  signal: AbortSignal.timeout(1e4)
487
600
  });
488
- if (res.ok) {
489
- const data = await res.json();
490
- if (data.error === "device_limit_exceeded") {
491
- const cached2 = await getCachedLicense();
492
- if (cached2) return cached2;
493
- const raw2 = getRawCachedPlan();
494
- if (raw2) return { ...raw2, valid: false };
495
- return { ...FREE_LICENSE, valid: false, plan: "free" };
496
- }
497
- if (data.token) {
498
- cacheResponse(data.token);
499
- const verified = await verifyLicenseJwt(data.token);
500
- if (verified) return verified;
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 = path4.join(EXE_AI_DIR, "config.json");
540
- if (existsSync4(configPath)) {
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 = path4.join(EXE_AI_DIR, "license.key");
701
- CACHE_PATH = path4.join(EXE_AI_DIR, "license-cache.json");
702
- DEVICE_ID_PATH = path4.join(EXE_AI_DIR, "device-id");
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 existsSync5, mkdirSync as mkdirSync2, unlinkSync as unlinkSync2 } from "fs";
734
- import path5 from "path";
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 = path5.join(homedir(), ".exe-os", "crdt-state.bin");
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 existsSync6, readdirSync, mkdirSync as mkdirSync3, appendFileSync, unlinkSync as unlinkSync3, openSync, closeSync } from "fs";
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 path6 from "path";
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 = path6.join(EXE_AI_DIR, "roster-merge.lock");
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 = path6.join(EXE_AI_DIR, "roster-deletions.json");
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";