@askexenow/exe-os 0.9.8 → 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 +222 -49
  2. package/dist/bin/backfill-responses.js +221 -48
  3. package/dist/bin/backfill-vectors.js +225 -52
  4. package/dist/bin/cleanup-stale-review-tasks.js +150 -28
  5. package/dist/bin/cli.js +1295 -856
  6. package/dist/bin/exe-agent-config.js +36 -8
  7. package/dist/bin/exe-agent.js +14 -4
  8. package/dist/bin/exe-assign.js +221 -48
  9. package/dist/bin/exe-boot.js +778 -427
  10. package/dist/bin/exe-call.js +41 -13
  11. package/dist/bin/exe-cloud.js +163 -58
  12. package/dist/bin/exe-dispatch.js +276 -139
  13. package/dist/bin/exe-doctor.js +145 -27
  14. package/dist/bin/exe-export-behaviors.js +141 -23
  15. package/dist/bin/exe-forget.js +137 -19
  16. package/dist/bin/exe-gateway.js +677 -388
  17. package/dist/bin/exe-heartbeat.js +227 -108
  18. package/dist/bin/exe-kill.js +138 -20
  19. package/dist/bin/exe-launch-agent.js +172 -39
  20. package/dist/bin/exe-link.js +291 -100
  21. package/dist/bin/exe-new-employee.js +214 -106
  22. package/dist/bin/exe-pending-messages.js +395 -33
  23. package/dist/bin/exe-pending-notifications.js +684 -99
  24. package/dist/bin/exe-pending-reviews.js +420 -74
  25. package/dist/bin/exe-rename.js +147 -49
  26. package/dist/bin/exe-review.js +138 -20
  27. package/dist/bin/exe-search.js +240 -69
  28. package/dist/bin/exe-session-cleanup.js +440 -250
  29. package/dist/bin/exe-settings.js +61 -17
  30. package/dist/bin/exe-start-codex.js +158 -39
  31. package/dist/bin/exe-start-opencode.js +157 -38
  32. package/dist/bin/exe-status.js +151 -29
  33. package/dist/bin/exe-team.js +138 -20
  34. package/dist/bin/git-sweep.js +404 -212
  35. package/dist/bin/graph-backfill.js +137 -19
  36. package/dist/bin/graph-export.js +140 -22
  37. package/dist/bin/install.js +90 -61
  38. package/dist/bin/scan-tasks.js +412 -220
  39. package/dist/bin/setup.js +564 -293
  40. package/dist/bin/shard-migrate.js +139 -21
  41. package/dist/bin/update.js +138 -49
  42. package/dist/bin/wiki-sync.js +137 -19
  43. package/dist/gateway/index.js +533 -320
  44. package/dist/hooks/bug-report-worker.js +344 -193
  45. package/dist/hooks/codex-stop-task-finalizer.js +4678 -0
  46. package/dist/hooks/commit-complete.js +402 -210
  47. package/dist/hooks/error-recall.js +245 -74
  48. package/dist/hooks/exe-heartbeat-hook.js +16 -6
  49. package/dist/hooks/ingest-worker.js +3423 -3157
  50. package/dist/hooks/ingest.js +832 -97
  51. package/dist/hooks/instructions-loaded.js +227 -54
  52. package/dist/hooks/notification.js +216 -43
  53. package/dist/hooks/post-compact.js +239 -62
  54. package/dist/hooks/pre-compact.js +408 -216
  55. package/dist/hooks/pre-tool-use.js +268 -90
  56. package/dist/hooks/prompt-ingest-worker.js +352 -102
  57. package/dist/hooks/prompt-submit.js +541 -328
  58. package/dist/hooks/response-ingest-worker.js +372 -122
  59. package/dist/hooks/session-end.js +443 -240
  60. package/dist/hooks/session-start.js +313 -127
  61. package/dist/hooks/stop.js +293 -98
  62. package/dist/hooks/subagent-stop.js +239 -62
  63. package/dist/hooks/summary-worker.js +568 -236
  64. package/dist/index.js +538 -324
  65. package/dist/lib/agent-config.js +28 -6
  66. package/dist/lib/cloud-sync.js +284 -105
  67. package/dist/lib/config.js +30 -10
  68. package/dist/lib/consolidation.js +16 -6
  69. package/dist/lib/database.js +123 -25
  70. package/dist/lib/db-daemon-client.js +73 -19
  71. package/dist/lib/db.js +123 -25
  72. package/dist/lib/device-registry.js +133 -35
  73. package/dist/lib/embedder.js +107 -32
  74. package/dist/lib/employee-templates.js +14 -4
  75. package/dist/lib/employees.js +41 -13
  76. package/dist/lib/exe-daemon-client.js +88 -22
  77. package/dist/lib/exe-daemon.js +935 -587
  78. package/dist/lib/hybrid-search.js +240 -69
  79. package/dist/lib/identity.js +18 -8
  80. package/dist/lib/license.js +133 -48
  81. package/dist/lib/messaging.js +116 -56
  82. package/dist/lib/reminders.js +14 -4
  83. package/dist/lib/schedules.js +137 -19
  84. package/dist/lib/skill-learning.js +33 -6
  85. package/dist/lib/store.js +137 -19
  86. package/dist/lib/task-router.js +14 -4
  87. package/dist/lib/tasks.js +280 -234
  88. package/dist/lib/tmux-routing.js +172 -125
  89. package/dist/lib/token-spend.js +26 -8
  90. package/dist/mcp/server.js +1326 -609
  91. package/dist/mcp/tools/complete-reminder.js +14 -4
  92. package/dist/mcp/tools/create-reminder.js +14 -4
  93. package/dist/mcp/tools/create-task.js +306 -248
  94. package/dist/mcp/tools/deactivate-behavior.js +16 -6
  95. package/dist/mcp/tools/list-reminders.js +14 -4
  96. package/dist/mcp/tools/list-tasks.js +123 -107
  97. package/dist/mcp/tools/send-message.js +75 -29
  98. package/dist/mcp/tools/update-task.js +1848 -199
  99. package/dist/runtime/index.js +441 -248
  100. package/dist/tui/App.js +761 -424
  101. package/package.json +1 -1
@@ -78,6 +78,44 @@ var init_db_retry = __esm({
78
78
  }
79
79
  });
80
80
 
81
+ // src/lib/secure-files.ts
82
+ import { chmodSync, existsSync, mkdirSync } from "fs";
83
+ import { chmod, mkdir } from "fs/promises";
84
+ async function ensurePrivateDir(dirPath) {
85
+ await mkdir(dirPath, { recursive: true, mode: PRIVATE_DIR_MODE });
86
+ try {
87
+ await chmod(dirPath, PRIVATE_DIR_MODE);
88
+ } catch {
89
+ }
90
+ }
91
+ function ensurePrivateDirSync(dirPath) {
92
+ mkdirSync(dirPath, { recursive: true, mode: PRIVATE_DIR_MODE });
93
+ try {
94
+ chmodSync(dirPath, PRIVATE_DIR_MODE);
95
+ } catch {
96
+ }
97
+ }
98
+ async function enforcePrivateFile(filePath) {
99
+ try {
100
+ await chmod(filePath, PRIVATE_FILE_MODE);
101
+ } catch {
102
+ }
103
+ }
104
+ function enforcePrivateFileSync(filePath) {
105
+ try {
106
+ if (existsSync(filePath)) chmodSync(filePath, PRIVATE_FILE_MODE);
107
+ } catch {
108
+ }
109
+ }
110
+ var PRIVATE_DIR_MODE, PRIVATE_FILE_MODE;
111
+ var init_secure_files = __esm({
112
+ "src/lib/secure-files.ts"() {
113
+ "use strict";
114
+ PRIVATE_DIR_MODE = 448;
115
+ PRIVATE_FILE_MODE = 384;
116
+ }
117
+ });
118
+
81
119
  // src/lib/config.ts
82
120
  var config_exports = {};
83
121
  __export(config_exports, {
@@ -94,8 +132,8 @@ __export(config_exports, {
94
132
  migrateConfig: () => migrateConfig,
95
133
  saveConfig: () => saveConfig
96
134
  });
97
- import { readFile, writeFile, mkdir, chmod } from "fs/promises";
98
- import { readFileSync, existsSync, renameSync } from "fs";
135
+ import { readFile, writeFile } from "fs/promises";
136
+ import { readFileSync, existsSync as existsSync2, renameSync } from "fs";
99
137
  import path2 from "path";
100
138
  import os from "os";
101
139
  function resolveDataDir() {
@@ -103,7 +141,7 @@ function resolveDataDir() {
103
141
  if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
104
142
  const newDir = path2.join(os.homedir(), ".exe-os");
105
143
  const legacyDir = path2.join(os.homedir(), ".exe-mem");
106
- if (!existsSync(newDir) && existsSync(legacyDir)) {
144
+ if (!existsSync2(newDir) && existsSync2(legacyDir)) {
107
145
  try {
108
146
  renameSync(legacyDir, newDir);
109
147
  process.stderr.write(`[exe-os] Migrated data directory: ~/.exe-mem \u2192 ~/.exe-os
@@ -166,9 +204,9 @@ function normalizeAutoUpdate(raw) {
166
204
  }
167
205
  async function loadConfig() {
168
206
  const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
169
- await mkdir(dir, { recursive: true });
207
+ await ensurePrivateDir(dir);
170
208
  const configPath = path2.join(dir, "config.json");
171
- if (!existsSync(configPath)) {
209
+ if (!existsSync2(configPath)) {
172
210
  return { ...DEFAULT_CONFIG, dbPath: path2.join(dir, "memories.db") };
173
211
  }
174
212
  const raw = await readFile(configPath, "utf-8");
@@ -181,6 +219,7 @@ async function loadConfig() {
181
219
  `);
182
220
  try {
183
221
  await writeFile(configPath, JSON.stringify(migratedCfg, null, 2) + "\n");
222
+ await enforcePrivateFile(configPath);
184
223
  } catch {
185
224
  }
186
225
  }
@@ -199,7 +238,7 @@ async function loadConfig() {
199
238
  function loadConfigSync() {
200
239
  const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
201
240
  const configPath = path2.join(dir, "config.json");
202
- if (!existsSync(configPath)) {
241
+ if (!existsSync2(configPath)) {
203
242
  return { ...DEFAULT_CONFIG, dbPath: path2.join(dir, "memories.db") };
204
243
  }
205
244
  try {
@@ -217,12 +256,10 @@ function loadConfigSync() {
217
256
  }
218
257
  async function saveConfig(config) {
219
258
  const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
220
- await mkdir(dir, { recursive: true });
259
+ await ensurePrivateDir(dir);
221
260
  const configPath = path2.join(dir, "config.json");
222
261
  await writeFile(configPath, JSON.stringify(config, null, 2) + "\n");
223
- if (config.cloud?.apiKey) {
224
- await chmod(configPath, 384);
225
- }
262
+ await enforcePrivateFile(configPath);
226
263
  }
227
264
  async function loadConfigFrom(configPath) {
228
265
  const raw = await readFile(configPath, "utf-8");
@@ -242,6 +279,7 @@ var EXE_AI_DIR, DB_PATH, MODELS_DIR, CONFIG_PATH, LEGACY_LANCE_PATH, CURRENT_CON
242
279
  var init_config = __esm({
243
280
  "src/lib/config.ts"() {
244
281
  "use strict";
282
+ init_secure_files();
245
283
  EXE_AI_DIR = resolveDataDir();
246
284
  DB_PATH = path2.join(EXE_AI_DIR, "memories.db");
247
285
  MODELS_DIR = path2.join(EXE_AI_DIR, "models");
@@ -320,7 +358,7 @@ var init_config = __esm({
320
358
 
321
359
  // src/lib/employees.ts
322
360
  import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
323
- import { existsSync as existsSync2, symlinkSync, readlinkSync, readFileSync as readFileSync2, renameSync as renameSync2, unlinkSync, writeFileSync } from "fs";
361
+ import { existsSync as existsSync3, symlinkSync, readlinkSync, readFileSync as readFileSync2, renameSync as renameSync2, unlinkSync, writeFileSync } from "fs";
324
362
  import { execSync as execSync2 } from "child_process";
325
363
  import path3 from "path";
326
364
  import os2 from "os";
@@ -337,7 +375,7 @@ function getCoordinatorName(employees = loadEmployeesSync()) {
337
375
  return getCoordinatorEmployee(employees)?.name ?? DEFAULT_COORDINATOR_TEMPLATE_NAME;
338
376
  }
339
377
  async function loadEmployees(employeesPath = EMPLOYEES_PATH) {
340
- if (!existsSync2(employeesPath)) {
378
+ if (!existsSync3(employeesPath)) {
341
379
  return [];
342
380
  }
343
381
  const raw = await readFile2(employeesPath, "utf-8");
@@ -348,7 +386,7 @@ async function loadEmployees(employeesPath = EMPLOYEES_PATH) {
348
386
  }
349
387
  }
350
388
  function loadEmployeesSync(employeesPath = EMPLOYEES_PATH) {
351
- if (!existsSync2(employeesPath)) return [];
389
+ if (!existsSync3(employeesPath)) return [];
352
390
  try {
353
391
  return JSON.parse(readFileSync2(employeesPath, "utf-8"));
354
392
  } catch {
@@ -1296,6 +1334,7 @@ async function ensureSchema() {
1296
1334
  project TEXT NOT NULL,
1297
1335
  summary TEXT NOT NULL,
1298
1336
  task_file TEXT,
1337
+ session_scope TEXT,
1299
1338
  read INTEGER NOT NULL DEFAULT 0,
1300
1339
  created_at TEXT NOT NULL
1301
1340
  );
@@ -1304,7 +1343,7 @@ async function ensureSchema() {
1304
1343
  ON notifications(read);
1305
1344
 
1306
1345
  CREATE INDEX IF NOT EXISTS idx_notifications_agent
1307
- ON notifications(agent_id);
1346
+ ON notifications(agent_id, session_scope);
1308
1347
 
1309
1348
  CREATE INDEX IF NOT EXISTS idx_notifications_task_file
1310
1349
  ON notifications(task_file);
@@ -1342,6 +1381,7 @@ async function ensureSchema() {
1342
1381
  target_agent TEXT NOT NULL,
1343
1382
  target_project TEXT,
1344
1383
  target_device TEXT NOT NULL DEFAULT 'local',
1384
+ session_scope TEXT,
1345
1385
  content TEXT NOT NULL,
1346
1386
  priority TEXT DEFAULT 'normal',
1347
1387
  status TEXT DEFAULT 'pending',
@@ -1355,10 +1395,31 @@ async function ensureSchema() {
1355
1395
  );
1356
1396
 
1357
1397
  CREATE INDEX IF NOT EXISTS idx_messages_target
1358
- ON messages(target_agent, status);
1398
+ ON messages(target_agent, session_scope, status);
1359
1399
 
1360
1400
  CREATE INDEX IF NOT EXISTS idx_messages_conversation_order
1361
- ON messages(target_agent, from_agent, server_seq);
1401
+ ON messages(target_agent, session_scope, from_agent, server_seq);
1402
+ `);
1403
+ try {
1404
+ await client.execute({
1405
+ sql: `ALTER TABLE notifications ADD COLUMN session_scope TEXT`,
1406
+ args: []
1407
+ });
1408
+ } catch {
1409
+ }
1410
+ try {
1411
+ await client.execute({
1412
+ sql: `ALTER TABLE messages ADD COLUMN session_scope TEXT`,
1413
+ args: []
1414
+ });
1415
+ } catch {
1416
+ }
1417
+ await client.executeMultiple(`
1418
+ CREATE INDEX IF NOT EXISTS idx_notifications_agent_scope_read
1419
+ ON notifications(agent_id, session_scope, read, created_at);
1420
+
1421
+ CREATE INDEX IF NOT EXISTS idx_messages_target_scope_status
1422
+ ON messages(target_agent, session_scope, status, created_at);
1362
1423
  `);
1363
1424
  try {
1364
1425
  await client.execute({
@@ -1942,6 +2003,13 @@ async function ensureSchema() {
1942
2003
  } catch {
1943
2004
  }
1944
2005
  }
2006
+ try {
2007
+ await client.execute({
2008
+ sql: `UPDATE tasks SET status = 'closed' WHERE status = 'done' AND result IS NOT NULL`,
2009
+ args: []
2010
+ });
2011
+ } catch {
2012
+ }
1945
2013
  }
1946
2014
  var _client, _resilientClient, _walCheckpointTimer, _daemonClient, _adapterClient, initTurso;
1947
2015
  var init_database = __esm({
@@ -1964,6 +2032,7 @@ var shard_manager_exports = {};
1964
2032
  __export(shard_manager_exports, {
1965
2033
  disposeShards: () => disposeShards,
1966
2034
  ensureShardSchema: () => ensureShardSchema,
2035
+ getOpenShardCount: () => getOpenShardCount,
1967
2036
  getReadyShardClient: () => getReadyShardClient,
1968
2037
  getShardClient: () => getShardClient,
1969
2038
  getShardsDir: () => getShardsDir,
@@ -1973,14 +2042,17 @@ __export(shard_manager_exports, {
1973
2042
  shardExists: () => shardExists
1974
2043
  });
1975
2044
  import path6 from "path";
1976
- import { existsSync as existsSync4, mkdirSync, readdirSync } from "fs";
2045
+ import { existsSync as existsSync5, mkdirSync as mkdirSync2, readdirSync } from "fs";
1977
2046
  import { createClient as createClient2 } from "@libsql/client";
1978
2047
  function initShardManager(encryptionKey) {
1979
2048
  _encryptionKey = encryptionKey;
1980
- if (!existsSync4(SHARDS_DIR)) {
1981
- mkdirSync(SHARDS_DIR, { recursive: true });
2049
+ if (!existsSync5(SHARDS_DIR)) {
2050
+ mkdirSync2(SHARDS_DIR, { recursive: true });
1982
2051
  }
1983
2052
  _shardingEnabled = true;
2053
+ if (_evictionTimer) clearInterval(_evictionTimer);
2054
+ _evictionTimer = setInterval(evictIdleShards, EVICTION_INTERVAL_MS);
2055
+ _evictionTimer.unref();
1984
2056
  }
1985
2057
  function isShardingEnabled() {
1986
2058
  return _shardingEnabled;
@@ -1997,21 +2069,28 @@ function getShardClient(projectName) {
1997
2069
  throw new Error(`Invalid project name for shard: "${projectName}"`);
1998
2070
  }
1999
2071
  const cached = _shards.get(safeName);
2000
- if (cached) return cached;
2072
+ if (cached) {
2073
+ _shardLastAccess.set(safeName, Date.now());
2074
+ return cached;
2075
+ }
2076
+ while (_shards.size >= MAX_OPEN_SHARDS) {
2077
+ evictLRU();
2078
+ }
2001
2079
  const dbPath = path6.join(SHARDS_DIR, `${safeName}.db`);
2002
2080
  const client = createClient2({
2003
2081
  url: `file:${dbPath}`,
2004
2082
  encryptionKey: _encryptionKey
2005
2083
  });
2006
2084
  _shards.set(safeName, client);
2085
+ _shardLastAccess.set(safeName, Date.now());
2007
2086
  return client;
2008
2087
  }
2009
2088
  function shardExists(projectName) {
2010
2089
  const safeName = projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
2011
- return existsSync4(path6.join(SHARDS_DIR, `${safeName}.db`));
2090
+ return existsSync5(path6.join(SHARDS_DIR, `${safeName}.db`));
2012
2091
  }
2013
2092
  function listShards() {
2014
- if (!existsSync4(SHARDS_DIR)) return [];
2093
+ if (!existsSync5(SHARDS_DIR)) return [];
2015
2094
  return readdirSync(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
2016
2095
  }
2017
2096
  async function ensureShardSchema(client) {
@@ -2063,6 +2142,8 @@ async function ensureShardSchema(client) {
2063
2142
  for (const col of [
2064
2143
  "ALTER TABLE memories ADD COLUMN task_id TEXT",
2065
2144
  "ALTER TABLE memories ADD COLUMN consolidated INTEGER NOT NULL DEFAULT 0",
2145
+ "ALTER TABLE memories ADD COLUMN author_device_id TEXT",
2146
+ "ALTER TABLE memories ADD COLUMN scope TEXT NOT NULL DEFAULT 'business'",
2066
2147
  "ALTER TABLE memories ADD COLUMN importance INTEGER DEFAULT 5",
2067
2148
  "ALTER TABLE memories ADD COLUMN status TEXT DEFAULT 'active'",
2068
2149
  "ALTER TABLE memories ADD COLUMN wiki_synced INTEGER DEFAULT 0",
@@ -2200,21 +2281,69 @@ async function getReadyShardClient(projectName) {
2200
2281
  await ensureShardSchema(client);
2201
2282
  return client;
2202
2283
  }
2284
+ function evictLRU() {
2285
+ let oldest = null;
2286
+ let oldestTime = Infinity;
2287
+ for (const [name, time] of _shardLastAccess) {
2288
+ if (time < oldestTime) {
2289
+ oldestTime = time;
2290
+ oldest = name;
2291
+ }
2292
+ }
2293
+ if (oldest) {
2294
+ const client = _shards.get(oldest);
2295
+ if (client) {
2296
+ client.close();
2297
+ }
2298
+ _shards.delete(oldest);
2299
+ _shardLastAccess.delete(oldest);
2300
+ }
2301
+ }
2302
+ function evictIdleShards() {
2303
+ const now = Date.now();
2304
+ const toEvict = [];
2305
+ for (const [name, lastAccess] of _shardLastAccess) {
2306
+ if (now - lastAccess > SHARD_IDLE_MS) {
2307
+ toEvict.push(name);
2308
+ }
2309
+ }
2310
+ for (const name of toEvict) {
2311
+ const client = _shards.get(name);
2312
+ if (client) {
2313
+ client.close();
2314
+ }
2315
+ _shards.delete(name);
2316
+ _shardLastAccess.delete(name);
2317
+ }
2318
+ }
2319
+ function getOpenShardCount() {
2320
+ return _shards.size;
2321
+ }
2203
2322
  function disposeShards() {
2323
+ if (_evictionTimer) {
2324
+ clearInterval(_evictionTimer);
2325
+ _evictionTimer = null;
2326
+ }
2204
2327
  for (const [, client] of _shards) {
2205
2328
  client.close();
2206
2329
  }
2207
2330
  _shards.clear();
2331
+ _shardLastAccess.clear();
2208
2332
  _shardingEnabled = false;
2209
2333
  _encryptionKey = null;
2210
2334
  }
2211
- var SHARDS_DIR, _shards, _encryptionKey, _shardingEnabled;
2335
+ var SHARDS_DIR, SHARD_IDLE_MS, MAX_OPEN_SHARDS, EVICTION_INTERVAL_MS, _shards, _shardLastAccess, _evictionTimer, _encryptionKey, _shardingEnabled;
2212
2336
  var init_shard_manager = __esm({
2213
2337
  "src/lib/shard-manager.ts"() {
2214
2338
  "use strict";
2215
2339
  init_config();
2216
2340
  SHARDS_DIR = path6.join(EXE_AI_DIR, "shards");
2341
+ SHARD_IDLE_MS = 5 * 60 * 1e3;
2342
+ MAX_OPEN_SHARDS = 10;
2343
+ EVICTION_INTERVAL_MS = 60 * 1e3;
2217
2344
  _shards = /* @__PURE__ */ new Map();
2345
+ _shardLastAccess = /* @__PURE__ */ new Map();
2346
+ _evictionTimer = null;
2218
2347
  _encryptionKey = null;
2219
2348
  _shardingEnabled = false;
2220
2349
  }
@@ -2407,13 +2536,50 @@ ${p.content}`).join("\n\n");
2407
2536
  }
2408
2537
  });
2409
2538
 
2539
+ // src/lib/daemon-auth.ts
2540
+ import crypto from "crypto";
2541
+ import path7 from "path";
2542
+ import { existsSync as existsSync6, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
2543
+ function normalizeToken(token) {
2544
+ if (!token) return null;
2545
+ const trimmed = token.trim();
2546
+ return trimmed.length > 0 ? trimmed : null;
2547
+ }
2548
+ function readDaemonToken() {
2549
+ try {
2550
+ if (!existsSync6(DAEMON_TOKEN_PATH)) return null;
2551
+ return normalizeToken(readFileSync3(DAEMON_TOKEN_PATH, "utf8"));
2552
+ } catch {
2553
+ return null;
2554
+ }
2555
+ }
2556
+ function ensureDaemonToken(seed) {
2557
+ const existing = readDaemonToken();
2558
+ if (existing) return existing;
2559
+ const token = normalizeToken(seed) ?? crypto.randomBytes(32).toString("hex");
2560
+ ensurePrivateDirSync(EXE_AI_DIR);
2561
+ writeFileSync2(DAEMON_TOKEN_PATH, `${token}
2562
+ `, "utf8");
2563
+ enforcePrivateFileSync(DAEMON_TOKEN_PATH);
2564
+ return token;
2565
+ }
2566
+ var DAEMON_TOKEN_PATH;
2567
+ var init_daemon_auth = __esm({
2568
+ "src/lib/daemon-auth.ts"() {
2569
+ "use strict";
2570
+ init_config();
2571
+ init_secure_files();
2572
+ DAEMON_TOKEN_PATH = path7.join(EXE_AI_DIR, "exed.token");
2573
+ }
2574
+ });
2575
+
2410
2576
  // src/lib/exe-daemon-client.ts
2411
2577
  import net from "net";
2412
2578
  import os5 from "os";
2413
2579
  import { spawn } from "child_process";
2414
2580
  import { randomUUID as randomUUID2 } from "crypto";
2415
- import { existsSync as existsSync5, unlinkSync as unlinkSync2, readFileSync as readFileSync3, openSync, closeSync, statSync } from "fs";
2416
- import path7 from "path";
2581
+ import { existsSync as existsSync7, unlinkSync as unlinkSync2, readFileSync as readFileSync4, openSync, closeSync, statSync } from "fs";
2582
+ import path8 from "path";
2417
2583
  import { fileURLToPath } from "url";
2418
2584
  function handleData(chunk) {
2419
2585
  _buffer += chunk.toString();
@@ -2441,9 +2607,9 @@ function handleData(chunk) {
2441
2607
  }
2442
2608
  }
2443
2609
  function cleanupStaleFiles() {
2444
- if (existsSync5(PID_PATH)) {
2610
+ if (existsSync7(PID_PATH)) {
2445
2611
  try {
2446
- const pid = parseInt(readFileSync3(PID_PATH, "utf8").trim(), 10);
2612
+ const pid = parseInt(readFileSync4(PID_PATH, "utf8").trim(), 10);
2447
2613
  if (pid > 0) {
2448
2614
  try {
2449
2615
  process.kill(pid, 0);
@@ -2464,11 +2630,11 @@ function cleanupStaleFiles() {
2464
2630
  }
2465
2631
  }
2466
2632
  function findPackageRoot() {
2467
- let dir = path7.dirname(fileURLToPath(import.meta.url));
2468
- const { root } = path7.parse(dir);
2633
+ let dir = path8.dirname(fileURLToPath(import.meta.url));
2634
+ const { root } = path8.parse(dir);
2469
2635
  while (dir !== root) {
2470
- if (existsSync5(path7.join(dir, "package.json"))) return dir;
2471
- dir = path7.dirname(dir);
2636
+ if (existsSync7(path8.join(dir, "package.json"))) return dir;
2637
+ dir = path8.dirname(dir);
2472
2638
  }
2473
2639
  return null;
2474
2640
  }
@@ -2494,16 +2660,17 @@ function spawnDaemon() {
2494
2660
  process.stderr.write("[exed-client] WARN: cannot find package root\n");
2495
2661
  return;
2496
2662
  }
2497
- const daemonPath = path7.join(pkgRoot, "dist", "lib", "exe-daemon.js");
2498
- if (!existsSync5(daemonPath)) {
2663
+ const daemonPath = path8.join(pkgRoot, "dist", "lib", "exe-daemon.js");
2664
+ if (!existsSync7(daemonPath)) {
2499
2665
  process.stderr.write(`[exed-client] WARN: daemon script not found at ${daemonPath}
2500
2666
  `);
2501
2667
  return;
2502
2668
  }
2503
2669
  const resolvedPath = daemonPath;
2670
+ const daemonToken = ensureDaemonToken(process.env[DAEMON_TOKEN_ENV] ?? null);
2504
2671
  process.stderr.write(`[exed-client] Spawning daemon: ${resolvedPath}
2505
2672
  `);
2506
- const logPath = path7.join(path7.dirname(SOCKET_PATH), "exed.log");
2673
+ const logPath = path8.join(path8.dirname(SOCKET_PATH), "exed.log");
2507
2674
  let stderrFd = "ignore";
2508
2675
  try {
2509
2676
  stderrFd = openSync(logPath, "a");
@@ -2521,7 +2688,8 @@ function spawnDaemon() {
2521
2688
  TMUX_PANE: void 0,
2522
2689
  // Prevents resolveExeSession() from scoping to one session
2523
2690
  EXE_DAEMON_SOCK: SOCKET_PATH,
2524
- EXE_DAEMON_PID: PID_PATH
2691
+ EXE_DAEMON_PID: PID_PATH,
2692
+ [DAEMON_TOKEN_ENV]: daemonToken
2525
2693
  }
2526
2694
  });
2527
2695
  child.unref();
@@ -2631,13 +2799,14 @@ function sendDaemonRequest(payload, timeoutMs = REQUEST_TIMEOUT_MS) {
2631
2799
  return;
2632
2800
  }
2633
2801
  const id = randomUUID2();
2802
+ const token = process.env[DAEMON_TOKEN_ENV] ?? readDaemonToken();
2634
2803
  const timer = setTimeout(() => {
2635
2804
  _pending.delete(id);
2636
2805
  resolve({ error: "Request timeout" });
2637
2806
  }, timeoutMs);
2638
2807
  _pending.set(id, { resolve, timer });
2639
2808
  try {
2640
- _socket.write(JSON.stringify({ id, ...payload }) + "\n");
2809
+ _socket.write(JSON.stringify({ id, token, ...payload }) + "\n");
2641
2810
  } catch {
2642
2811
  clearTimeout(timer);
2643
2812
  _pending.delete(id);
@@ -2666,9 +2835,9 @@ function killAndRespawnDaemon() {
2666
2835
  }
2667
2836
  try {
2668
2837
  process.stderr.write("[exed-client] Killing daemon for restart...\n");
2669
- if (existsSync5(PID_PATH)) {
2838
+ if (existsSync7(PID_PATH)) {
2670
2839
  try {
2671
- const pid = parseInt(readFileSync3(PID_PATH, "utf8").trim(), 10);
2840
+ const pid = parseInt(readFileSync4(PID_PATH, "utf8").trim(), 10);
2672
2841
  if (pid > 0) {
2673
2842
  try {
2674
2843
  process.kill(pid, "SIGKILL");
@@ -2785,17 +2954,19 @@ function disconnectClient() {
2785
2954
  entry.resolve({ error: "Client disconnected" });
2786
2955
  }
2787
2956
  }
2788
- var SOCKET_PATH, PID_PATH, SPAWN_LOCK_PATH, SPAWN_LOCK_STALE_MS, CONNECT_TIMEOUT_MS, REQUEST_TIMEOUT_MS, _socket, _connected, _buffer, _requestCount, _consecutiveFailures, HEALTH_CHECK_INTERVAL, MAX_RETRIES_BEFORE_RESTART, RETRY_DELAYS_MS, MIN_DAEMON_AGE_MS, _pending, MAX_BUFFER;
2957
+ var SOCKET_PATH, PID_PATH, SPAWN_LOCK_PATH, SPAWN_LOCK_STALE_MS, CONNECT_TIMEOUT_MS, REQUEST_TIMEOUT_MS, DAEMON_TOKEN_ENV, _socket, _connected, _buffer, _requestCount, _consecutiveFailures, HEALTH_CHECK_INTERVAL, MAX_RETRIES_BEFORE_RESTART, RETRY_DELAYS_MS, MIN_DAEMON_AGE_MS, _pending, MAX_BUFFER;
2789
2958
  var init_exe_daemon_client = __esm({
2790
2959
  "src/lib/exe-daemon-client.ts"() {
2791
2960
  "use strict";
2792
2961
  init_config();
2793
- SOCKET_PATH = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ?? path7.join(EXE_AI_DIR, "exed.sock");
2794
- PID_PATH = process.env.EXE_DAEMON_PID ?? process.env.EXE_EMBED_PID ?? path7.join(EXE_AI_DIR, "exed.pid");
2795
- SPAWN_LOCK_PATH = path7.join(EXE_AI_DIR, "exed-spawn.lock");
2962
+ init_daemon_auth();
2963
+ SOCKET_PATH = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ?? path8.join(EXE_AI_DIR, "exed.sock");
2964
+ PID_PATH = process.env.EXE_DAEMON_PID ?? process.env.EXE_EMBED_PID ?? path8.join(EXE_AI_DIR, "exed.pid");
2965
+ SPAWN_LOCK_PATH = path8.join(EXE_AI_DIR, "exed-spawn.lock");
2796
2966
  SPAWN_LOCK_STALE_MS = 3e4;
2797
2967
  CONNECT_TIMEOUT_MS = 15e3;
2798
2968
  REQUEST_TIMEOUT_MS = 3e4;
2969
+ DAEMON_TOKEN_ENV = "EXE_DAEMON_TOKEN";
2799
2970
  _socket = null;
2800
2971
  _connected = false;
2801
2972
  _buffer = "";
@@ -2847,10 +3018,10 @@ async function disposeEmbedder() {
2847
3018
  async function embedDirect(text) {
2848
3019
  const llamaCpp = await import("node-llama-cpp");
2849
3020
  const { MODELS_DIR: MODELS_DIR2 } = await Promise.resolve().then(() => (init_config(), config_exports));
2850
- const { existsSync: existsSync8 } = await import("fs");
2851
- const path11 = await import("path");
2852
- const modelPath = path11.join(MODELS_DIR2, "jina-embeddings-v5-small-q4_k_m.gguf");
2853
- if (!existsSync8(modelPath)) {
3021
+ const { existsSync: existsSync10 } = await import("fs");
3022
+ const path12 = await import("path");
3023
+ const modelPath = path12.join(MODELS_DIR2, "jina-embeddings-v5-small-q4_k_m.gguf");
3024
+ if (!existsSync10(modelPath)) {
2854
3025
  throw new Error(`Embedding model not found at ${modelPath}. Run '/exe-setup' to download it.`);
2855
3026
  }
2856
3027
  const llama = await llamaCpp.getLlama();
@@ -2879,9 +3050,12 @@ var init_embedder = __esm({
2879
3050
  });
2880
3051
 
2881
3052
  // src/lib/license.ts
2882
- import { readFileSync as readFileSync4, writeFileSync as writeFileSync2, existsSync as existsSync6, mkdirSync as mkdirSync2 } from "fs";
3053
+ import { readFileSync as readFileSync5, writeFileSync as writeFileSync3, existsSync as existsSync8, mkdirSync as mkdirSync3 } from "fs";
2883
3054
  import { randomUUID as randomUUID3 } from "crypto";
2884
- import path8 from "path";
3055
+ import { createRequire as createRequire2 } from "module";
3056
+ import { pathToFileURL as pathToFileURL2 } from "url";
3057
+ import os6 from "os";
3058
+ import path9 from "path";
2885
3059
  import { jwtVerify, importSPKI } from "jose";
2886
3060
  async function fetchRetry(url, init) {
2887
3061
  try {
@@ -2892,37 +3066,37 @@ async function fetchRetry(url, init) {
2892
3066
  }
2893
3067
  }
2894
3068
  function loadDeviceId() {
2895
- const deviceJsonPath = path8.join(EXE_AI_DIR, "device.json");
3069
+ const deviceJsonPath = path9.join(EXE_AI_DIR, "device.json");
2896
3070
  try {
2897
- if (existsSync6(deviceJsonPath)) {
2898
- const data = JSON.parse(readFileSync4(deviceJsonPath, "utf8"));
3071
+ if (existsSync8(deviceJsonPath)) {
3072
+ const data = JSON.parse(readFileSync5(deviceJsonPath, "utf8"));
2899
3073
  if (data.deviceId) return data.deviceId;
2900
3074
  }
2901
3075
  } catch {
2902
3076
  }
2903
3077
  try {
2904
- if (existsSync6(DEVICE_ID_PATH)) {
2905
- const id2 = readFileSync4(DEVICE_ID_PATH, "utf8").trim();
3078
+ if (existsSync8(DEVICE_ID_PATH)) {
3079
+ const id2 = readFileSync5(DEVICE_ID_PATH, "utf8").trim();
2906
3080
  if (id2) return id2;
2907
3081
  }
2908
3082
  } catch {
2909
3083
  }
2910
3084
  const id = randomUUID3();
2911
- mkdirSync2(EXE_AI_DIR, { recursive: true });
2912
- writeFileSync2(DEVICE_ID_PATH, id, "utf8");
3085
+ mkdirSync3(EXE_AI_DIR, { recursive: true });
3086
+ writeFileSync3(DEVICE_ID_PATH, id, "utf8");
2913
3087
  return id;
2914
3088
  }
2915
3089
  function loadLicense() {
2916
3090
  try {
2917
- if (!existsSync6(LICENSE_PATH)) return null;
2918
- return readFileSync4(LICENSE_PATH, "utf8").trim();
3091
+ if (!existsSync8(LICENSE_PATH)) return null;
3092
+ return readFileSync5(LICENSE_PATH, "utf8").trim();
2919
3093
  } catch {
2920
3094
  return null;
2921
3095
  }
2922
3096
  }
2923
3097
  function saveLicense(apiKey) {
2924
- mkdirSync2(EXE_AI_DIR, { recursive: true });
2925
- writeFileSync2(LICENSE_PATH, apiKey.trim(), { encoding: "utf8", mode: 384 });
3098
+ mkdirSync3(EXE_AI_DIR, { recursive: true });
3099
+ writeFileSync3(LICENSE_PATH, apiKey.trim(), { encoding: "utf8", mode: 384 });
2926
3100
  }
2927
3101
  async function verifyLicenseJwt(token) {
2928
3102
  try {
@@ -2948,8 +3122,8 @@ async function verifyLicenseJwt(token) {
2948
3122
  }
2949
3123
  async function getCachedLicense() {
2950
3124
  try {
2951
- if (!existsSync6(CACHE_PATH)) return null;
2952
- const raw = JSON.parse(readFileSync4(CACHE_PATH, "utf8"));
3125
+ if (!existsSync8(CACHE_PATH)) return null;
3126
+ const raw = JSON.parse(readFileSync5(CACHE_PATH, "utf8"));
2953
3127
  if (!raw.token || typeof raw.token !== "string") return null;
2954
3128
  return await verifyLicenseJwt(raw.token);
2955
3129
  } catch {
@@ -2958,8 +3132,8 @@ async function getCachedLicense() {
2958
3132
  }
2959
3133
  function readCachedToken() {
2960
3134
  try {
2961
- if (!existsSync6(CACHE_PATH)) return null;
2962
- const raw = JSON.parse(readFileSync4(CACHE_PATH, "utf8"));
3135
+ if (!existsSync8(CACHE_PATH)) return null;
3136
+ const raw = JSON.parse(readFileSync5(CACHE_PATH, "utf8"));
2963
3137
  return typeof raw.token === "string" ? raw.token : null;
2964
3138
  } catch {
2965
3139
  return null;
@@ -2993,56 +3167,130 @@ function getRawCachedPlan() {
2993
3167
  }
2994
3168
  function cacheResponse(token) {
2995
3169
  try {
2996
- writeFileSync2(CACHE_PATH, JSON.stringify({ token }), "utf8");
3170
+ writeFileSync3(CACHE_PATH, JSON.stringify({ token }), "utf8");
2997
3171
  } catch {
2998
3172
  }
2999
3173
  }
3000
- async function validateLicense(apiKey, deviceId) {
3001
- const did = deviceId ?? loadDeviceId();
3174
+ function loadPrismaForLicense() {
3175
+ if (_prismaFailed) return null;
3176
+ const dbUrl = process.env.DATABASE_URL;
3177
+ if (!dbUrl) {
3178
+ const exeDbRoot = process.env.EXE_DB_ROOT ?? path9.join(os6.homedir(), "exe-db");
3179
+ if (!existsSync8(path9.join(exeDbRoot, "package.json"))) {
3180
+ _prismaFailed = true;
3181
+ return null;
3182
+ }
3183
+ }
3184
+ if (!_prismaPromise) {
3185
+ _prismaPromise = (async () => {
3186
+ const explicitPath = process.env.EXE_OS_PRISMA_CLIENT_PATH;
3187
+ if (explicitPath) {
3188
+ const mod2 = await import(pathToFileURL2(explicitPath).href);
3189
+ const Ctor2 = mod2.PrismaClient ?? mod2.default?.PrismaClient;
3190
+ if (!Ctor2) throw new Error(`No PrismaClient at ${explicitPath}`);
3191
+ return new Ctor2();
3192
+ }
3193
+ const exeDbRoot = process.env.EXE_DB_ROOT ?? path9.join(os6.homedir(), "exe-db");
3194
+ const req = createRequire2(path9.join(exeDbRoot, "package.json"));
3195
+ const entry = req.resolve("@prisma/client");
3196
+ const mod = await import(pathToFileURL2(entry).href);
3197
+ const Ctor = mod.PrismaClient ?? mod.default?.PrismaClient;
3198
+ if (!Ctor) throw new Error(`No PrismaClient in ${entry}`);
3199
+ return new Ctor();
3200
+ })().catch((err) => {
3201
+ _prismaFailed = true;
3202
+ _prismaPromise = null;
3203
+ throw err;
3204
+ });
3205
+ }
3206
+ return _prismaPromise;
3207
+ }
3208
+ async function validateViaPostgres(apiKey) {
3209
+ const loader = loadPrismaForLicense();
3210
+ if (!loader) return null;
3211
+ try {
3212
+ const prisma = await loader;
3213
+ const rows = await prisma.$queryRawUnsafe(
3214
+ `SELECT plan, email, status, device_limit, employee_limit, memory_limit, expires_at
3215
+ FROM billing.licenses WHERE key = $1 LIMIT 1`,
3216
+ apiKey
3217
+ );
3218
+ if (!rows || rows.length === 0) return null;
3219
+ const row = rows[0];
3220
+ if (row.status !== "active") return null;
3221
+ if (row.expires_at && new Date(row.expires_at) < /* @__PURE__ */ new Date()) return null;
3222
+ const plan = row.plan;
3223
+ const limits = PLAN_LIMITS[plan] ?? PLAN_LIMITS.free;
3224
+ return {
3225
+ valid: true,
3226
+ plan,
3227
+ email: row.email,
3228
+ expiresAt: row.expires_at ? new Date(row.expires_at).toISOString() : null,
3229
+ deviceLimit: row.device_limit ?? limits.devices,
3230
+ employeeLimit: row.employee_limit ?? limits.employees,
3231
+ memoryLimit: row.memory_limit ?? limits.memories
3232
+ };
3233
+ } catch {
3234
+ return null;
3235
+ }
3236
+ }
3237
+ async function validateViaCFWorker(apiKey, deviceId) {
3002
3238
  try {
3003
3239
  const res = await fetchRetry(`${API_BASE}/auth/activate`, {
3004
3240
  method: "POST",
3005
3241
  headers: { "Content-Type": "application/json" },
3006
- body: JSON.stringify({ apiKey, deviceId: did }),
3242
+ body: JSON.stringify({ apiKey, deviceId }),
3007
3243
  signal: AbortSignal.timeout(1e4)
3008
3244
  });
3009
- if (res.ok) {
3010
- const data = await res.json();
3011
- if (data.error === "device_limit_exceeded") {
3012
- const cached2 = await getCachedLicense();
3013
- if (cached2) return cached2;
3014
- const raw2 = getRawCachedPlan();
3015
- if (raw2) return { ...raw2, valid: false };
3016
- return { ...FREE_LICENSE, valid: false, plan: "free" };
3017
- }
3018
- if (data.token) {
3019
- cacheResponse(data.token);
3020
- const verified = await verifyLicenseJwt(data.token);
3021
- if (verified) return verified;
3245
+ if (!res.ok) return null;
3246
+ const data = await res.json();
3247
+ if (data.error === "device_limit_exceeded") return null;
3248
+ if (!data.valid) return null;
3249
+ if (data.token) {
3250
+ cacheResponse(data.token);
3251
+ const verified = await verifyLicenseJwt(data.token);
3252
+ if (verified) return verified;
3253
+ }
3254
+ const limits = PLAN_LIMITS[data.plan] ?? PLAN_LIMITS.free;
3255
+ return {
3256
+ valid: data.valid,
3257
+ plan: data.plan,
3258
+ email: data.email,
3259
+ expiresAt: data.expiresAt,
3260
+ deviceLimit: limits.devices,
3261
+ employeeLimit: limits.employees,
3262
+ memoryLimit: limits.memories
3263
+ };
3264
+ } catch {
3265
+ return null;
3266
+ }
3267
+ }
3268
+ async function validateLicense(apiKey, deviceId) {
3269
+ const did = deviceId ?? loadDeviceId();
3270
+ const pgResult = await validateViaPostgres(apiKey);
3271
+ if (pgResult) {
3272
+ try {
3273
+ writeFileSync3(CACHE_PATH, JSON.stringify({ pgLicense: pgResult, ts: Date.now() }), "utf8");
3274
+ } catch {
3275
+ }
3276
+ return pgResult;
3277
+ }
3278
+ const cfResult = await validateViaCFWorker(apiKey, did);
3279
+ if (cfResult) return cfResult;
3280
+ const cached = await getCachedLicense();
3281
+ if (cached) return cached;
3282
+ try {
3283
+ if (existsSync8(CACHE_PATH)) {
3284
+ const raw = JSON.parse(readFileSync5(CACHE_PATH, "utf8"));
3285
+ if (raw.pgLicense && raw.ts && Date.now() - raw.ts < 7 * 24 * 60 * 60 * 1e3) {
3286
+ return raw.pgLicense;
3022
3287
  }
3023
- const limits = PLAN_LIMITS[data.plan] ?? PLAN_LIMITS.free;
3024
- return {
3025
- valid: data.valid,
3026
- plan: data.plan,
3027
- email: data.email,
3028
- expiresAt: data.expiresAt,
3029
- deviceLimit: limits.devices,
3030
- employeeLimit: limits.employees,
3031
- memoryLimit: limits.memories
3032
- };
3033
3288
  }
3034
- const cached = await getCachedLicense();
3035
- if (cached) return cached;
3036
- const raw = getRawCachedPlan();
3037
- if (raw) return raw;
3038
- return { ...FREE_LICENSE, valid: false, plan: "free" };
3039
3289
  } catch {
3040
- const cached = await getCachedLicense();
3041
- if (cached) return cached;
3042
- const rawFallback = getRawCachedPlan();
3043
- if (rawFallback) return rawFallback;
3044
- return { ...FREE_LICENSE, valid: false, error: "offline" };
3045
3290
  }
3291
+ const rawFallback = getRawCachedPlan();
3292
+ if (rawFallback) return rawFallback;
3293
+ return { ...FREE_LICENSE, valid: false };
3046
3294
  }
3047
3295
  function getCacheAgeMs() {
3048
3296
  try {
@@ -3057,9 +3305,9 @@ async function checkLicense() {
3057
3305
  let key = loadLicense();
3058
3306
  if (!key) {
3059
3307
  try {
3060
- const configPath = path8.join(EXE_AI_DIR, "config.json");
3061
- if (existsSync6(configPath)) {
3062
- const raw = JSON.parse(readFileSync4(configPath, "utf8"));
3308
+ const configPath = path9.join(EXE_AI_DIR, "config.json");
3309
+ if (existsSync8(configPath)) {
3310
+ const raw = JSON.parse(readFileSync5(configPath, "utf8"));
3063
3311
  const cloud = raw.cloud;
3064
3312
  if (cloud?.apiKey) {
3065
3313
  key = cloud.apiKey;
@@ -3085,14 +3333,14 @@ function isFeatureAllowed(license, feature) {
3085
3333
  return license.plan === "team" || license.plan === "agency" || license.plan === "enterprise";
3086
3334
  }
3087
3335
  }
3088
- 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;
3336
+ 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;
3089
3337
  var init_license = __esm({
3090
3338
  "src/lib/license.ts"() {
3091
3339
  "use strict";
3092
3340
  init_config();
3093
- LICENSE_PATH = path8.join(EXE_AI_DIR, "license.key");
3094
- CACHE_PATH = path8.join(EXE_AI_DIR, "license-cache.json");
3095
- DEVICE_ID_PATH = path8.join(EXE_AI_DIR, "device-id");
3341
+ LICENSE_PATH = path9.join(EXE_AI_DIR, "license.key");
3342
+ CACHE_PATH = path9.join(EXE_AI_DIR, "license-cache.json");
3343
+ DEVICE_ID_PATH = path9.join(EXE_AI_DIR, "device-id");
3096
3344
  API_BASE = "https://askexe.com/cloud";
3097
3345
  RETRY_DELAY_MS = 500;
3098
3346
  LICENSE_PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----
@@ -3116,6 +3364,8 @@ MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeHztAMOpR/ZMh+rWuOASjEZ54CGY
3116
3364
  employeeLimit: 1,
3117
3365
  memoryLimit: 5e3
3118
3366
  };
3367
+ _prismaPromise = null;
3368
+ _prismaFailed = false;
3119
3369
  CACHE_MAX_AGE_MS = 36e5;
3120
3370
  }
3121
3371
  });
@@ -3131,12 +3381,12 @@ __export(plan_limits_exports, {
3131
3381
  countActiveMemories: () => countActiveMemories,
3132
3382
  getLicenseSync: () => getLicenseSync
3133
3383
  });
3134
- import { readFileSync as readFileSync5, existsSync as existsSync7 } from "fs";
3135
- import path9 from "path";
3384
+ import { readFileSync as readFileSync6, existsSync as existsSync9 } from "fs";
3385
+ import path10 from "path";
3136
3386
  function getLicenseSync() {
3137
3387
  try {
3138
- if (!existsSync7(CACHE_PATH2)) return freeLicense();
3139
- const raw = JSON.parse(readFileSync5(CACHE_PATH2, "utf8"));
3388
+ if (!existsSync9(CACHE_PATH2)) return freeLicense();
3389
+ const raw = JSON.parse(readFileSync6(CACHE_PATH2, "utf8"));
3140
3390
  if (!raw.token || typeof raw.token !== "string") return freeLicense();
3141
3391
  const parts = raw.token.split(".");
3142
3392
  if (parts.length !== 3) return freeLicense();
@@ -3203,8 +3453,8 @@ function assertEmployeeLimitSync(rosterPath) {
3203
3453
  const filePath = rosterPath ?? EMPLOYEES_PATH;
3204
3454
  let count = 0;
3205
3455
  try {
3206
- if (existsSync7(filePath)) {
3207
- const raw = readFileSync5(filePath, "utf8");
3456
+ if (existsSync9(filePath)) {
3457
+ const raw = readFileSync6(filePath, "utf8");
3208
3458
  const employees = JSON.parse(raw);
3209
3459
  count = Array.isArray(employees) ? employees.length : 0;
3210
3460
  }
@@ -3241,14 +3491,14 @@ var init_plan_limits = __esm({
3241
3491
  this.name = "PlanLimitError";
3242
3492
  }
3243
3493
  };
3244
- CACHE_PATH2 = path9.join(EXE_AI_DIR, "license-cache.json");
3494
+ CACHE_PATH2 = path10.join(EXE_AI_DIR, "license-cache.json");
3245
3495
  }
3246
3496
  });
3247
3497
 
3248
3498
  // src/adapters/claude/hooks/response-ingest-worker.ts
3249
- import crypto from "crypto";
3250
- import { writeFileSync as writeFileSync3 } from "fs";
3251
- import path10 from "path";
3499
+ import crypto2 from "crypto";
3500
+ import { writeFileSync as writeFileSync4 } from "fs";
3501
+ import path11 from "path";
3252
3502
 
3253
3503
  // src/lib/project-name.ts
3254
3504
  import { execSync } from "child_process";
@@ -3293,7 +3543,7 @@ import { createHash } from "crypto";
3293
3543
 
3294
3544
  // src/lib/keychain.ts
3295
3545
  import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
3296
- import { existsSync as existsSync3 } from "fs";
3546
+ import { existsSync as existsSync4 } from "fs";
3297
3547
  import path5 from "path";
3298
3548
  import os4 from "os";
3299
3549
  var SERVICE = "exe-mem";
@@ -3323,7 +3573,7 @@ async function getMasterKey() {
3323
3573
  }
3324
3574
  }
3325
3575
  const keyPath = getKeyPath();
3326
- if (!existsSync3(keyPath)) {
3576
+ if (!existsSync4(keyPath)) {
3327
3577
  process.stderr.write(
3328
3578
  `[keychain] Key not found at ${keyPath} (HOME=${os4.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
3329
3579
  `
@@ -3782,7 +4032,7 @@ async function main() {
3782
4032
  process.exit(0);
3783
4033
  }
3784
4034
  await writeMemory({
3785
- id: crypto.randomUUID(),
4035
+ id: crypto2.randomUUID(),
3786
4036
  agent_id: agentId,
3787
4037
  agent_role: agentRole,
3788
4038
  session_id: sessionId,
@@ -3798,8 +4048,8 @@ async function main() {
3798
4048
  if (needsBackfill) {
3799
4049
  try {
3800
4050
  const { EXE_AI_DIR: exeDir } = await Promise.resolve().then(() => (init_config(), config_exports));
3801
- const flagPath = path10.join(exeDir, "session-cache", "needs-backfill");
3802
- writeFileSync3(flagPath, "1");
4051
+ const flagPath = path11.join(exeDir, "session-cache", "needs-backfill");
4052
+ writeFileSync4(flagPath, "1");
3803
4053
  } catch (err) {
3804
4054
  process.stderr.write(`[response-ingest-worker] backfill flag write failed: ${err instanceof Error ? err.message : String(err)}
3805
4055
  `);