@askexenow/exe-os 0.8.38 → 0.8.39

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/README.md +17 -8
  2. package/dist/bin/backfill-conversations.js +46 -10
  3. package/dist/bin/backfill-responses.js +46 -10
  4. package/dist/bin/backfill-vectors.js +42 -8
  5. package/dist/bin/cleanup-stale-review-tasks.js +37 -8
  6. package/dist/bin/cli.js +281 -154
  7. package/dist/bin/exe-agent.js +19 -4
  8. package/dist/bin/exe-assign.js +39 -5
  9. package/dist/bin/exe-boot.js +237 -111
  10. package/dist/bin/exe-call.js +11 -6
  11. package/dist/bin/exe-cloud.js +99 -28
  12. package/dist/bin/exe-dispatch.js +1 -1
  13. package/dist/bin/exe-doctor.js +37 -8
  14. package/dist/bin/exe-export-behaviors.js +39 -10
  15. package/dist/bin/exe-forget.js +38 -9
  16. package/dist/bin/exe-gateway.js +109 -42
  17. package/dist/bin/exe-heartbeat.js +49 -20
  18. package/dist/bin/exe-kill.js +39 -10
  19. package/dist/bin/exe-launch-agent.js +58 -22
  20. package/dist/bin/exe-link.js +184 -85
  21. package/dist/bin/exe-new-employee.js +21 -7
  22. package/dist/bin/exe-pending-messages.js +46 -17
  23. package/dist/bin/exe-pending-notifications.js +37 -8
  24. package/dist/bin/exe-pending-reviews.js +47 -18
  25. package/dist/bin/exe-rename.js +21 -7
  26. package/dist/bin/exe-review.js +34 -5
  27. package/dist/bin/exe-search.js +47 -10
  28. package/dist/bin/exe-session-cleanup.js +56 -19
  29. package/dist/bin/exe-settings.js +63 -2
  30. package/dist/bin/exe-status.js +34 -5
  31. package/dist/bin/exe-team.js +34 -5
  32. package/dist/bin/git-sweep.js +38 -9
  33. package/dist/bin/graph-backfill.js +37 -8
  34. package/dist/bin/graph-export.js +37 -8
  35. package/dist/bin/install.js +1 -1
  36. package/dist/bin/scan-tasks.js +40 -11
  37. package/dist/bin/setup.js +58 -24
  38. package/dist/bin/shard-migrate.js +37 -8
  39. package/dist/bin/wiki-sync.js +39 -9
  40. package/dist/gateway/index.js +102 -37
  41. package/dist/hooks/bug-report-worker.js +62 -28
  42. package/dist/hooks/commit-complete.js +38 -9
  43. package/dist/hooks/error-recall.js +49 -8
  44. package/dist/hooks/exe-heartbeat-hook.js +3 -2
  45. package/dist/hooks/ingest-worker.js +151 -37
  46. package/dist/hooks/ingest.js +74 -28
  47. package/dist/hooks/instructions-loaded.js +39 -9
  48. package/dist/hooks/notification.js +37 -7
  49. package/dist/hooks/post-compact.js +37 -7
  50. package/dist/hooks/pre-compact.js +35 -6
  51. package/dist/hooks/pre-tool-use.js +52 -14
  52. package/dist/hooks/prompt-ingest-worker.js +56 -10
  53. package/dist/hooks/prompt-submit.js +61 -23
  54. package/dist/hooks/response-ingest-worker.js +57 -11
  55. package/dist/hooks/session-end.js +43 -10
  56. package/dist/hooks/session-start.js +46 -8
  57. package/dist/hooks/stop.js +37 -7
  58. package/dist/hooks/subagent-stop.js +37 -7
  59. package/dist/hooks/summary-worker.js +317 -99
  60. package/dist/index.js +87 -22
  61. package/dist/lib/cloud-sync.js +172 -78
  62. package/dist/lib/config.js +4 -1
  63. package/dist/lib/consolidation.js +5 -4
  64. package/dist/lib/database.js +1 -0
  65. package/dist/lib/device-registry.js +2 -1
  66. package/dist/lib/embedder.js +9 -1
  67. package/dist/lib/employees.js +11 -6
  68. package/dist/lib/exe-daemon-client.js +6 -1
  69. package/dist/lib/exe-daemon.js +71 -28
  70. package/dist/lib/hybrid-search.js +47 -10
  71. package/dist/lib/identity.js +1 -1
  72. package/dist/lib/keychain.js +2 -1
  73. package/dist/lib/license.js +13 -4
  74. package/dist/lib/messaging.js +1 -1
  75. package/dist/lib/reminders.js +2 -2
  76. package/dist/lib/schedules.js +37 -8
  77. package/dist/lib/skill-learning.js +1 -1
  78. package/dist/lib/store.js +37 -8
  79. package/dist/lib/tasks.js +1 -1
  80. package/dist/lib/tmux-routing.js +1 -1
  81. package/dist/mcp/server.js +97 -43
  82. package/dist/mcp/tools/complete-reminder.js +1 -1
  83. package/dist/mcp/tools/create-task.js +14 -6
  84. package/dist/mcp/tools/deactivate-behavior.js +2 -2
  85. package/dist/mcp/tools/list-reminders.js +1 -1
  86. package/dist/mcp/tools/list-tasks.js +1 -1
  87. package/dist/mcp/tools/send-message.js +1 -1
  88. package/dist/mcp/tools/update-task.js +1 -1
  89. package/dist/runtime/index.js +35 -6
  90. package/dist/tui/App.js +177 -95
  91. package/package.json +3 -3
package/dist/tui/App.js CHANGED
@@ -141,6 +141,7 @@ async function ensureSchema() {
141
141
  const client = getRawClient();
142
142
  await client.execute("PRAGMA journal_mode = WAL");
143
143
  await client.execute("PRAGMA busy_timeout = 30000");
144
+ await client.execute("PRAGMA wal_autocheckpoint = 1000");
144
145
  try {
145
146
  await client.execute("PRAGMA libsql_vector_search_ef = 128");
146
147
  } catch {
@@ -964,7 +965,7 @@ __export(config_exports, {
964
965
  migrateConfig: () => migrateConfig,
965
966
  saveConfig: () => saveConfig
966
967
  });
967
- import { readFile, writeFile, mkdir } from "fs/promises";
968
+ import { readFile, writeFile, mkdir, chmod } from "fs/promises";
968
969
  import { readFileSync as readFileSync2, existsSync as existsSync2, renameSync } from "fs";
969
970
  import path from "path";
970
971
  import os from "os";
@@ -1090,6 +1091,9 @@ async function saveConfig(config) {
1090
1091
  await mkdir(dir, { recursive: true });
1091
1092
  const configPath = path.join(dir, "config.json");
1092
1093
  await writeFile(configPath, JSON.stringify(config, null, 2) + "\n");
1094
+ if (config.cloud?.apiKey) {
1095
+ await chmod(configPath, 384);
1096
+ }
1093
1097
  }
1094
1098
  async function loadConfigFrom(configPath) {
1095
1099
  const raw = await readFile(configPath, "utf-8");
@@ -1212,6 +1216,14 @@ import { readFileSync as readFileSync3, writeFileSync, existsSync as existsSync3
1212
1216
  import { randomUUID } from "crypto";
1213
1217
  import path2 from "path";
1214
1218
  import { jwtVerify, importSPKI } from "jose";
1219
+ async function fetchRetry(url, init) {
1220
+ try {
1221
+ return await fetch(url, init);
1222
+ } catch {
1223
+ await new Promise((r) => setTimeout(r, RETRY_DELAY_MS));
1224
+ return fetch(url, { ...init, signal: AbortSignal.timeout(1e4) });
1225
+ }
1226
+ }
1215
1227
  function loadDeviceId() {
1216
1228
  const deviceJsonPath = path2.join(EXE_AI_DIR, "device.json");
1217
1229
  try {
@@ -1243,7 +1255,7 @@ function loadLicense() {
1243
1255
  }
1244
1256
  function saveLicense(apiKey) {
1245
1257
  mkdirSync(EXE_AI_DIR, { recursive: true });
1246
- writeFileSync(LICENSE_PATH, apiKey.trim(), "utf8");
1258
+ writeFileSync(LICENSE_PATH, apiKey.trim(), { encoding: "utf8", mode: 384 });
1247
1259
  }
1248
1260
  async function verifyLicenseJwt(token) {
1249
1261
  try {
@@ -1295,7 +1307,7 @@ function cacheResponse(token) {
1295
1307
  async function validateLicense(apiKey, deviceId) {
1296
1308
  const did = deviceId ?? loadDeviceId();
1297
1309
  try {
1298
- const res = await fetch(`${API_BASE}/auth/activate`, {
1310
+ const res = await fetchRetry(`${API_BASE}/auth/activate`, {
1299
1311
  method: "POST",
1300
1312
  headers: { "Content-Type": "application/json" },
1301
1313
  body: JSON.stringify({ apiKey, deviceId: did }),
@@ -1386,7 +1398,7 @@ async function assertVpsLicense(opts) {
1386
1398
  let explicitRejection = false;
1387
1399
  let transientFailure = false;
1388
1400
  try {
1389
- const res = await fetch(`${API_BASE}/auth/activate`, {
1401
+ const res = await fetchRetry(`${API_BASE}/auth/activate`, {
1390
1402
  method: "POST",
1391
1403
  headers: { "Content-Type": "application/json" },
1392
1404
  body: JSON.stringify({ apiKey, deviceId }),
@@ -1488,7 +1500,7 @@ function stopLicenseRevalidation() {
1488
1500
  _revalTimer = null;
1489
1501
  }
1490
1502
  }
1491
- var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH, API_BASE, LICENSE_PUBLIC_KEY_PEM, LICENSE_JWT_ALG, PLAN_LIMITS, FREE_LICENSE, CACHE_MAX_AGE_MS, _revalTimer;
1503
+ 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;
1492
1504
  var init_license = __esm({
1493
1505
  "src/lib/license.ts"() {
1494
1506
  "use strict";
@@ -1497,6 +1509,7 @@ var init_license = __esm({
1497
1509
  CACHE_PATH = path2.join(EXE_AI_DIR, "license-cache.json");
1498
1510
  DEVICE_ID_PATH = path2.join(EXE_AI_DIR, "device-id");
1499
1511
  API_BASE = "https://askexe.com/cloud";
1512
+ RETRY_DELAY_MS = 500;
1500
1513
  LICENSE_PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----
1501
1514
  MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeHztAMOpR/ZMh+rWuOASjEZ54CGY
1502
1515
  4uj+UqeKCcvtgNHKmOK278HJaJcANe9xAeji8AFYu27q3WtzCi04pHudow==
@@ -3369,8 +3382,13 @@ function runRipgrep(input, searchPath, context) {
3369
3382
  timeout: 3e4,
3370
3383
  stdio: ["ignore", "pipe", "pipe"]
3371
3384
  });
3385
+ const MAX_OUTPUT = 1e7;
3372
3386
  const chunks = [];
3373
- child.stdout.on("data", (chunk) => chunks.push(chunk));
3387
+ let totalSize = 0;
3388
+ child.stdout.on("data", (chunk) => {
3389
+ totalSize += chunk.length;
3390
+ if (totalSize <= MAX_OUTPUT) chunks.push(chunk);
3391
+ });
3374
3392
  const onAbort = () => child.kill("SIGTERM");
3375
3393
  context.abortSignal.addEventListener("abort", onAbort, { once: true });
3376
3394
  child.on("close", (code) => {
@@ -3754,10 +3772,19 @@ var init_bash = __esm({
3754
3772
  stdio: ["ignore", "pipe", "pipe"],
3755
3773
  env: { ...process.env }
3756
3774
  });
3775
+ const MAX_OUTPUT_SIZE = 5242880;
3757
3776
  const stdoutChunks = [];
3758
3777
  const stderrChunks = [];
3759
- child.stdout.on("data", (chunk) => stdoutChunks.push(chunk));
3760
- child.stderr.on("data", (chunk) => stderrChunks.push(chunk));
3778
+ let stdoutSize = 0;
3779
+ let stderrSize = 0;
3780
+ child.stdout.on("data", (chunk) => {
3781
+ if (stdoutSize < MAX_OUTPUT_SIZE) stdoutChunks.push(chunk);
3782
+ stdoutSize += chunk.length;
3783
+ });
3784
+ child.stderr.on("data", (chunk) => {
3785
+ if (stderrSize < MAX_OUTPUT_SIZE) stderrChunks.push(chunk);
3786
+ stderrSize += chunk.length;
3787
+ });
3761
3788
  const onAbort = () => {
3762
3789
  child.kill("SIGTERM");
3763
3790
  setTimeout(() => {
@@ -3937,15 +3964,20 @@ function addEmployee(employees, employee) {
3937
3964
  }
3938
3965
  return [...employees, normalized];
3939
3966
  }
3967
+ function findExeBin() {
3968
+ try {
3969
+ return execSync3(process.platform === "win32" ? "where exe-os" : "which exe-os", { encoding: "utf8" }).trim();
3970
+ } catch {
3971
+ return null;
3972
+ }
3973
+ }
3940
3974
  function registerBinSymlinks(name) {
3941
3975
  const created = [];
3942
3976
  const skipped = [];
3943
3977
  const errors = [];
3944
- let exeBinPath;
3945
- try {
3946
- exeBinPath = execSync3("which exe", { encoding: "utf-8" }).trim();
3947
- } catch {
3948
- errors.push("Could not find 'exe' in PATH");
3978
+ const exeBinPath = findExeBin();
3979
+ if (!exeBinPath) {
3980
+ errors.push("Could not find 'exe-os' in PATH");
3949
3981
  return { created, skipped, errors };
3950
3982
  }
3951
3983
  const binDir = path10.dirname(exeBinPath);
@@ -4304,10 +4336,10 @@ var init_provider_table = __esm({
4304
4336
 
4305
4337
  // src/lib/intercom-queue.ts
4306
4338
  import { readFileSync as readFileSync6, writeFileSync as writeFileSync3, renameSync as renameSync2, existsSync as existsSync6, mkdirSync as mkdirSync3 } from "fs";
4307
- import path11 from "path";
4339
+ import path12 from "path";
4308
4340
  import os4 from "os";
4309
4341
  function ensureDir() {
4310
- const dir = path11.dirname(QUEUE_PATH);
4342
+ const dir = path12.dirname(QUEUE_PATH);
4311
4343
  if (!existsSync6(dir)) mkdirSync3(dir, { recursive: true });
4312
4344
  }
4313
4345
  function readQueue() {
@@ -4345,15 +4377,15 @@ var QUEUE_PATH, TTL_MS, INTERCOM_LOG;
4345
4377
  var init_intercom_queue = __esm({
4346
4378
  "src/lib/intercom-queue.ts"() {
4347
4379
  "use strict";
4348
- QUEUE_PATH = path11.join(os4.homedir(), ".exe-os", "intercom-queue.json");
4380
+ QUEUE_PATH = path12.join(os4.homedir(), ".exe-os", "intercom-queue.json");
4349
4381
  TTL_MS = 60 * 60 * 1e3;
4350
- INTERCOM_LOG = path11.join(os4.homedir(), ".exe-os", "intercom.log");
4382
+ INTERCOM_LOG = path12.join(os4.homedir(), ".exe-os", "intercom.log");
4351
4383
  }
4352
4384
  });
4353
4385
 
4354
4386
  // src/lib/plan-limits.ts
4355
4387
  import { readFileSync as readFileSync7, existsSync as existsSync7 } from "fs";
4356
- import path12 from "path";
4388
+ import path13 from "path";
4357
4389
  function getLicenseSync() {
4358
4390
  try {
4359
4391
  if (!existsSync7(CACHE_PATH2)) return freeLicense();
@@ -4425,13 +4457,13 @@ var init_plan_limits = __esm({
4425
4457
  this.name = "PlanLimitError";
4426
4458
  }
4427
4459
  };
4428
- CACHE_PATH2 = path12.join(EXE_AI_DIR, "license-cache.json");
4460
+ CACHE_PATH2 = path13.join(EXE_AI_DIR, "license-cache.json");
4429
4461
  }
4430
4462
  });
4431
4463
 
4432
4464
  // src/lib/notifications.ts
4433
4465
  import crypto from "crypto";
4434
- import path13 from "path";
4466
+ import path14 from "path";
4435
4467
  import os5 from "os";
4436
4468
  import {
4437
4469
  readFileSync as readFileSync8,
@@ -4517,7 +4549,7 @@ var init_session_kill_telemetry = __esm({
4517
4549
 
4518
4550
  // src/lib/tasks-crud.ts
4519
4551
  import crypto3 from "crypto";
4520
- import path14 from "path";
4552
+ import path15 from "path";
4521
4553
  import { execSync as execSync6 } from "child_process";
4522
4554
  import { mkdir as mkdir3, writeFile as writeFile3, appendFile } from "fs/promises";
4523
4555
  import { existsSync as existsSync9, readFileSync as readFileSync9 } from "fs";
@@ -4650,8 +4682,8 @@ async function createTaskCore(input) {
4650
4682
  }
4651
4683
  if (input.baseDir) {
4652
4684
  try {
4653
- await mkdir3(path14.join(input.baseDir, "exe", "output"), { recursive: true });
4654
- await mkdir3(path14.join(input.baseDir, "exe", "research"), { recursive: true });
4685
+ await mkdir3(path15.join(input.baseDir, "exe", "output"), { recursive: true });
4686
+ await mkdir3(path15.join(input.baseDir, "exe", "research"), { recursive: true });
4655
4687
  await ensureArchitectureDoc(input.baseDir, input.projectName);
4656
4688
  await ensureGitignoreExe(input.baseDir);
4657
4689
  } catch {
@@ -4859,7 +4891,7 @@ async function deleteTaskCore(taskId, _baseDir) {
4859
4891
  return { taskFile, assignedTo, assignedBy, taskSlug };
4860
4892
  }
4861
4893
  async function ensureArchitectureDoc(baseDir, projectName) {
4862
- const archPath = path14.join(baseDir, "exe", "ARCHITECTURE.md");
4894
+ const archPath = path15.join(baseDir, "exe", "ARCHITECTURE.md");
4863
4895
  try {
4864
4896
  if (existsSync9(archPath)) return;
4865
4897
  const template = [
@@ -4894,7 +4926,7 @@ async function ensureArchitectureDoc(baseDir, projectName) {
4894
4926
  }
4895
4927
  }
4896
4928
  async function ensureGitignoreExe(baseDir) {
4897
- const gitignorePath = path14.join(baseDir, ".gitignore");
4929
+ const gitignorePath = path15.join(baseDir, ".gitignore");
4898
4930
  try {
4899
4931
  if (existsSync9(gitignorePath)) {
4900
4932
  const content = readFileSync9(gitignorePath, "utf-8");
@@ -4917,7 +4949,7 @@ var init_tasks_crud = __esm({
4917
4949
  });
4918
4950
 
4919
4951
  // src/lib/tasks-review.ts
4920
- import path15 from "path";
4952
+ import path16 from "path";
4921
4953
  import { existsSync as existsSync10, readdirSync as readdirSync2, unlinkSync as unlinkSync2 } from "fs";
4922
4954
  async function countPendingReviews() {
4923
4955
  const client = getClient();
@@ -5038,11 +5070,11 @@ async function cleanupReviewFile(row, taskFile, _baseDir) {
5038
5070
  );
5039
5071
  }
5040
5072
  try {
5041
- const cacheDir = path15.join(EXE_AI_DIR, "session-cache");
5073
+ const cacheDir = path16.join(EXE_AI_DIR, "session-cache");
5042
5074
  if (existsSync10(cacheDir)) {
5043
5075
  for (const f of readdirSync2(cacheDir)) {
5044
5076
  if (f.startsWith("review-notified-")) {
5045
- unlinkSync2(path15.join(cacheDir, f));
5077
+ unlinkSync2(path16.join(cacheDir, f));
5046
5078
  }
5047
5079
  }
5048
5080
  }
@@ -5063,7 +5095,7 @@ var init_tasks_review = __esm({
5063
5095
  });
5064
5096
 
5065
5097
  // src/lib/tasks-chain.ts
5066
- import path16 from "path";
5098
+ import path17 from "path";
5067
5099
  import { readFile as readFile3, writeFile as writeFile4 } from "fs/promises";
5068
5100
  async function cascadeUnblock(taskId, baseDir, now) {
5069
5101
  const client = getClient();
@@ -5079,7 +5111,7 @@ async function cascadeUnblock(taskId, baseDir, now) {
5079
5111
  });
5080
5112
  for (const ur of unblockedRows.rows) {
5081
5113
  try {
5082
- const ubFile = path16.join(baseDir, String(ur.task_file));
5114
+ const ubFile = path17.join(baseDir, String(ur.task_file));
5083
5115
  let ubContent = await readFile3(ubFile, "utf-8");
5084
5116
  ubContent = ubContent.replace(/\*\*Status:\*\* blocked/, "**Status:** open");
5085
5117
  ubContent = ubContent.replace(/\n\*\*Blocked by:\*\*.*\n/, "\n");
@@ -5145,7 +5177,7 @@ var init_tasks_chain = __esm({
5145
5177
 
5146
5178
  // src/lib/project-name.ts
5147
5179
  import { execSync as execSync7 } from "child_process";
5148
- import path17 from "path";
5180
+ import path18 from "path";
5149
5181
  function getProjectName(cwd2) {
5150
5182
  const dir = cwd2 ?? process.cwd();
5151
5183
  if (_cached2 && _cachedCwd === dir) return _cached2;
@@ -5158,7 +5190,7 @@ function getProjectName(cwd2) {
5158
5190
  timeout: 2e3,
5159
5191
  stdio: ["pipe", "pipe", "pipe"]
5160
5192
  }).trim();
5161
- repoRoot = path17.dirname(gitCommonDir);
5193
+ repoRoot = path18.dirname(gitCommonDir);
5162
5194
  } catch {
5163
5195
  repoRoot = execSync7("git rev-parse --show-toplevel", {
5164
5196
  cwd: dir,
@@ -5167,11 +5199,11 @@ function getProjectName(cwd2) {
5167
5199
  stdio: ["pipe", "pipe", "pipe"]
5168
5200
  }).trim();
5169
5201
  }
5170
- _cached2 = path17.basename(repoRoot);
5202
+ _cached2 = path18.basename(repoRoot);
5171
5203
  _cachedCwd = dir;
5172
5204
  return _cached2;
5173
5205
  } catch {
5174
- _cached2 = path17.basename(dir);
5206
+ _cached2 = path18.basename(dir);
5175
5207
  _cachedCwd = dir;
5176
5208
  return _cached2;
5177
5209
  }
@@ -5642,7 +5674,7 @@ __export(tasks_exports, {
5642
5674
  updateTaskStatus: () => updateTaskStatus,
5643
5675
  writeCheckpoint: () => writeCheckpoint
5644
5676
  });
5645
- import path18 from "path";
5677
+ import path19 from "path";
5646
5678
  import { writeFileSync as writeFileSync4, mkdirSync as mkdirSync4, unlinkSync as unlinkSync3 } from "fs";
5647
5679
  async function createTask(input) {
5648
5680
  const result = await createTaskCore(input);
@@ -5662,8 +5694,8 @@ async function updateTask(input) {
5662
5694
  const { row, taskFile, now, taskId } = await updateTaskStatus(input);
5663
5695
  try {
5664
5696
  const agent = String(row.assigned_to);
5665
- const cacheDir = path18.join(EXE_AI_DIR, "session-cache");
5666
- const cachePath = path18.join(cacheDir, `current-task-${agent}.json`);
5697
+ const cacheDir = path19.join(EXE_AI_DIR, "session-cache");
5698
+ const cachePath = path19.join(cacheDir, `current-task-${agent}.json`);
5667
5699
  if (input.status === "in_progress") {
5668
5700
  mkdirSync4(cacheDir, { recursive: true });
5669
5701
  writeFileSync4(cachePath, JSON.stringify({ taskId, title: String(row.title) }));
@@ -6085,12 +6117,12 @@ __export(tmux_routing_exports, {
6085
6117
  });
6086
6118
  import { execFileSync as execFileSync3, execSync as execSync8 } from "child_process";
6087
6119
  import { readFileSync as readFileSync10, writeFileSync as writeFileSync5, mkdirSync as mkdirSync5, existsSync as existsSync11, appendFileSync } from "fs";
6088
- import path19 from "path";
6120
+ import path20 from "path";
6089
6121
  import os6 from "os";
6090
6122
  import { fileURLToPath } from "url";
6091
6123
  import { unlinkSync as unlinkSync4 } from "fs";
6092
6124
  function spawnLockPath(sessionName) {
6093
- return path19.join(SPAWN_LOCK_DIR, `${sessionName}.lock`);
6125
+ return path20.join(SPAWN_LOCK_DIR, `${sessionName}.lock`);
6094
6126
  }
6095
6127
  function isProcessAlive(pid) {
6096
6128
  try {
@@ -6127,8 +6159,8 @@ function releaseSpawnLock(sessionName) {
6127
6159
  function resolveBehaviorsExporterScript() {
6128
6160
  try {
6129
6161
  const thisFile = fileURLToPath(import.meta.url);
6130
- const scriptPath = path19.join(
6131
- path19.dirname(thisFile),
6162
+ const scriptPath = path20.join(
6163
+ path20.dirname(thisFile),
6132
6164
  "..",
6133
6165
  "bin",
6134
6166
  "exe-export-behaviors.js"
@@ -6178,7 +6210,7 @@ function registerParentExe(sessionKey, parentExe, dispatchedBy) {
6178
6210
  mkdirSync5(SESSION_CACHE, { recursive: true });
6179
6211
  }
6180
6212
  const rootExe = extractRootExe(parentExe) ?? parentExe;
6181
- const filePath = path19.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`);
6213
+ const filePath = path20.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`);
6182
6214
  writeFileSync5(filePath, JSON.stringify({
6183
6215
  parentExe: rootExe,
6184
6216
  dispatchedBy: dispatchedBy || rootExe,
@@ -6187,7 +6219,7 @@ function registerParentExe(sessionKey, parentExe, dispatchedBy) {
6187
6219
  }
6188
6220
  function getParentExe(sessionKey) {
6189
6221
  try {
6190
- const data = JSON.parse(readFileSync10(path19.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
6222
+ const data = JSON.parse(readFileSync10(path20.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
6191
6223
  return data.parentExe || null;
6192
6224
  } catch {
6193
6225
  return null;
@@ -6196,7 +6228,7 @@ function getParentExe(sessionKey) {
6196
6228
  function getDispatchedBy(sessionKey) {
6197
6229
  try {
6198
6230
  const data = JSON.parse(readFileSync10(
6199
- path19.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`),
6231
+ path20.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`),
6200
6232
  "utf8"
6201
6233
  ));
6202
6234
  return data.dispatchedBy ?? data.parentExe ?? null;
@@ -6439,8 +6471,8 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
6439
6471
  const transport = getTransport();
6440
6472
  const sessionName = employeeSessionName(employeeName, exeSession, opts?.instance);
6441
6473
  const instanceLabel = opts?.instance != null && opts.instance > 0 ? `${employeeName}${opts.instance}` : employeeName;
6442
- const logDir = path19.join(os6.homedir(), ".exe-os", "session-logs");
6443
- const logFile = path19.join(logDir, `${instanceLabel}-${Date.now()}.log`);
6474
+ const logDir = path20.join(os6.homedir(), ".exe-os", "session-logs");
6475
+ const logFile = path20.join(logDir, `${instanceLabel}-${Date.now()}.log`);
6444
6476
  if (!existsSync11(logDir)) {
6445
6477
  mkdirSync5(logDir, { recursive: true });
6446
6478
  }
@@ -6448,14 +6480,14 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
6448
6480
  let cleanupSuffix = "";
6449
6481
  try {
6450
6482
  const thisFile = fileURLToPath(import.meta.url);
6451
- const cleanupScript = path19.join(path19.dirname(thisFile), "..", "bin", "exe-session-cleanup.js");
6483
+ const cleanupScript = path20.join(path20.dirname(thisFile), "..", "bin", "exe-session-cleanup.js");
6452
6484
  if (existsSync11(cleanupScript)) {
6453
6485
  cleanupSuffix = `; ${process.execPath} "${cleanupScript}" "${employeeName}" "${exeSession}"`;
6454
6486
  }
6455
6487
  } catch {
6456
6488
  }
6457
6489
  try {
6458
- const claudeJsonPath = path19.join(os6.homedir(), ".claude.json");
6490
+ const claudeJsonPath = path20.join(os6.homedir(), ".claude.json");
6459
6491
  let claudeJson = {};
6460
6492
  try {
6461
6493
  claudeJson = JSON.parse(readFileSync10(claudeJsonPath, "utf8"));
@@ -6470,10 +6502,10 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
6470
6502
  } catch {
6471
6503
  }
6472
6504
  try {
6473
- const settingsDir = path19.join(os6.homedir(), ".claude", "projects");
6505
+ const settingsDir = path20.join(os6.homedir(), ".claude", "projects");
6474
6506
  const normalizedKey = (opts?.cwd ?? projectDir).replace(/\//g, "-").replace(/^-/, "");
6475
- const projSettingsDir = path19.join(settingsDir, normalizedKey);
6476
- const settingsPath = path19.join(projSettingsDir, "settings.json");
6507
+ const projSettingsDir = path20.join(settingsDir, normalizedKey);
6508
+ const settingsPath = path20.join(projSettingsDir, "settings.json");
6477
6509
  let settings = {};
6478
6510
  try {
6479
6511
  settings = JSON.parse(readFileSync10(settingsPath, "utf8"));
@@ -6517,7 +6549,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
6517
6549
  let behaviorsFlag = "";
6518
6550
  let legacyFallbackWarned = false;
6519
6551
  if (!useExeAgent && !useBinSymlink) {
6520
- const identityPath = path19.join(
6552
+ const identityPath = path20.join(
6521
6553
  os6.homedir(),
6522
6554
  ".exe-os",
6523
6555
  "identity",
@@ -6533,7 +6565,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
6533
6565
  }
6534
6566
  const behaviorsFile = exportBehaviorsSync(
6535
6567
  employeeName,
6536
- path19.basename(spawnCwd),
6568
+ path20.basename(spawnCwd),
6537
6569
  sessionName
6538
6570
  );
6539
6571
  if (behaviorsFile) {
@@ -6548,9 +6580,9 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
6548
6580
  }
6549
6581
  let sessionContextFlag = "";
6550
6582
  try {
6551
- const ctxDir = path19.join(os6.homedir(), ".exe-os", "session-cache");
6583
+ const ctxDir = path20.join(os6.homedir(), ".exe-os", "session-cache");
6552
6584
  mkdirSync5(ctxDir, { recursive: true });
6553
- const ctxFile = path19.join(ctxDir, `session-context-${sessionName}.md`);
6585
+ const ctxFile = path20.join(ctxDir, `session-context-${sessionName}.md`);
6554
6586
  const ctxContent = [
6555
6587
  `## Session Context`,
6556
6588
  `You are running in tmux session: ${sessionName}.`,
@@ -6595,7 +6627,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
6595
6627
  transport.pipeLog(sessionName, logFile);
6596
6628
  try {
6597
6629
  const mySession = getMySession();
6598
- const dispatchInfo = path19.join(SESSION_CACHE, `dispatch-info-${sessionName}.json`);
6630
+ const dispatchInfo = path20.join(SESSION_CACHE, `dispatch-info-${sessionName}.json`);
6599
6631
  writeFileSync5(dispatchInfo, JSON.stringify({
6600
6632
  dispatchedBy: mySession,
6601
6633
  rootExe: exeSession,
@@ -6659,13 +6691,13 @@ var init_tmux_routing = __esm({
6659
6691
  init_provider_table();
6660
6692
  init_intercom_queue();
6661
6693
  init_plan_limits();
6662
- SPAWN_LOCK_DIR = path19.join(os6.homedir(), ".exe-os", "spawn-locks");
6663
- SESSION_CACHE = path19.join(os6.homedir(), ".exe-os", "session-cache");
6694
+ SPAWN_LOCK_DIR = path20.join(os6.homedir(), ".exe-os", "spawn-locks");
6695
+ SESSION_CACHE = path20.join(os6.homedir(), ".exe-os", "session-cache");
6664
6696
  BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
6665
6697
  VERIFY_PANE_LINES = 200;
6666
6698
  INTERCOM_DEBOUNCE_MS = 3e4;
6667
- INTERCOM_LOG2 = path19.join(os6.homedir(), ".exe-os", "intercom.log");
6668
- DEBOUNCE_FILE = path19.join(SESSION_CACHE, "intercom-debounce.json");
6699
+ INTERCOM_LOG2 = path20.join(os6.homedir(), ".exe-os", "intercom.log");
6700
+ DEBOUNCE_FILE = path20.join(SESSION_CACHE, "intercom-debounce.json");
6669
6701
  DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
6670
6702
  BUSY_PATTERN = /[✻✽✶✳·].*…|Running…/;
6671
6703
  }
@@ -6972,15 +7004,16 @@ __export(keychain_exports, {
6972
7004
  importMnemonic: () => importMnemonic,
6973
7005
  setMasterKey: () => setMasterKey
6974
7006
  });
6975
- import { readFile as readFile4, writeFile as writeFile5, unlink, mkdir as mkdir4, chmod } from "fs/promises";
7007
+ import { readFile as readFile4, writeFile as writeFile5, unlink, mkdir as mkdir4, chmod as chmod2 } from "fs/promises";
6976
7008
  import { existsSync as existsSync12 } from "fs";
6977
- import path20 from "path";
7009
+ import path22 from "path";
7010
+ import os7 from "os";
6978
7011
  import crypto6 from "crypto";
6979
7012
  function getKeyDir() {
6980
- return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path20.join(process.env.HOME ?? "/tmp", ".exe-os");
7013
+ return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path22.join(os7.homedir(), ".exe-os");
6981
7014
  }
6982
7015
  function getKeyPath() {
6983
- return path20.join(getKeyDir(), "master.key");
7016
+ return path22.join(getKeyDir(), "master.key");
6984
7017
  }
6985
7018
  async function tryKeytar() {
6986
7019
  try {
@@ -7025,7 +7058,7 @@ async function setMasterKey(key) {
7025
7058
  await mkdir4(dir, { recursive: true });
7026
7059
  const keyPath = getKeyPath();
7027
7060
  await writeFile5(keyPath, b64 + "\n", "utf-8");
7028
- await chmod(keyPath, 384);
7061
+ await chmod2(keyPath, 384);
7029
7062
  }
7030
7063
  async function deleteMasterKey() {
7031
7064
  const keytar = await tryKeytar();
@@ -7367,8 +7400,8 @@ __export(wiki_client_exports, {
7367
7400
  listDocuments: () => listDocuments,
7368
7401
  listWorkspaces: () => listWorkspaces
7369
7402
  });
7370
- async function wikiFetch(config, path22, method = "GET", body) {
7371
- const url = `${config.baseUrl}/api/v1${path22}`;
7403
+ async function wikiFetch(config, path24, method = "GET", body) {
7404
+ const url = `${config.baseUrl}/api/v1${path24}`;
7372
7405
  const headers = {
7373
7406
  Authorization: `Bearer ${config.apiKey}`,
7374
7407
  "Content-Type": "application/json"
@@ -7376,14 +7409,32 @@ async function wikiFetch(config, path22, method = "GET", body) {
7376
7409
  const controller = new AbortController();
7377
7410
  const timeout = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
7378
7411
  try {
7379
- const response = await fetch(url, {
7380
- method,
7381
- headers,
7382
- body: body ? JSON.stringify(body) : void 0,
7383
- signal: controller.signal
7384
- });
7412
+ let response;
7413
+ try {
7414
+ response = await fetch(url, {
7415
+ method,
7416
+ headers,
7417
+ body: body ? JSON.stringify(body) : void 0,
7418
+ signal: controller.signal
7419
+ });
7420
+ } catch {
7421
+ clearTimeout(timeout);
7422
+ const retryController = new AbortController();
7423
+ const retryTimeout = setTimeout(() => retryController.abort(), REQUEST_TIMEOUT_MS);
7424
+ try {
7425
+ await new Promise((r) => setTimeout(r, 500));
7426
+ response = await fetch(url, {
7427
+ method,
7428
+ headers,
7429
+ body: body ? JSON.stringify(body) : void 0,
7430
+ signal: retryController.signal
7431
+ });
7432
+ } finally {
7433
+ clearTimeout(retryTimeout);
7434
+ }
7435
+ }
7385
7436
  if (!response.ok) {
7386
- throw new Error(`Wiki API ${method} ${path22}: ${response.status} ${response.statusText}`);
7437
+ throw new Error(`Wiki API ${method} ${path24}: ${response.status} ${response.statusText}`);
7387
7438
  }
7388
7439
  return response.json();
7389
7440
  } finally {
@@ -7504,7 +7555,7 @@ __export(shard_manager_exports, {
7504
7555
  listShards: () => listShards,
7505
7556
  shardExists: () => shardExists
7506
7557
  });
7507
- import path21 from "path";
7558
+ import path23 from "path";
7508
7559
  import { existsSync as existsSync13, mkdirSync as mkdirSync6, readdirSync as readdirSync3 } from "fs";
7509
7560
  import { createClient as createClient2 } from "@libsql/client";
7510
7561
  function initShardManager(encryptionKey) {
@@ -7530,7 +7581,7 @@ function getShardClient(projectName) {
7530
7581
  }
7531
7582
  const cached = _shards.get(safeName);
7532
7583
  if (cached) return cached;
7533
- const dbPath = path21.join(SHARDS_DIR, `${safeName}.db`);
7584
+ const dbPath = path23.join(SHARDS_DIR, `${safeName}.db`);
7534
7585
  const client = createClient2({
7535
7586
  url: `file:${dbPath}`,
7536
7587
  encryptionKey: _encryptionKey
@@ -7540,7 +7591,7 @@ function getShardClient(projectName) {
7540
7591
  }
7541
7592
  function shardExists(projectName) {
7542
7593
  const safeName = projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
7543
- return existsSync13(path21.join(SHARDS_DIR, `${safeName}.db`));
7594
+ return existsSync13(path23.join(SHARDS_DIR, `${safeName}.db`));
7544
7595
  }
7545
7596
  function listShards() {
7546
7597
  if (!existsSync13(SHARDS_DIR)) return [];
@@ -7725,7 +7776,7 @@ var init_shard_manager = __esm({
7725
7776
  "src/lib/shard-manager.ts"() {
7726
7777
  "use strict";
7727
7778
  init_config();
7728
- SHARDS_DIR = path21.join(EXE_AI_DIR, "shards");
7779
+ SHARDS_DIR = path23.join(EXE_AI_DIR, "shards");
7729
7780
  _shards = /* @__PURE__ */ new Map();
7730
7781
  _encryptionKey = null;
7731
7782
  _shardingEnabled = false;
@@ -7749,6 +7800,28 @@ __export(store_exports, {
7749
7800
  vectorToBlob: () => vectorToBlob,
7750
7801
  writeMemory: () => writeMemory
7751
7802
  });
7803
+ function isBusyError2(err) {
7804
+ if (err instanceof Error) {
7805
+ const msg = err.message.toLowerCase();
7806
+ return msg.includes("sqlite_busy") || msg.includes("database is locked");
7807
+ }
7808
+ return false;
7809
+ }
7810
+ async function retryOnBusy2(fn, label) {
7811
+ for (let attempt = 0; attempt <= INIT_MAX_RETRIES; attempt++) {
7812
+ try {
7813
+ return await fn();
7814
+ } catch (err) {
7815
+ if (!isBusyError2(err) || attempt === INIT_MAX_RETRIES) throw err;
7816
+ process.stderr.write(
7817
+ `[store] SQLITE_BUSY during ${label}, retry ${attempt + 1}/${INIT_MAX_RETRIES}
7818
+ `
7819
+ );
7820
+ await new Promise((r) => setTimeout(r, INIT_RETRY_DELAY_MS * (attempt + 1)));
7821
+ }
7822
+ }
7823
+ throw new Error("unreachable");
7824
+ }
7752
7825
  async function initStore(options) {
7753
7826
  if (_flushTimer !== null) {
7754
7827
  clearInterval(_flushTimer);
@@ -7777,14 +7850,17 @@ async function initStore(options) {
7777
7850
  dbPath,
7778
7851
  encryptionKey: hexKey
7779
7852
  });
7780
- await ensureSchema();
7853
+ await retryOnBusy2(() => ensureSchema(), "ensureSchema");
7781
7854
  try {
7782
7855
  const { initShardManager: initShardManager2 } = await Promise.resolve().then(() => (init_shard_manager(), shard_manager_exports));
7783
7856
  initShardManager2(hexKey);
7784
7857
  } catch {
7785
7858
  }
7786
7859
  const client = getClient();
7787
- const vResult = await client.execute("SELECT MAX(version) as max_v FROM memories");
7860
+ const vResult = await retryOnBusy2(
7861
+ () => client.execute("SELECT MAX(version) as max_v FROM memories"),
7862
+ "version-query"
7863
+ );
7788
7864
  _nextVersion = (Number(vResult.rows[0]?.max_v) || 0) + 1;
7789
7865
  }
7790
7866
  function classifyTier(record) {
@@ -8164,7 +8240,7 @@ async function getMemoryCardinality(agentId) {
8164
8240
  return 0;
8165
8241
  }
8166
8242
  }
8167
- var _pendingRecords, _batchSize, _flushIntervalMs, _flushTimer, _flushing, _nextVersion;
8243
+ var INIT_MAX_RETRIES, INIT_RETRY_DELAY_MS, _pendingRecords, _batchSize, _flushIntervalMs, _flushTimer, _flushing, _nextVersion;
8168
8244
  var init_store = __esm({
8169
8245
  "src/lib/store.ts"() {
8170
8246
  "use strict";
@@ -8172,6 +8248,8 @@ var init_store = __esm({
8172
8248
  init_database();
8173
8249
  init_keychain();
8174
8250
  init_config();
8251
+ INIT_MAX_RETRIES = 3;
8252
+ INIT_RETRY_DELAY_MS = 1e3;
8175
8253
  _pendingRecords = [];
8176
8254
  _batchSize = 20;
8177
8255
  _flushIntervalMs = 1e4;
@@ -12176,8 +12254,8 @@ function Text({ color, backgroundColor, dimColor = false, bold = false, italic =
12176
12254
  }
12177
12255
 
12178
12256
  // src/tui/ink/components/ErrorOverview.js
12179
- var cleanupPath = (path22) => {
12180
- return path22?.replace(`file://${cwd()}/`, "");
12257
+ var cleanupPath = (path24) => {
12258
+ return path24?.replace(`file://${cwd()}/`, "");
12181
12259
  };
12182
12260
  var stackUtils = new StackUtils({
12183
12261
  cwd: cwd(),
@@ -14185,6 +14263,8 @@ function Footer() {
14185
14263
  // src/tui/views/CommandCenter.tsx
14186
14264
  import { useState as useState6, useEffect as useEffect8, useMemo as useMemo4, useCallback as useCallback4, useRef as useRef4 } from "react";
14187
14265
  import TextInput from "ink-text-input";
14266
+ import path11 from "path";
14267
+ import { homedir } from "os";
14188
14268
 
14189
14269
  // src/tui/components/StatusDot.tsx
14190
14270
  import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
@@ -14207,7 +14287,7 @@ function StatusDot({ status, showLabel = true }) {
14207
14287
 
14208
14288
  // src/tui/demo-data.ts
14209
14289
  var DEMO_EMPLOYEES = [
14210
- { name: "exe", role: "COO", status: "active", activity: "Reviewing yoshi's task-aware behavior injection PR", memoryCount: 16409, projects: [
14290
+ { name: "exe", role: "COO", status: "active", activity: "Reviewing yoshi's task-aware behavior injection PR", memoryCount: 15e3, projects: [
14211
14291
  { name: "exe-os", status: "active" },
14212
14292
  { name: "exe-create", status: "has_tasks" },
14213
14293
  { name: "openclaw", status: "idle" }
@@ -14216,7 +14296,7 @@ var DEMO_EMPLOYEES = [
14216
14296
  "Dispatched behavior injection task",
14217
14297
  "Approved gateway Phase 4"
14218
14298
  ] },
14219
- { name: "yoshi", role: "CTO", status: "active", activity: "Implementing skill learning trajectory capture", memoryCount: 8164, projects: [
14299
+ { name: "yoshi", role: "CTO", status: "active", activity: "Implementing skill learning trajectory capture", memoryCount: 8e3, projects: [
14220
14300
  { name: "exe-os", status: "active" },
14221
14301
  { name: "exe-create", status: "idle" }
14222
14302
  ], recentTasks: [
@@ -14224,7 +14304,7 @@ var DEMO_EMPLOYEES = [
14224
14304
  "Fixed TUI mouse listener leak",
14225
14305
  "Built task-aware behavior injection"
14226
14306
  ] },
14227
- { name: "mari", role: "CMO", status: "idle", activity: "", memoryCount: 2158, projects: [
14307
+ { name: "mari", role: "CMO", status: "idle", activity: "", memoryCount: 2e3, projects: [
14228
14308
  { name: "exe-build-skills", status: "has_tasks" },
14229
14309
  { name: "exe-os", status: "idle" }
14230
14310
  ], recentTasks: [
@@ -14232,13 +14312,13 @@ var DEMO_EMPLOYEES = [
14232
14312
  "Designed exe-os UI system",
14233
14313
  "Fixed logo layouts"
14234
14314
  ] },
14235
- { name: "tom", role: "Principal Engineer", status: "idle", activity: "", memoryCount: 689, projects: [
14315
+ { name: "tom", role: "Principal Engineer", status: "idle", activity: "", memoryCount: 700, projects: [
14236
14316
  { name: "exe-os", status: "idle" }
14237
14317
  ], recentTasks: [
14238
14318
  "Implemented BashTool sandboxed execution",
14239
14319
  "Ported session scoping to exe-agent-memory"
14240
14320
  ] },
14241
- { name: "sasha", role: "Content Production", status: "offline", activity: "", memoryCount: 60, projects: [
14321
+ { name: "sasha", role: "Content Production", status: "offline", activity: "", memoryCount: 50, projects: [
14242
14322
  { name: "exe-build-skills", status: "idle" }
14243
14323
  ], recentTasks: [
14244
14324
  "Rendered carousel export prototype"
@@ -14251,7 +14331,7 @@ var DEMO_ACTIVITY = [
14251
14331
  { time: "11:15", agent: "mari", action: "Completed exe-os UI design system" },
14252
14332
  { time: "10:50", agent: "exe", action: "Approved gateway Phase 4" }
14253
14333
  ];
14254
- var DEMO_HEALTH = { memories: 27453, daemon: "running", cloud: "disabled" };
14334
+ var DEMO_HEALTH = { memories: 25750, daemon: "running", cloud: "disabled" };
14255
14335
  var DEMO_PROJECTS = [
14256
14336
  {
14257
14337
  projectName: "exe-os",
@@ -14829,8 +14909,8 @@ function CommandCenterView({
14829
14909
  const { createDefaultHooks: createDefaultHooks2 } = await Promise.resolve().then(() => (init_hooks(), hooks_exports));
14830
14910
  const { readFileSync: readFileSync11, existsSync: existsSync14 } = await import("fs");
14831
14911
  const { join } = await import("path");
14832
- const { homedir } = await import("os");
14833
- const configPath = join(homedir(), ".exe-os", "config.json");
14912
+ const { homedir: homedir3 } = await import("os");
14913
+ const configPath = join(homedir3(), ".exe-os", "config.json");
14834
14914
  let failoverChain = ["anthropic", "opencode", "gemini", "openai"];
14835
14915
  let providerConfigs = {};
14836
14916
  if (existsSync14(configPath)) {
@@ -14893,7 +14973,7 @@ function CommandCenterView({
14893
14973
  registry.register(BashTool2);
14894
14974
  let agentRole = "CTO";
14895
14975
  try {
14896
- const markerDir = join(homedir(), ".exe-os", "session-cache");
14976
+ const markerDir = join(homedir3(), ".exe-os", "session-cache");
14897
14977
  const agentFiles = (await import("fs")).readdirSync(markerDir).filter((f) => f.startsWith("active-agent-"));
14898
14978
  for (const f of agentFiles) {
14899
14979
  const data = JSON.parse(readFileSync11(join(markerDir, f), "utf8"));
@@ -15033,10 +15113,10 @@ function CommandCenterView({
15033
15113
  const demoEntries = DEMO_PROJECTS.map((p) => ({
15034
15114
  projectName: p.projectName,
15035
15115
  exeSession: p.exeSession,
15036
- projectDir: `/Users/demo/${p.projectName}`,
15116
+ projectDir: path11.join(homedir(), p.projectName),
15037
15117
  employeeCount: p.employees.length,
15038
15118
  activeCount: p.employees.filter((e) => e.status === "active").length,
15039
- memoryCount: p.projectName === "exe-os" ? 18331 : p.projectName === "exe-create" || p.projectName === "exe-build-skills" ? 2100 : 890,
15119
+ memoryCount: p.employees.length * 4e3,
15040
15120
  status: p.employees.some((e) => e.status === "active") ? "active" : "idle",
15041
15121
  type: p.projectName.startsWith("exe-") ? "code" : "automation",
15042
15122
  recentTasks: DEMO_RECENT_TASKS[p.projectName] ?? []
@@ -15434,6 +15514,8 @@ function ChatMessageRow({ msg }) {
15434
15514
 
15435
15515
  // src/tui/views/Sessions.tsx
15436
15516
  import { useState as useState9, useEffect as useEffect11, useCallback as useCallback6 } from "react";
15517
+ import path21 from "path";
15518
+ import { homedir as homedir2 } from "os";
15437
15519
 
15438
15520
  // src/tui/components/TmuxPane.tsx
15439
15521
  import { useState as useState7, useEffect as useEffect9 } from "react";
@@ -15712,7 +15794,7 @@ function SessionsView({
15712
15794
  if (demo) {
15713
15795
  setProjects(DEMO_PROJECTS.map((p) => ({
15714
15796
  ...p,
15715
- projectDir: `/Users/demo/${p.projectName}`,
15797
+ projectDir: path21.join(homedir2(), p.projectName),
15716
15798
  employees: p.employees.map((e) => ({ ...e, attached: e.status === "active" }))
15717
15799
  })));
15718
15800
  return;