@askexenow/exe-os 0.8.89 → 0.8.91

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 (44) hide show
  1. package/dist/bin/backfill-conversations.js +10 -0
  2. package/dist/bin/backfill-responses.js +10 -0
  3. package/dist/bin/backfill-vectors.js +10 -0
  4. package/dist/bin/cli.js +75 -30
  5. package/dist/bin/exe-assign.js +13 -3
  6. package/dist/bin/exe-boot.js +34 -24
  7. package/dist/bin/exe-gateway.js +36 -26
  8. package/dist/bin/exe-link.js +10 -0
  9. package/dist/bin/exe-rename.js +10 -0
  10. package/dist/bin/exe-search.js +10 -0
  11. package/dist/bin/exe-session-cleanup.js +30 -20
  12. package/dist/bin/git-sweep.js +25 -15
  13. package/dist/bin/scan-tasks.js +27 -17
  14. package/dist/bin/setup.js +52 -7
  15. package/dist/gateway/index.js +34 -24
  16. package/dist/hooks/commit-complete.js +25 -15
  17. package/dist/hooks/error-recall.js +10 -0
  18. package/dist/hooks/ingest-worker.js +30 -20
  19. package/dist/hooks/instructions-loaded.js +15 -5
  20. package/dist/hooks/notification.js +13 -3
  21. package/dist/hooks/post-compact.js +17 -7
  22. package/dist/hooks/pre-compact.js +25 -15
  23. package/dist/hooks/pre-tool-use.js +20 -10
  24. package/dist/hooks/prompt-ingest-worker.js +10 -0
  25. package/dist/hooks/prompt-submit.js +20 -10
  26. package/dist/hooks/response-ingest-worker.js +10 -0
  27. package/dist/hooks/session-end.js +26 -16
  28. package/dist/hooks/session-start.js +19 -9
  29. package/dist/hooks/stop.js +17 -7
  30. package/dist/hooks/subagent-stop.js +17 -7
  31. package/dist/hooks/summary-worker.js +23 -13
  32. package/dist/index.js +29 -19
  33. package/dist/lib/cloud-sync.js +13 -3
  34. package/dist/lib/database.js +10 -0
  35. package/dist/lib/db-daemon-client.js +10 -0
  36. package/dist/lib/device-registry.js +12 -2
  37. package/dist/lib/embedder.js +10 -0
  38. package/dist/lib/exe-daemon-client.js +10 -0
  39. package/dist/lib/exe-daemon.js +31 -21
  40. package/dist/lib/hybrid-search.js +10 -0
  41. package/dist/mcp/server.js +38 -28
  42. package/dist/runtime/index.js +25 -15
  43. package/dist/tui/App.js +27 -17
  44. package/package.json +1 -1
@@ -286,6 +286,7 @@ __export(exe_daemon_client_exports, {
286
286
  sendDaemonRequest: () => sendDaemonRequest
287
287
  });
288
288
  import net from "net";
289
+ import os2 from "os";
289
290
  import { spawn } from "child_process";
290
291
  import { randomUUID } from "crypto";
291
292
  import { existsSync as existsSync2, unlinkSync, readFileSync as readFileSync2, openSync, closeSync, statSync } from "fs";
@@ -349,6 +350,15 @@ function findPackageRoot() {
349
350
  return null;
350
351
  }
351
352
  function spawnDaemon() {
353
+ const freeGB = os2.freemem() / (1024 * 1024 * 1024);
354
+ const totalGB = os2.totalmem() / (1024 * 1024 * 1024);
355
+ if (freeGB < 1.5 && totalGB <= 8) {
356
+ process.stderr.write(
357
+ `[exed-client] SKIP: low memory (${freeGB.toFixed(1)}GB free / ${totalGB.toFixed(0)}GB total). Embedding daemon not started \u2014 using keyword search only. Close other apps and retry.
358
+ `
359
+ );
360
+ return;
361
+ }
352
362
  const pkgRoot = findPackageRoot();
353
363
  if (!pkgRoot) {
354
364
  process.stderr.write("[exed-client] WARN: cannot find package root\n");
@@ -795,7 +805,7 @@ import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from
795
805
  import { existsSync as existsSync3, symlinkSync, readlinkSync, readFileSync as readFileSync3, renameSync as renameSync2, unlinkSync as unlinkSync2, writeFileSync } from "fs";
796
806
  import { execSync } from "child_process";
797
807
  import path3 from "path";
798
- import os2 from "os";
808
+ import os3 from "os";
799
809
  function normalizeRole(role) {
800
810
  return (role ?? "").trim().toLowerCase();
801
811
  }
@@ -899,7 +909,7 @@ async function normalizeRosterCase(rosterPath) {
899
909
  emp.name = emp.name.toLowerCase();
900
910
  changed = true;
901
911
  try {
902
- const identityDir = path3.join(os2.homedir(), ".exe-os", "identity");
912
+ const identityDir = path3.join(os3.homedir(), ".exe-os", "identity");
903
913
  const oldPath = path3.join(identityDir, `${oldName}.md`);
904
914
  const newPath = path3.join(identityDir, `${emp.name}.md`);
905
915
  if (existsSync3(oldPath) && !existsSync3(newPath)) {
@@ -2196,9 +2206,9 @@ __export(keychain_exports, {
2196
2206
  import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
2197
2207
  import { existsSync as existsSync4 } from "fs";
2198
2208
  import path4 from "path";
2199
- import os3 from "os";
2209
+ import os4 from "os";
2200
2210
  function getKeyDir() {
2201
- return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path4.join(os3.homedir(), ".exe-os");
2211
+ return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path4.join(os4.homedir(), ".exe-os");
2202
2212
  }
2203
2213
  function getKeyPath() {
2204
2214
  return path4.join(getKeyDir(), "master.key");
@@ -2224,7 +2234,7 @@ async function getMasterKey() {
2224
2234
  const keyPath = getKeyPath();
2225
2235
  if (!existsSync4(keyPath)) {
2226
2236
  process.stderr.write(
2227
- `[keychain] Key not found at ${keyPath} (HOME=${os3.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
2237
+ `[keychain] Key not found at ${keyPath} (HOME=${os4.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
2228
2238
  `
2229
2239
  );
2230
2240
  return null;
@@ -5652,7 +5662,7 @@ var init_plan_limits = __esm({
5652
5662
  // src/lib/notifications.ts
5653
5663
  import crypto4 from "crypto";
5654
5664
  import path14 from "path";
5655
- import os4 from "os";
5665
+ import os5 from "os";
5656
5666
  import {
5657
5667
  readFileSync as readFileSync8,
5658
5668
  readdirSync as readdirSync4,
@@ -5704,7 +5714,7 @@ var init_notifications = __esm({
5704
5714
  // src/lib/session-registry.ts
5705
5715
  import { readFileSync as readFileSync9, writeFileSync as writeFileSync6, mkdirSync as mkdirSync4, existsSync as existsSync11 } from "fs";
5706
5716
  import path15 from "path";
5707
- import os5 from "os";
5717
+ import os6 from "os";
5708
5718
  function registerSession(entry) {
5709
5719
  const dir = path15.dirname(REGISTRY_PATH);
5710
5720
  if (!existsSync11(dir)) {
@@ -5731,7 +5741,7 @@ var REGISTRY_PATH;
5731
5741
  var init_session_registry = __esm({
5732
5742
  "src/lib/session-registry.ts"() {
5733
5743
  "use strict";
5734
- REGISTRY_PATH = path15.join(os5.homedir(), ".exe-os", "session-registry.json");
5744
+ REGISTRY_PATH = path15.join(os6.homedir(), ".exe-os", "session-registry.json");
5735
5745
  }
5736
5746
  });
5737
5747
 
@@ -5998,7 +6008,7 @@ var init_agent_config = __esm({
5998
6008
  // src/lib/intercom-queue.ts
5999
6009
  import { readFileSync as readFileSync11, writeFileSync as writeFileSync8, renameSync as renameSync3, existsSync as existsSync13, mkdirSync as mkdirSync6 } from "fs";
6000
6010
  import path17 from "path";
6001
- import os6 from "os";
6011
+ import os7 from "os";
6002
6012
  function ensureDir() {
6003
6013
  const dir = path17.dirname(QUEUE_PATH);
6004
6014
  if (!existsSync13(dir)) mkdirSync6(dir, { recursive: true });
@@ -6038,9 +6048,9 @@ var QUEUE_PATH, TTL_MS, INTERCOM_LOG;
6038
6048
  var init_intercom_queue = __esm({
6039
6049
  "src/lib/intercom-queue.ts"() {
6040
6050
  "use strict";
6041
- QUEUE_PATH = path17.join(os6.homedir(), ".exe-os", "intercom-queue.json");
6051
+ QUEUE_PATH = path17.join(os7.homedir(), ".exe-os", "intercom-queue.json");
6042
6052
  TTL_MS = 60 * 60 * 1e3;
6043
- INTERCOM_LOG = path17.join(os6.homedir(), ".exe-os", "intercom.log");
6053
+ INTERCOM_LOG = path17.join(os7.homedir(), ".exe-os", "intercom.log");
6044
6054
  }
6045
6055
  });
6046
6056
 
@@ -6420,7 +6430,7 @@ __export(tmux_routing_exports, {
6420
6430
  import { execFileSync as execFileSync2, execSync as execSync7 } from "child_process";
6421
6431
  import { readFileSync as readFileSync12, writeFileSync as writeFileSync9, mkdirSync as mkdirSync7, existsSync as existsSync14, appendFileSync } from "fs";
6422
6432
  import path18 from "path";
6423
- import os7 from "os";
6433
+ import os8 from "os";
6424
6434
  import { fileURLToPath as fileURLToPath2 } from "url";
6425
6435
  import { unlinkSync as unlinkSync5 } from "fs";
6426
6436
  function spawnLockPath(sessionName) {
@@ -6834,7 +6844,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
6834
6844
  const transport = getTransport();
6835
6845
  const sessionName = employeeSessionName(employeeName, exeSession, opts?.instance);
6836
6846
  const instanceLabel = opts?.instance != null && opts.instance > 0 ? `${employeeName}${opts.instance}` : employeeName;
6837
- const logDir = path18.join(os7.homedir(), ".exe-os", "session-logs");
6847
+ const logDir = path18.join(os8.homedir(), ".exe-os", "session-logs");
6838
6848
  const logFile = path18.join(logDir, `${instanceLabel}-${Date.now()}.log`);
6839
6849
  if (!existsSync14(logDir)) {
6840
6850
  mkdirSync7(logDir, { recursive: true });
@@ -6850,7 +6860,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
6850
6860
  } catch {
6851
6861
  }
6852
6862
  try {
6853
- const claudeJsonPath = path18.join(os7.homedir(), ".claude.json");
6863
+ const claudeJsonPath = path18.join(os8.homedir(), ".claude.json");
6854
6864
  let claudeJson = {};
6855
6865
  try {
6856
6866
  claudeJson = JSON.parse(readFileSync12(claudeJsonPath, "utf8"));
@@ -6865,7 +6875,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
6865
6875
  } catch {
6866
6876
  }
6867
6877
  try {
6868
- const settingsDir = path18.join(os7.homedir(), ".claude", "projects");
6878
+ const settingsDir = path18.join(os8.homedir(), ".claude", "projects");
6869
6879
  const normalizedKey = (opts?.cwd ?? projectDir).replace(/\//g, "-").replace(/^-/, "");
6870
6880
  const projSettingsDir = path18.join(settingsDir, normalizedKey);
6871
6881
  const settingsPath = path18.join(projSettingsDir, "settings.json");
@@ -6916,7 +6926,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
6916
6926
  let legacyFallbackWarned = false;
6917
6927
  if (!useExeAgent && !useBinSymlink) {
6918
6928
  const identityPath2 = path18.join(
6919
- os7.homedir(),
6929
+ os8.homedir(),
6920
6930
  ".exe-os",
6921
6931
  "identity",
6922
6932
  `${employeeName}.md`
@@ -6946,7 +6956,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
6946
6956
  }
6947
6957
  let sessionContextFlag = "";
6948
6958
  try {
6949
- const ctxDir = path18.join(os7.homedir(), ".exe-os", "session-cache");
6959
+ const ctxDir = path18.join(os8.homedir(), ".exe-os", "session-cache");
6950
6960
  mkdirSync7(ctxDir, { recursive: true });
6951
6961
  const ctxFile = path18.join(ctxDir, `session-context-${sessionName}.md`);
6952
6962
  const ctxContent = [
@@ -7107,13 +7117,13 @@ var init_tmux_routing = __esm({
7107
7117
  init_intercom_queue();
7108
7118
  init_plan_limits();
7109
7119
  init_employees();
7110
- SPAWN_LOCK_DIR = path18.join(os7.homedir(), ".exe-os", "spawn-locks");
7111
- SESSION_CACHE = path18.join(os7.homedir(), ".exe-os", "session-cache");
7120
+ SPAWN_LOCK_DIR = path18.join(os8.homedir(), ".exe-os", "spawn-locks");
7121
+ SESSION_CACHE = path18.join(os8.homedir(), ".exe-os", "session-cache");
7112
7122
  BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
7113
7123
  VALID_SESSION_NAME = /^[a-z]+\d*-[a-zA-Z0-9_]+$/;
7114
7124
  VERIFY_PANE_LINES = 200;
7115
7125
  INTERCOM_DEBOUNCE_MS = 3e4;
7116
- INTERCOM_LOG2 = path18.join(os7.homedir(), ".exe-os", "intercom.log");
7126
+ INTERCOM_LOG2 = path18.join(os8.homedir(), ".exe-os", "intercom.log");
7117
7127
  DEBOUNCE_FILE = path18.join(SESSION_CACHE, "intercom-debounce.json");
7118
7128
  DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
7119
7129
  BUSY_PATTERN = /[✻✽✶✳·].*…|Running…/;
@@ -7163,7 +7173,7 @@ __export(tasks_crud_exports, {
7163
7173
  });
7164
7174
  import crypto6 from "crypto";
7165
7175
  import path19 from "path";
7166
- import os8 from "os";
7176
+ import os9 from "os";
7167
7177
  import { execSync as execSync8 } from "child_process";
7168
7178
  import { mkdir as mkdir4, writeFile as writeFile4, appendFile } from "fs/promises";
7169
7179
  import { existsSync as existsSync15, readFileSync as readFileSync13 } from "fs";
@@ -7378,7 +7388,7 @@ ${laneWarning}` : laneWarning;
7378
7388
  });
7379
7389
  if (input.baseDir) {
7380
7390
  try {
7381
- const EXE_OS_DIR = path19.join(os8.homedir(), ".exe-os");
7391
+ const EXE_OS_DIR = path19.join(os9.homedir(), ".exe-os");
7382
7392
  const mdPath = path19.join(EXE_OS_DIR, taskFile);
7383
7393
  const mdDir = path19.dirname(mdPath);
7384
7394
  if (!existsSync15(mdDir)) await mkdir4(mdDir, { recursive: true });
@@ -12926,8 +12936,8 @@ import { z as z29 } from "zod";
12926
12936
  import { readFileSync as readFileSync16, writeFileSync as writeFileSync12, existsSync as existsSync18, mkdirSync as mkdirSync10 } from "fs";
12927
12937
  import { randomUUID as randomUUID4 } from "crypto";
12928
12938
  import path24 from "path";
12929
- import os9 from "os";
12930
- var TRIGGERS_PATH = path24.join(os9.homedir(), ".exe-os", "triggers.json");
12939
+ import os10 from "os";
12940
+ var TRIGGERS_PATH = path24.join(os10.homedir(), ".exe-os", "triggers.json");
12931
12941
  function loadTriggers(project) {
12932
12942
  if (!existsSync18(TRIGGERS_PATH)) return [];
12933
12943
  try {
@@ -15470,7 +15480,7 @@ import { readdir } from "fs/promises";
15470
15480
  import { createReadStream } from "fs";
15471
15481
  import { createInterface } from "readline";
15472
15482
  import path29 from "path";
15473
- import os10 from "os";
15483
+ import os11 from "os";
15474
15484
  var MODEL_PRICING = {
15475
15485
  // Opus 4.5+ ($5/$25 — Anthropic price drop from original Opus 4)
15476
15486
  "claude-opus-4-7": { input: 5 / 1e6, output: 25 / 1e6, cacheRead: 0.5 / 1e6, cacheWrite: 6.25 / 1e6 },
@@ -15518,7 +15528,7 @@ async function getAgentSpend(period = "7d") {
15518
15528
  for (const row of result.rows) {
15519
15529
  sessionAgent.set(row.session_uuid, row.agent_id);
15520
15530
  }
15521
- const claudeDir = path29.join(os10.homedir(), ".claude", "projects");
15531
+ const claudeDir = path29.join(os11.homedir(), ".claude", "projects");
15522
15532
  let projectDirs = [];
15523
15533
  try {
15524
15534
  const entries = await readdir(claudeDir);
@@ -16108,8 +16118,8 @@ function registerExportGraph(server2) {
16108
16118
  const html = await exportGraphHTML(client);
16109
16119
  const fs = await import("fs");
16110
16120
  const path38 = await import("path");
16111
- const os11 = await import("os");
16112
- const outDir = path38.join(os11.homedir(), ".exe-os", "exports");
16121
+ const os12 = await import("os");
16122
+ const outDir = path38.join(os12.homedir(), ".exe-os", "exports");
16113
16123
  fs.mkdirSync(outDir, { recursive: true });
16114
16124
  const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-").slice(0, 19);
16115
16125
  const filePath = path38.join(outDir, `graph-${timestamp}.html`);
@@ -701,6 +701,7 @@ var init_db_retry = __esm({
701
701
 
702
702
  // src/lib/exe-daemon-client.ts
703
703
  import net from "net";
704
+ import os6 from "os";
704
705
  import { spawn } from "child_process";
705
706
  import { randomUUID as randomUUID2 } from "crypto";
706
707
  import { existsSync as existsSync6, unlinkSync as unlinkSync2, readFileSync as readFileSync6, openSync, closeSync, statSync } from "fs";
@@ -764,6 +765,15 @@ function findPackageRoot() {
764
765
  return null;
765
766
  }
766
767
  function spawnDaemon() {
768
+ const freeGB = os6.freemem() / (1024 * 1024 * 1024);
769
+ const totalGB = os6.totalmem() / (1024 * 1024 * 1024);
770
+ if (freeGB < 1.5 && totalGB <= 8) {
771
+ process.stderr.write(
772
+ `[exed-client] SKIP: low memory (${freeGB.toFixed(1)}GB free / ${totalGB.toFixed(0)}GB total). Embedding daemon not started \u2014 using keyword search only. Close other apps and retry.
773
+ `
774
+ );
775
+ return;
776
+ }
767
777
  const pkgRoot = findPackageRoot();
768
778
  if (!pkgRoot) {
769
779
  process.stderr.write("[exed-client] WARN: cannot find package root\n");
@@ -2253,7 +2263,7 @@ var init_plan_limits = __esm({
2253
2263
  // src/lib/notifications.ts
2254
2264
  import crypto from "crypto";
2255
2265
  import path10 from "path";
2256
- import os6 from "os";
2266
+ import os7 from "os";
2257
2267
  import {
2258
2268
  readFileSync as readFileSync9,
2259
2269
  readdirSync,
@@ -2423,7 +2433,7 @@ var init_state_bus = __esm({
2423
2433
  // src/lib/tasks-crud.ts
2424
2434
  import crypto3 from "crypto";
2425
2435
  import path11 from "path";
2426
- import os7 from "os";
2436
+ import os8 from "os";
2427
2437
  import { execSync as execSync5 } from "child_process";
2428
2438
  import { mkdir as mkdir3, writeFile as writeFile3, appendFile } from "fs/promises";
2429
2439
  import { existsSync as existsSync10, readFileSync as readFileSync10 } from "fs";
@@ -2638,7 +2648,7 @@ ${laneWarning}` : laneWarning;
2638
2648
  });
2639
2649
  if (input.baseDir) {
2640
2650
  try {
2641
- const EXE_OS_DIR = path11.join(os7.homedir(), ".exe-os");
2651
+ const EXE_OS_DIR = path11.join(os8.homedir(), ".exe-os");
2642
2652
  const mdPath = path11.join(EXE_OS_DIR, taskFile);
2643
2653
  const mdDir = path11.dirname(mdPath);
2644
2654
  if (!existsSync10(mdDir)) await mkdir3(mdDir, { recursive: true });
@@ -4346,7 +4356,7 @@ __export(tmux_routing_exports, {
4346
4356
  import { execFileSync as execFileSync2, execSync as execSync7 } from "child_process";
4347
4357
  import { readFileSync as readFileSync11, writeFileSync as writeFileSync7, mkdirSync as mkdirSync6, existsSync as existsSync12, appendFileSync } from "fs";
4348
4358
  import path16 from "path";
4349
- import os8 from "os";
4359
+ import os9 from "os";
4350
4360
  import { fileURLToPath as fileURLToPath2 } from "url";
4351
4361
  import { unlinkSync as unlinkSync6 } from "fs";
4352
4362
  function spawnLockPath(sessionName) {
@@ -4760,7 +4770,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
4760
4770
  const transport = getTransport();
4761
4771
  const sessionName = employeeSessionName(employeeName, exeSession, opts?.instance);
4762
4772
  const instanceLabel = opts?.instance != null && opts.instance > 0 ? `${employeeName}${opts.instance}` : employeeName;
4763
- const logDir = path16.join(os8.homedir(), ".exe-os", "session-logs");
4773
+ const logDir = path16.join(os9.homedir(), ".exe-os", "session-logs");
4764
4774
  const logFile = path16.join(logDir, `${instanceLabel}-${Date.now()}.log`);
4765
4775
  if (!existsSync12(logDir)) {
4766
4776
  mkdirSync6(logDir, { recursive: true });
@@ -4776,7 +4786,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
4776
4786
  } catch {
4777
4787
  }
4778
4788
  try {
4779
- const claudeJsonPath = path16.join(os8.homedir(), ".claude.json");
4789
+ const claudeJsonPath = path16.join(os9.homedir(), ".claude.json");
4780
4790
  let claudeJson = {};
4781
4791
  try {
4782
4792
  claudeJson = JSON.parse(readFileSync11(claudeJsonPath, "utf8"));
@@ -4791,7 +4801,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
4791
4801
  } catch {
4792
4802
  }
4793
4803
  try {
4794
- const settingsDir = path16.join(os8.homedir(), ".claude", "projects");
4804
+ const settingsDir = path16.join(os9.homedir(), ".claude", "projects");
4795
4805
  const normalizedKey = (opts?.cwd ?? projectDir).replace(/\//g, "-").replace(/^-/, "");
4796
4806
  const projSettingsDir = path16.join(settingsDir, normalizedKey);
4797
4807
  const settingsPath = path16.join(projSettingsDir, "settings.json");
@@ -4842,7 +4852,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
4842
4852
  let legacyFallbackWarned = false;
4843
4853
  if (!useExeAgent && !useBinSymlink) {
4844
4854
  const identityPath = path16.join(
4845
- os8.homedir(),
4855
+ os9.homedir(),
4846
4856
  ".exe-os",
4847
4857
  "identity",
4848
4858
  `${employeeName}.md`
@@ -4872,7 +4882,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
4872
4882
  }
4873
4883
  let sessionContextFlag = "";
4874
4884
  try {
4875
- const ctxDir = path16.join(os8.homedir(), ".exe-os", "session-cache");
4885
+ const ctxDir = path16.join(os9.homedir(), ".exe-os", "session-cache");
4876
4886
  mkdirSync6(ctxDir, { recursive: true });
4877
4887
  const ctxFile = path16.join(ctxDir, `session-context-${sessionName}.md`);
4878
4888
  const ctxContent = [
@@ -5033,13 +5043,13 @@ var init_tmux_routing = __esm({
5033
5043
  init_intercom_queue();
5034
5044
  init_plan_limits();
5035
5045
  init_employees();
5036
- SPAWN_LOCK_DIR = path16.join(os8.homedir(), ".exe-os", "spawn-locks");
5037
- SESSION_CACHE = path16.join(os8.homedir(), ".exe-os", "session-cache");
5046
+ SPAWN_LOCK_DIR = path16.join(os9.homedir(), ".exe-os", "spawn-locks");
5047
+ SESSION_CACHE = path16.join(os9.homedir(), ".exe-os", "session-cache");
5038
5048
  BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
5039
5049
  VALID_SESSION_NAME = /^[a-z]+\d*-[a-zA-Z0-9_]+$/;
5040
5050
  VERIFY_PANE_LINES = 200;
5041
5051
  INTERCOM_DEBOUNCE_MS = 3e4;
5042
- INTERCOM_LOG2 = path16.join(os8.homedir(), ".exe-os", "intercom.log");
5052
+ INTERCOM_LOG2 = path16.join(os9.homedir(), ".exe-os", "intercom.log");
5043
5053
  DEBOUNCE_FILE = path16.join(SESSION_CACHE, "intercom-debounce.json");
5044
5054
  DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
5045
5055
  BUSY_PATTERN = /[✻✽✶✳·].*…|Running…/;
@@ -5059,9 +5069,9 @@ var init_memory = __esm({
5059
5069
  import { readFile as readFile4, writeFile as writeFile5, unlink, mkdir as mkdir4, chmod as chmod2 } from "fs/promises";
5060
5070
  import { existsSync as existsSync13 } from "fs";
5061
5071
  import path17 from "path";
5062
- import os9 from "os";
5072
+ import os10 from "os";
5063
5073
  function getKeyDir() {
5064
- return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path17.join(os9.homedir(), ".exe-os");
5074
+ return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path17.join(os10.homedir(), ".exe-os");
5065
5075
  }
5066
5076
  function getKeyPath() {
5067
5077
  return path17.join(getKeyDir(), "master.key");
@@ -5087,7 +5097,7 @@ async function getMasterKey() {
5087
5097
  const keyPath = getKeyPath();
5088
5098
  if (!existsSync13(keyPath)) {
5089
5099
  process.stderr.write(
5090
- `[keychain] Key not found at ${keyPath} (HOME=${os9.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
5100
+ `[keychain] Key not found at ${keyPath} (HOME=${os10.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
5091
5101
  `
5092
5102
  );
5093
5103
  return null;
package/dist/tui/App.js CHANGED
@@ -926,6 +926,7 @@ var init_employees = __esm({
926
926
 
927
927
  // src/lib/exe-daemon-client.ts
928
928
  import net from "net";
929
+ import os5 from "os";
929
930
  import { spawn } from "child_process";
930
931
  import { randomUUID } from "crypto";
931
932
  import { existsSync as existsSync7, unlinkSync as unlinkSync2, readFileSync as readFileSync7, openSync, closeSync, statSync } from "fs";
@@ -989,6 +990,15 @@ function findPackageRoot() {
989
990
  return null;
990
991
  }
991
992
  function spawnDaemon() {
993
+ const freeGB = os5.freemem() / (1024 * 1024 * 1024);
994
+ const totalGB = os5.totalmem() / (1024 * 1024 * 1024);
995
+ if (freeGB < 1.5 && totalGB <= 8) {
996
+ process.stderr.write(
997
+ `[exed-client] SKIP: low memory (${freeGB.toFixed(1)}GB free / ${totalGB.toFixed(0)}GB total). Embedding daemon not started \u2014 using keyword search only. Close other apps and retry.
998
+ `
999
+ );
1000
+ return;
1001
+ }
992
1002
  const pkgRoot = findPackageRoot();
993
1003
  if (!pkgRoot) {
994
1004
  process.stderr.write("[exed-client] WARN: cannot find package root\n");
@@ -2842,7 +2852,7 @@ var init_plan_limits = __esm({
2842
2852
  // src/lib/notifications.ts
2843
2853
  import crypto from "crypto";
2844
2854
  import path9 from "path";
2845
- import os5 from "os";
2855
+ import os6 from "os";
2846
2856
  import {
2847
2857
  readFileSync as readFileSync10,
2848
2858
  readdirSync,
@@ -2999,7 +3009,7 @@ __export(tasks_crud_exports, {
2999
3009
  });
3000
3010
  import crypto3 from "crypto";
3001
3011
  import path10 from "path";
3002
- import os6 from "os";
3012
+ import os7 from "os";
3003
3013
  import { execSync as execSync5 } from "child_process";
3004
3014
  import { mkdir as mkdir3, writeFile as writeFile3, appendFile } from "fs/promises";
3005
3015
  import { existsSync as existsSync11, readFileSync as readFileSync11 } from "fs";
@@ -3214,7 +3224,7 @@ ${laneWarning}` : laneWarning;
3214
3224
  });
3215
3225
  if (input.baseDir) {
3216
3226
  try {
3217
- const EXE_OS_DIR = path10.join(os6.homedir(), ".exe-os");
3227
+ const EXE_OS_DIR = path10.join(os7.homedir(), ".exe-os");
3218
3228
  const mdPath = path10.join(EXE_OS_DIR, taskFile);
3219
3229
  const mdDir = path10.dirname(mdPath);
3220
3230
  if (!existsSync11(mdDir)) await mkdir3(mdDir, { recursive: true });
@@ -4860,7 +4870,7 @@ __export(tmux_routing_exports, {
4860
4870
  import { execFileSync as execFileSync3, execSync as execSync7 } from "child_process";
4861
4871
  import { readFileSync as readFileSync12, writeFileSync as writeFileSync7, mkdirSync as mkdirSync6, existsSync as existsSync13, appendFileSync } from "fs";
4862
4872
  import path15 from "path";
4863
- import os7 from "os";
4873
+ import os8 from "os";
4864
4874
  import { fileURLToPath as fileURLToPath2 } from "url";
4865
4875
  import { unlinkSync as unlinkSync6 } from "fs";
4866
4876
  function spawnLockPath(sessionName) {
@@ -5274,7 +5284,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
5274
5284
  const transport = getTransport();
5275
5285
  const sessionName = employeeSessionName(employeeName, exeSession, opts?.instance);
5276
5286
  const instanceLabel = opts?.instance != null && opts.instance > 0 ? `${employeeName}${opts.instance}` : employeeName;
5277
- const logDir = path15.join(os7.homedir(), ".exe-os", "session-logs");
5287
+ const logDir = path15.join(os8.homedir(), ".exe-os", "session-logs");
5278
5288
  const logFile = path15.join(logDir, `${instanceLabel}-${Date.now()}.log`);
5279
5289
  if (!existsSync13(logDir)) {
5280
5290
  mkdirSync6(logDir, { recursive: true });
@@ -5290,7 +5300,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
5290
5300
  } catch {
5291
5301
  }
5292
5302
  try {
5293
- const claudeJsonPath = path15.join(os7.homedir(), ".claude.json");
5303
+ const claudeJsonPath = path15.join(os8.homedir(), ".claude.json");
5294
5304
  let claudeJson = {};
5295
5305
  try {
5296
5306
  claudeJson = JSON.parse(readFileSync12(claudeJsonPath, "utf8"));
@@ -5305,7 +5315,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
5305
5315
  } catch {
5306
5316
  }
5307
5317
  try {
5308
- const settingsDir = path15.join(os7.homedir(), ".claude", "projects");
5318
+ const settingsDir = path15.join(os8.homedir(), ".claude", "projects");
5309
5319
  const normalizedKey = (opts?.cwd ?? projectDir).replace(/\//g, "-").replace(/^-/, "");
5310
5320
  const projSettingsDir = path15.join(settingsDir, normalizedKey);
5311
5321
  const settingsPath = path15.join(projSettingsDir, "settings.json");
@@ -5356,7 +5366,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
5356
5366
  let legacyFallbackWarned = false;
5357
5367
  if (!useExeAgent && !useBinSymlink) {
5358
5368
  const identityPath = path15.join(
5359
- os7.homedir(),
5369
+ os8.homedir(),
5360
5370
  ".exe-os",
5361
5371
  "identity",
5362
5372
  `${employeeName}.md`
@@ -5386,7 +5396,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
5386
5396
  }
5387
5397
  let sessionContextFlag = "";
5388
5398
  try {
5389
- const ctxDir = path15.join(os7.homedir(), ".exe-os", "session-cache");
5399
+ const ctxDir = path15.join(os8.homedir(), ".exe-os", "session-cache");
5390
5400
  mkdirSync6(ctxDir, { recursive: true });
5391
5401
  const ctxFile = path15.join(ctxDir, `session-context-${sessionName}.md`);
5392
5402
  const ctxContent = [
@@ -5547,13 +5557,13 @@ var init_tmux_routing = __esm({
5547
5557
  init_intercom_queue();
5548
5558
  init_plan_limits();
5549
5559
  init_employees();
5550
- SPAWN_LOCK_DIR = path15.join(os7.homedir(), ".exe-os", "spawn-locks");
5551
- SESSION_CACHE = path15.join(os7.homedir(), ".exe-os", "session-cache");
5560
+ SPAWN_LOCK_DIR = path15.join(os8.homedir(), ".exe-os", "spawn-locks");
5561
+ SESSION_CACHE = path15.join(os8.homedir(), ".exe-os", "session-cache");
5552
5562
  BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
5553
5563
  VALID_SESSION_NAME = /^[a-z]+\d*-[a-zA-Z0-9_]+$/;
5554
5564
  VERIFY_PANE_LINES = 200;
5555
5565
  INTERCOM_DEBOUNCE_MS = 3e4;
5556
- INTERCOM_LOG2 = path15.join(os7.homedir(), ".exe-os", "intercom.log");
5566
+ INTERCOM_LOG2 = path15.join(os8.homedir(), ".exe-os", "intercom.log");
5557
5567
  DEBOUNCE_FILE = path15.join(SESSION_CACHE, "intercom-debounce.json");
5558
5568
  DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
5559
5569
  BUSY_PATTERN = /[✻✽✶✳·].*…|Running…/;
@@ -7424,7 +7434,7 @@ var init_hooks = __esm({
7424
7434
 
7425
7435
  // src/runtime/safety-checks.ts
7426
7436
  import path16 from "path";
7427
- import os8 from "os";
7437
+ import os9 from "os";
7428
7438
  function checkPathSafety(filePath) {
7429
7439
  const resolved = path16.resolve(filePath);
7430
7440
  for (const { pattern, reason } of BYPASS_IMMUNE_PATTERNS) {
@@ -7451,7 +7461,7 @@ var HOME, BYPASS_IMMUNE_PATTERNS;
7451
7461
  var init_safety_checks = __esm({
7452
7462
  "src/runtime/safety-checks.ts"() {
7453
7463
  "use strict";
7454
- HOME = os8.homedir();
7464
+ HOME = os9.homedir();
7455
7465
  BYPASS_IMMUNE_PATTERNS = [
7456
7466
  {
7457
7467
  pattern: /\/\.git\/hooks\//,
@@ -8546,9 +8556,9 @@ __export(keychain_exports, {
8546
8556
  import { readFile as readFile4, writeFile as writeFile5, unlink, mkdir as mkdir4, chmod as chmod2 } from "fs/promises";
8547
8557
  import { existsSync as existsSync14 } from "fs";
8548
8558
  import path24 from "path";
8549
- import os9 from "os";
8559
+ import os10 from "os";
8550
8560
  function getKeyDir() {
8551
- return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path24.join(os9.homedir(), ".exe-os");
8561
+ return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path24.join(os10.homedir(), ".exe-os");
8552
8562
  }
8553
8563
  function getKeyPath() {
8554
8564
  return path24.join(getKeyDir(), "master.key");
@@ -8574,7 +8584,7 @@ async function getMasterKey() {
8574
8584
  const keyPath = getKeyPath();
8575
8585
  if (!existsSync14(keyPath)) {
8576
8586
  process.stderr.write(
8577
- `[keychain] Key not found at ${keyPath} (HOME=${os9.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
8587
+ `[keychain] Key not found at ${keyPath} (HOME=${os10.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
8578
8588
  `
8579
8589
  );
8580
8590
  return null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@askexenow/exe-os",
3
- "version": "0.8.89",
3
+ "version": "0.8.91",
4
4
  "description": "AI employee operating system — persistent memory, task management, and multi-agent coordination for Claude Code.",
5
5
  "license": "CC-BY-NC-4.0",
6
6
  "type": "module",