@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
@@ -63,9 +63,34 @@ var init_db_retry = __esm({
63
63
  }
64
64
  });
65
65
 
66
+ // src/lib/secure-files.ts
67
+ import { chmodSync, existsSync, mkdirSync } from "fs";
68
+ import { chmod, mkdir } from "fs/promises";
69
+ async function ensurePrivateDir(dirPath) {
70
+ await mkdir(dirPath, { recursive: true, mode: PRIVATE_DIR_MODE });
71
+ try {
72
+ await chmod(dirPath, PRIVATE_DIR_MODE);
73
+ } catch {
74
+ }
75
+ }
76
+ async function enforcePrivateFile(filePath) {
77
+ try {
78
+ await chmod(filePath, PRIVATE_FILE_MODE);
79
+ } catch {
80
+ }
81
+ }
82
+ var PRIVATE_DIR_MODE, PRIVATE_FILE_MODE;
83
+ var init_secure_files = __esm({
84
+ "src/lib/secure-files.ts"() {
85
+ "use strict";
86
+ PRIVATE_DIR_MODE = 448;
87
+ PRIVATE_FILE_MODE = 384;
88
+ }
89
+ });
90
+
66
91
  // src/lib/config.ts
67
- import { readFile, writeFile, mkdir, chmod } from "fs/promises";
68
- import { readFileSync, existsSync, renameSync } from "fs";
92
+ import { readFile, writeFile } from "fs/promises";
93
+ import { readFileSync, existsSync as existsSync2, renameSync } from "fs";
69
94
  import path from "path";
70
95
  import os from "os";
71
96
  function resolveDataDir() {
@@ -73,7 +98,7 @@ function resolveDataDir() {
73
98
  if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
74
99
  const newDir = path.join(os.homedir(), ".exe-os");
75
100
  const legacyDir = path.join(os.homedir(), ".exe-mem");
76
- if (!existsSync(newDir) && existsSync(legacyDir)) {
101
+ if (!existsSync2(newDir) && existsSync2(legacyDir)) {
77
102
  try {
78
103
  renameSync(legacyDir, newDir);
79
104
  process.stderr.write(`[exe-os] Migrated data directory: ~/.exe-mem \u2192 ~/.exe-os
@@ -136,9 +161,9 @@ function normalizeAutoUpdate(raw) {
136
161
  }
137
162
  async function loadConfig() {
138
163
  const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
139
- await mkdir(dir, { recursive: true });
164
+ await ensurePrivateDir(dir);
140
165
  const configPath = path.join(dir, "config.json");
141
- if (!existsSync(configPath)) {
166
+ if (!existsSync2(configPath)) {
142
167
  return { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db") };
143
168
  }
144
169
  const raw = await readFile(configPath, "utf-8");
@@ -151,6 +176,7 @@ async function loadConfig() {
151
176
  `);
152
177
  try {
153
178
  await writeFile(configPath, JSON.stringify(migratedCfg, null, 2) + "\n");
179
+ await enforcePrivateFile(configPath);
154
180
  } catch {
155
181
  }
156
182
  }
@@ -170,6 +196,7 @@ var EXE_AI_DIR, DB_PATH, MODELS_DIR, CONFIG_PATH, LEGACY_LANCE_PATH, CURRENT_CON
170
196
  var init_config = __esm({
171
197
  "src/lib/config.ts"() {
172
198
  "use strict";
199
+ init_secure_files();
173
200
  EXE_AI_DIR = resolveDataDir();
174
201
  DB_PATH = path.join(EXE_AI_DIR, "memories.db");
175
202
  MODELS_DIR = path.join(EXE_AI_DIR, "models");
@@ -248,7 +275,7 @@ var init_config = __esm({
248
275
 
249
276
  // src/lib/employees.ts
250
277
  import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
251
- import { existsSync as existsSync2, symlinkSync, readlinkSync, readFileSync as readFileSync2, renameSync as renameSync2, unlinkSync, writeFileSync } from "fs";
278
+ import { existsSync as existsSync3, symlinkSync, readlinkSync, readFileSync as readFileSync2, renameSync as renameSync2, unlinkSync, writeFileSync } from "fs";
252
279
  import { execSync } from "child_process";
253
280
  import path2 from "path";
254
281
  import os2 from "os";
@@ -265,7 +292,7 @@ function getCoordinatorName(employees = loadEmployeesSync()) {
265
292
  return getCoordinatorEmployee(employees)?.name ?? DEFAULT_COORDINATOR_TEMPLATE_NAME;
266
293
  }
267
294
  function loadEmployeesSync(employeesPath = EMPLOYEES_PATH) {
268
- if (!existsSync2(employeesPath)) return [];
295
+ if (!existsSync3(employeesPath)) return [];
269
296
  try {
270
297
  return JSON.parse(readFileSync2(employeesPath, "utf-8"));
271
298
  } catch {
@@ -1213,6 +1240,7 @@ async function ensureSchema() {
1213
1240
  project TEXT NOT NULL,
1214
1241
  summary TEXT NOT NULL,
1215
1242
  task_file TEXT,
1243
+ session_scope TEXT,
1216
1244
  read INTEGER NOT NULL DEFAULT 0,
1217
1245
  created_at TEXT NOT NULL
1218
1246
  );
@@ -1221,7 +1249,7 @@ async function ensureSchema() {
1221
1249
  ON notifications(read);
1222
1250
 
1223
1251
  CREATE INDEX IF NOT EXISTS idx_notifications_agent
1224
- ON notifications(agent_id);
1252
+ ON notifications(agent_id, session_scope);
1225
1253
 
1226
1254
  CREATE INDEX IF NOT EXISTS idx_notifications_task_file
1227
1255
  ON notifications(task_file);
@@ -1259,6 +1287,7 @@ async function ensureSchema() {
1259
1287
  target_agent TEXT NOT NULL,
1260
1288
  target_project TEXT,
1261
1289
  target_device TEXT NOT NULL DEFAULT 'local',
1290
+ session_scope TEXT,
1262
1291
  content TEXT NOT NULL,
1263
1292
  priority TEXT DEFAULT 'normal',
1264
1293
  status TEXT DEFAULT 'pending',
@@ -1272,10 +1301,31 @@ async function ensureSchema() {
1272
1301
  );
1273
1302
 
1274
1303
  CREATE INDEX IF NOT EXISTS idx_messages_target
1275
- ON messages(target_agent, status);
1304
+ ON messages(target_agent, session_scope, status);
1276
1305
 
1277
1306
  CREATE INDEX IF NOT EXISTS idx_messages_conversation_order
1278
- ON messages(target_agent, from_agent, server_seq);
1307
+ ON messages(target_agent, session_scope, from_agent, server_seq);
1308
+ `);
1309
+ try {
1310
+ await client.execute({
1311
+ sql: `ALTER TABLE notifications ADD COLUMN session_scope TEXT`,
1312
+ args: []
1313
+ });
1314
+ } catch {
1315
+ }
1316
+ try {
1317
+ await client.execute({
1318
+ sql: `ALTER TABLE messages ADD COLUMN session_scope TEXT`,
1319
+ args: []
1320
+ });
1321
+ } catch {
1322
+ }
1323
+ await client.executeMultiple(`
1324
+ CREATE INDEX IF NOT EXISTS idx_notifications_agent_scope_read
1325
+ ON notifications(agent_id, session_scope, read, created_at);
1326
+
1327
+ CREATE INDEX IF NOT EXISTS idx_messages_target_scope_status
1328
+ ON messages(target_agent, session_scope, status, created_at);
1279
1329
  `);
1280
1330
  try {
1281
1331
  await client.execute({
@@ -1859,6 +1909,13 @@ async function ensureSchema() {
1859
1909
  } catch {
1860
1910
  }
1861
1911
  }
1912
+ try {
1913
+ await client.execute({
1914
+ sql: `UPDATE tasks SET status = 'closed' WHERE status = 'done' AND result IS NOT NULL`,
1915
+ args: []
1916
+ });
1917
+ } catch {
1918
+ }
1862
1919
  }
1863
1920
  var _client, _resilientClient, _walCheckpointTimer, _daemonClient, _adapterClient, initTurso;
1864
1921
  var init_database = __esm({
@@ -1881,6 +1938,7 @@ var shard_manager_exports = {};
1881
1938
  __export(shard_manager_exports, {
1882
1939
  disposeShards: () => disposeShards,
1883
1940
  ensureShardSchema: () => ensureShardSchema,
1941
+ getOpenShardCount: () => getOpenShardCount,
1884
1942
  getReadyShardClient: () => getReadyShardClient,
1885
1943
  getShardClient: () => getShardClient,
1886
1944
  getShardsDir: () => getShardsDir,
@@ -1890,14 +1948,17 @@ __export(shard_manager_exports, {
1890
1948
  shardExists: () => shardExists
1891
1949
  });
1892
1950
  import path5 from "path";
1893
- import { existsSync as existsSync4, mkdirSync, readdirSync } from "fs";
1951
+ import { existsSync as existsSync5, mkdirSync as mkdirSync2, readdirSync } from "fs";
1894
1952
  import { createClient as createClient2 } from "@libsql/client";
1895
1953
  function initShardManager(encryptionKey) {
1896
1954
  _encryptionKey = encryptionKey;
1897
- if (!existsSync4(SHARDS_DIR)) {
1898
- mkdirSync(SHARDS_DIR, { recursive: true });
1955
+ if (!existsSync5(SHARDS_DIR)) {
1956
+ mkdirSync2(SHARDS_DIR, { recursive: true });
1899
1957
  }
1900
1958
  _shardingEnabled = true;
1959
+ if (_evictionTimer) clearInterval(_evictionTimer);
1960
+ _evictionTimer = setInterval(evictIdleShards, EVICTION_INTERVAL_MS);
1961
+ _evictionTimer.unref();
1901
1962
  }
1902
1963
  function isShardingEnabled() {
1903
1964
  return _shardingEnabled;
@@ -1914,21 +1975,28 @@ function getShardClient(projectName) {
1914
1975
  throw new Error(`Invalid project name for shard: "${projectName}"`);
1915
1976
  }
1916
1977
  const cached = _shards.get(safeName);
1917
- if (cached) return cached;
1978
+ if (cached) {
1979
+ _shardLastAccess.set(safeName, Date.now());
1980
+ return cached;
1981
+ }
1982
+ while (_shards.size >= MAX_OPEN_SHARDS) {
1983
+ evictLRU();
1984
+ }
1918
1985
  const dbPath = path5.join(SHARDS_DIR, `${safeName}.db`);
1919
1986
  const client = createClient2({
1920
1987
  url: `file:${dbPath}`,
1921
1988
  encryptionKey: _encryptionKey
1922
1989
  });
1923
1990
  _shards.set(safeName, client);
1991
+ _shardLastAccess.set(safeName, Date.now());
1924
1992
  return client;
1925
1993
  }
1926
1994
  function shardExists(projectName) {
1927
1995
  const safeName = projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
1928
- return existsSync4(path5.join(SHARDS_DIR, `${safeName}.db`));
1996
+ return existsSync5(path5.join(SHARDS_DIR, `${safeName}.db`));
1929
1997
  }
1930
1998
  function listShards() {
1931
- if (!existsSync4(SHARDS_DIR)) return [];
1999
+ if (!existsSync5(SHARDS_DIR)) return [];
1932
2000
  return readdirSync(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
1933
2001
  }
1934
2002
  async function ensureShardSchema(client) {
@@ -1980,6 +2048,8 @@ async function ensureShardSchema(client) {
1980
2048
  for (const col of [
1981
2049
  "ALTER TABLE memories ADD COLUMN task_id TEXT",
1982
2050
  "ALTER TABLE memories ADD COLUMN consolidated INTEGER NOT NULL DEFAULT 0",
2051
+ "ALTER TABLE memories ADD COLUMN author_device_id TEXT",
2052
+ "ALTER TABLE memories ADD COLUMN scope TEXT NOT NULL DEFAULT 'business'",
1983
2053
  "ALTER TABLE memories ADD COLUMN importance INTEGER DEFAULT 5",
1984
2054
  "ALTER TABLE memories ADD COLUMN status TEXT DEFAULT 'active'",
1985
2055
  "ALTER TABLE memories ADD COLUMN wiki_synced INTEGER DEFAULT 0",
@@ -2117,21 +2187,69 @@ async function getReadyShardClient(projectName) {
2117
2187
  await ensureShardSchema(client);
2118
2188
  return client;
2119
2189
  }
2190
+ function evictLRU() {
2191
+ let oldest = null;
2192
+ let oldestTime = Infinity;
2193
+ for (const [name, time] of _shardLastAccess) {
2194
+ if (time < oldestTime) {
2195
+ oldestTime = time;
2196
+ oldest = name;
2197
+ }
2198
+ }
2199
+ if (oldest) {
2200
+ const client = _shards.get(oldest);
2201
+ if (client) {
2202
+ client.close();
2203
+ }
2204
+ _shards.delete(oldest);
2205
+ _shardLastAccess.delete(oldest);
2206
+ }
2207
+ }
2208
+ function evictIdleShards() {
2209
+ const now = Date.now();
2210
+ const toEvict = [];
2211
+ for (const [name, lastAccess] of _shardLastAccess) {
2212
+ if (now - lastAccess > SHARD_IDLE_MS) {
2213
+ toEvict.push(name);
2214
+ }
2215
+ }
2216
+ for (const name of toEvict) {
2217
+ const client = _shards.get(name);
2218
+ if (client) {
2219
+ client.close();
2220
+ }
2221
+ _shards.delete(name);
2222
+ _shardLastAccess.delete(name);
2223
+ }
2224
+ }
2225
+ function getOpenShardCount() {
2226
+ return _shards.size;
2227
+ }
2120
2228
  function disposeShards() {
2229
+ if (_evictionTimer) {
2230
+ clearInterval(_evictionTimer);
2231
+ _evictionTimer = null;
2232
+ }
2121
2233
  for (const [, client] of _shards) {
2122
2234
  client.close();
2123
2235
  }
2124
2236
  _shards.clear();
2237
+ _shardLastAccess.clear();
2125
2238
  _shardingEnabled = false;
2126
2239
  _encryptionKey = null;
2127
2240
  }
2128
- var SHARDS_DIR, _shards, _encryptionKey, _shardingEnabled;
2241
+ var SHARDS_DIR, SHARD_IDLE_MS, MAX_OPEN_SHARDS, EVICTION_INTERVAL_MS, _shards, _shardLastAccess, _evictionTimer, _encryptionKey, _shardingEnabled;
2129
2242
  var init_shard_manager = __esm({
2130
2243
  "src/lib/shard-manager.ts"() {
2131
2244
  "use strict";
2132
2245
  init_config();
2133
2246
  SHARDS_DIR = path5.join(EXE_AI_DIR, "shards");
2247
+ SHARD_IDLE_MS = 5 * 60 * 1e3;
2248
+ MAX_OPEN_SHARDS = 10;
2249
+ EVICTION_INTERVAL_MS = 60 * 1e3;
2134
2250
  _shards = /* @__PURE__ */ new Map();
2251
+ _shardLastAccess = /* @__PURE__ */ new Map();
2252
+ _evictionTimer = null;
2135
2253
  _encryptionKey = null;
2136
2254
  _shardingEnabled = false;
2137
2255
  }
@@ -2335,7 +2453,7 @@ init_database();
2335
2453
 
2336
2454
  // src/lib/keychain.ts
2337
2455
  import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
2338
- import { existsSync as existsSync3 } from "fs";
2456
+ import { existsSync as existsSync4 } from "fs";
2339
2457
  import path4 from "path";
2340
2458
  import os4 from "os";
2341
2459
  var SERVICE = "exe-mem";
@@ -2365,7 +2483,7 @@ async function getMasterKey() {
2365
2483
  }
2366
2484
  }
2367
2485
  const keyPath = getKeyPath();
2368
- if (!existsSync3(keyPath)) {
2486
+ if (!existsSync4(keyPath)) {
2369
2487
  process.stderr.write(
2370
2488
  `[keychain] Key not found at ${keyPath} (HOME=${os4.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
2371
2489
  `
@@ -3,9 +3,34 @@ var __esm = (fn, res) => function __init() {
3
3
  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
4
4
  };
5
5
 
6
+ // src/lib/secure-files.ts
7
+ import { chmodSync, existsSync, mkdirSync } from "fs";
8
+ import { chmod, mkdir } from "fs/promises";
9
+ async function ensurePrivateDir(dirPath) {
10
+ await mkdir(dirPath, { recursive: true, mode: PRIVATE_DIR_MODE });
11
+ try {
12
+ await chmod(dirPath, PRIVATE_DIR_MODE);
13
+ } catch {
14
+ }
15
+ }
16
+ async function enforcePrivateFile(filePath) {
17
+ try {
18
+ await chmod(filePath, PRIVATE_FILE_MODE);
19
+ } catch {
20
+ }
21
+ }
22
+ var PRIVATE_DIR_MODE, PRIVATE_FILE_MODE;
23
+ var init_secure_files = __esm({
24
+ "src/lib/secure-files.ts"() {
25
+ "use strict";
26
+ PRIVATE_DIR_MODE = 448;
27
+ PRIVATE_FILE_MODE = 384;
28
+ }
29
+ });
30
+
6
31
  // src/lib/config.ts
7
- import { readFile, writeFile, mkdir, chmod } from "fs/promises";
8
- import { readFileSync, existsSync, renameSync } from "fs";
32
+ import { readFile, writeFile } from "fs/promises";
33
+ import { readFileSync, existsSync as existsSync2, renameSync } from "fs";
9
34
  import path from "path";
10
35
  import os from "os";
11
36
  function resolveDataDir() {
@@ -13,7 +38,7 @@ function resolveDataDir() {
13
38
  if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
14
39
  const newDir = path.join(os.homedir(), ".exe-os");
15
40
  const legacyDir = path.join(os.homedir(), ".exe-mem");
16
- if (!existsSync(newDir) && existsSync(legacyDir)) {
41
+ if (!existsSync2(newDir) && existsSync2(legacyDir)) {
17
42
  try {
18
43
  renameSync(legacyDir, newDir);
19
44
  process.stderr.write(`[exe-os] Migrated data directory: ~/.exe-mem \u2192 ~/.exe-os
@@ -76,9 +101,9 @@ function normalizeAutoUpdate(raw) {
76
101
  }
77
102
  async function loadConfig() {
78
103
  const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
79
- await mkdir(dir, { recursive: true });
104
+ await ensurePrivateDir(dir);
80
105
  const configPath = path.join(dir, "config.json");
81
- if (!existsSync(configPath)) {
106
+ if (!existsSync2(configPath)) {
82
107
  return { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db") };
83
108
  }
84
109
  const raw = await readFile(configPath, "utf-8");
@@ -91,6 +116,7 @@ async function loadConfig() {
91
116
  `);
92
117
  try {
93
118
  await writeFile(configPath, JSON.stringify(migratedCfg, null, 2) + "\n");
119
+ await enforcePrivateFile(configPath);
94
120
  } catch {
95
121
  }
96
122
  }
@@ -110,6 +136,7 @@ var EXE_AI_DIR, DB_PATH, MODELS_DIR, CONFIG_PATH, LEGACY_LANCE_PATH, CURRENT_CON
110
136
  var init_config = __esm({
111
137
  "src/lib/config.ts"() {
112
138
  "use strict";
139
+ init_secure_files();
113
140
  EXE_AI_DIR = resolveDataDir();
114
141
  DB_PATH = path.join(EXE_AI_DIR, "memories.db");
115
142
  MODELS_DIR = path.join(EXE_AI_DIR, "models");
@@ -195,7 +222,7 @@ import { createClient } from "@libsql/client";
195
222
  // src/lib/employees.ts
196
223
  init_config();
197
224
  import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
198
- import { existsSync as existsSync2, symlinkSync, readlinkSync, readFileSync as readFileSync2, renameSync as renameSync2, unlinkSync, writeFileSync } from "fs";
225
+ import { existsSync as existsSync3, symlinkSync, readlinkSync, readFileSync as readFileSync2, renameSync as renameSync2, unlinkSync, writeFileSync } from "fs";
199
226
  import { execSync } from "child_process";
200
227
  import path2 from "path";
201
228
  import os2 from "os";