@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
@@ -1689,6 +1689,7 @@ ${p.content}`).join("\n\n");
1689
1689
 
1690
1690
  // src/lib/exe-daemon-client.ts
1691
1691
  import net from "net";
1692
+ import os4 from "os";
1692
1693
  import { spawn } from "child_process";
1693
1694
  import { randomUUID as randomUUID2 } from "crypto";
1694
1695
  import { existsSync as existsSync5, unlinkSync as unlinkSync2, readFileSync as readFileSync3, openSync, closeSync, statSync } from "fs";
@@ -1752,6 +1753,15 @@ function findPackageRoot() {
1752
1753
  return null;
1753
1754
  }
1754
1755
  function spawnDaemon() {
1756
+ const freeGB = os4.freemem() / (1024 * 1024 * 1024);
1757
+ const totalGB = os4.totalmem() / (1024 * 1024 * 1024);
1758
+ if (freeGB < 1.5 && totalGB <= 8) {
1759
+ process.stderr.write(
1760
+ `[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.
1761
+ `
1762
+ );
1763
+ return;
1764
+ }
1755
1765
  const pkgRoot = findPackageRoot();
1756
1766
  if (!pkgRoot) {
1757
1767
  process.stderr.write("[exed-client] WARN: cannot find package root\n");
@@ -1689,6 +1689,7 @@ ${p.content}`).join("\n\n");
1689
1689
 
1690
1690
  // src/lib/exe-daemon-client.ts
1691
1691
  import net from "net";
1692
+ import os4 from "os";
1692
1693
  import { spawn } from "child_process";
1693
1694
  import { randomUUID as randomUUID2 } from "crypto";
1694
1695
  import { existsSync as existsSync5, unlinkSync as unlinkSync2, readFileSync as readFileSync3, openSync, closeSync, statSync } from "fs";
@@ -1752,6 +1753,15 @@ function findPackageRoot() {
1752
1753
  return null;
1753
1754
  }
1754
1755
  function spawnDaemon() {
1756
+ const freeGB = os4.freemem() / (1024 * 1024 * 1024);
1757
+ const totalGB = os4.totalmem() / (1024 * 1024 * 1024);
1758
+ if (freeGB < 1.5 && totalGB <= 8) {
1759
+ process.stderr.write(
1760
+ `[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.
1761
+ `
1762
+ );
1763
+ return;
1764
+ }
1755
1765
  const pkgRoot = findPackageRoot();
1756
1766
  if (!pkgRoot) {
1757
1767
  process.stderr.write("[exed-client] WARN: cannot find package root\n");
@@ -1691,6 +1691,7 @@ ${p.content}`).join("\n\n");
1691
1691
 
1692
1692
  // src/lib/exe-daemon-client.ts
1693
1693
  import net from "net";
1694
+ import os4 from "os";
1694
1695
  import { spawn } from "child_process";
1695
1696
  import { randomUUID as randomUUID2 } from "crypto";
1696
1697
  import { existsSync as existsSync5, unlinkSync as unlinkSync2, readFileSync as readFileSync3, openSync, closeSync, statSync } from "fs";
@@ -1754,6 +1755,15 @@ function findPackageRoot() {
1754
1755
  return null;
1755
1756
  }
1756
1757
  function spawnDaemon() {
1758
+ const freeGB = os4.freemem() / (1024 * 1024 * 1024);
1759
+ const totalGB = os4.totalmem() / (1024 * 1024 * 1024);
1760
+ if (freeGB < 1.5 && totalGB <= 8) {
1761
+ process.stderr.write(
1762
+ `[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.
1763
+ `
1764
+ );
1765
+ return;
1766
+ }
1757
1767
  const pkgRoot = findPackageRoot();
1758
1768
  if (!pkgRoot) {
1759
1769
  process.stderr.write("[exed-client] WARN: cannot find package root\n");
package/dist/bin/cli.js CHANGED
@@ -1389,6 +1389,7 @@ var init_db_retry = __esm({
1389
1389
 
1390
1390
  // src/lib/exe-daemon-client.ts
1391
1391
  import net from "net";
1392
+ import os6 from "os";
1392
1393
  import { spawn } from "child_process";
1393
1394
  import { randomUUID } from "crypto";
1394
1395
  import { existsSync as existsSync6, unlinkSync as unlinkSync2, readFileSync as readFileSync4, openSync, closeSync, statSync } from "fs";
@@ -1452,6 +1453,15 @@ function findPackageRoot() {
1452
1453
  return null;
1453
1454
  }
1454
1455
  function spawnDaemon() {
1456
+ const freeGB = os6.freemem() / (1024 * 1024 * 1024);
1457
+ const totalGB = os6.totalmem() / (1024 * 1024 * 1024);
1458
+ if (freeGB < 1.5 && totalGB <= 8) {
1459
+ process.stderr.write(
1460
+ `[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.
1461
+ `
1462
+ );
1463
+ return;
1464
+ }
1455
1465
  const pkgRoot = findPackageRoot();
1456
1466
  if (!pkgRoot) {
1457
1467
  process.stderr.write("[exed-client] WARN: cannot find package root\n");
@@ -6972,7 +6982,7 @@ __export(session_registry_exports, {
6972
6982
  import { readFileSync as readFileSync8, writeFileSync as writeFileSync6, mkdirSync as mkdirSync7, existsSync as existsSync11 } from "fs";
6973
6983
  import { execSync as execSync3 } from "child_process";
6974
6984
  import path12 from "path";
6975
- import os6 from "os";
6985
+ import os7 from "os";
6976
6986
  function registerSession(entry) {
6977
6987
  const dir = path12.dirname(REGISTRY_PATH);
6978
6988
  if (!existsSync11(dir)) {
@@ -7018,7 +7028,7 @@ var REGISTRY_PATH;
7018
7028
  var init_session_registry = __esm({
7019
7029
  "src/lib/session-registry.ts"() {
7020
7030
  "use strict";
7021
- REGISTRY_PATH = path12.join(os6.homedir(), ".exe-os", "session-registry.json");
7031
+ REGISTRY_PATH = path12.join(os7.homedir(), ".exe-os", "session-registry.json");
7022
7032
  }
7023
7033
  });
7024
7034
 
@@ -7276,7 +7286,7 @@ var init_agent_config = __esm({
7276
7286
  // src/lib/intercom-queue.ts
7277
7287
  import { readFileSync as readFileSync10, writeFileSync as writeFileSync8, renameSync as renameSync3, existsSync as existsSync13, mkdirSync as mkdirSync9 } from "fs";
7278
7288
  import path14 from "path";
7279
- import os7 from "os";
7289
+ import os8 from "os";
7280
7290
  function ensureDir() {
7281
7291
  const dir = path14.dirname(QUEUE_PATH);
7282
7292
  if (!existsSync13(dir)) mkdirSync9(dir, { recursive: true });
@@ -7316,9 +7326,9 @@ var QUEUE_PATH, TTL_MS, INTERCOM_LOG;
7316
7326
  var init_intercom_queue = __esm({
7317
7327
  "src/lib/intercom-queue.ts"() {
7318
7328
  "use strict";
7319
- QUEUE_PATH = path14.join(os7.homedir(), ".exe-os", "intercom-queue.json");
7329
+ QUEUE_PATH = path14.join(os8.homedir(), ".exe-os", "intercom-queue.json");
7320
7330
  TTL_MS = 60 * 60 * 1e3;
7321
- INTERCOM_LOG = path14.join(os7.homedir(), ".exe-os", "intercom.log");
7331
+ INTERCOM_LOG = path14.join(os8.homedir(), ".exe-os", "intercom.log");
7322
7332
  }
7323
7333
  });
7324
7334
 
@@ -7403,7 +7413,7 @@ var init_plan_limits = __esm({
7403
7413
  // src/lib/notifications.ts
7404
7414
  import crypto5 from "crypto";
7405
7415
  import path16 from "path";
7406
- import os8 from "os";
7416
+ import os9 from "os";
7407
7417
  import {
7408
7418
  readFileSync as readFileSync12,
7409
7419
  readdirSync as readdirSync3,
@@ -7534,7 +7544,7 @@ __export(tasks_crud_exports, {
7534
7544
  });
7535
7545
  import crypto7 from "crypto";
7536
7546
  import path17 from "path";
7537
- import os9 from "os";
7547
+ import os10 from "os";
7538
7548
  import { execSync as execSync6 } from "child_process";
7539
7549
  import { mkdir as mkdir5, writeFile as writeFile5, appendFile } from "fs/promises";
7540
7550
  import { existsSync as existsSync16, readFileSync as readFileSync13 } from "fs";
@@ -7749,7 +7759,7 @@ ${laneWarning}` : laneWarning;
7749
7759
  });
7750
7760
  if (input.baseDir) {
7751
7761
  try {
7752
- const EXE_OS_DIR = path17.join(os9.homedir(), ".exe-os");
7762
+ const EXE_OS_DIR = path17.join(os10.homedir(), ".exe-os");
7753
7763
  const mdPath = path17.join(EXE_OS_DIR, taskFile);
7754
7764
  const mdDir = path17.dirname(mdPath);
7755
7765
  if (!existsSync16(mdDir)) await mkdir5(mdDir, { recursive: true });
@@ -9395,7 +9405,7 @@ __export(tmux_routing_exports, {
9395
9405
  import { execFileSync as execFileSync2, execSync as execSync8 } from "child_process";
9396
9406
  import { readFileSync as readFileSync14, writeFileSync as writeFileSync10, mkdirSync as mkdirSync11, existsSync as existsSync18, appendFileSync as appendFileSync2 } from "fs";
9397
9407
  import path22 from "path";
9398
- import os10 from "os";
9408
+ import os11 from "os";
9399
9409
  import { fileURLToPath as fileURLToPath4 } from "url";
9400
9410
  import { unlinkSync as unlinkSync8 } from "fs";
9401
9411
  function spawnLockPath(sessionName) {
@@ -9809,7 +9819,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
9809
9819
  const transport = getTransport();
9810
9820
  const sessionName = employeeSessionName(employeeName, exeSession, opts?.instance);
9811
9821
  const instanceLabel = opts?.instance != null && opts.instance > 0 ? `${employeeName}${opts.instance}` : employeeName;
9812
- const logDir = path22.join(os10.homedir(), ".exe-os", "session-logs");
9822
+ const logDir = path22.join(os11.homedir(), ".exe-os", "session-logs");
9813
9823
  const logFile = path22.join(logDir, `${instanceLabel}-${Date.now()}.log`);
9814
9824
  if (!existsSync18(logDir)) {
9815
9825
  mkdirSync11(logDir, { recursive: true });
@@ -9825,7 +9835,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
9825
9835
  } catch {
9826
9836
  }
9827
9837
  try {
9828
- const claudeJsonPath = path22.join(os10.homedir(), ".claude.json");
9838
+ const claudeJsonPath = path22.join(os11.homedir(), ".claude.json");
9829
9839
  let claudeJson = {};
9830
9840
  try {
9831
9841
  claudeJson = JSON.parse(readFileSync14(claudeJsonPath, "utf8"));
@@ -9840,7 +9850,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
9840
9850
  } catch {
9841
9851
  }
9842
9852
  try {
9843
- const settingsDir = path22.join(os10.homedir(), ".claude", "projects");
9853
+ const settingsDir = path22.join(os11.homedir(), ".claude", "projects");
9844
9854
  const normalizedKey = (opts?.cwd ?? projectDir).replace(/\//g, "-").replace(/^-/, "");
9845
9855
  const projSettingsDir = path22.join(settingsDir, normalizedKey);
9846
9856
  const settingsPath = path22.join(projSettingsDir, "settings.json");
@@ -9891,7 +9901,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
9891
9901
  let legacyFallbackWarned = false;
9892
9902
  if (!useExeAgent && !useBinSymlink) {
9893
9903
  const identityPath2 = path22.join(
9894
- os10.homedir(),
9904
+ os11.homedir(),
9895
9905
  ".exe-os",
9896
9906
  "identity",
9897
9907
  `${employeeName}.md`
@@ -9921,7 +9931,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
9921
9931
  }
9922
9932
  let sessionContextFlag = "";
9923
9933
  try {
9924
- const ctxDir = path22.join(os10.homedir(), ".exe-os", "session-cache");
9934
+ const ctxDir = path22.join(os11.homedir(), ".exe-os", "session-cache");
9925
9935
  mkdirSync11(ctxDir, { recursive: true });
9926
9936
  const ctxFile = path22.join(ctxDir, `session-context-${sessionName}.md`);
9927
9937
  const ctxContent = [
@@ -10082,13 +10092,13 @@ var init_tmux_routing = __esm({
10082
10092
  init_intercom_queue();
10083
10093
  init_plan_limits();
10084
10094
  init_employees();
10085
- SPAWN_LOCK_DIR = path22.join(os10.homedir(), ".exe-os", "spawn-locks");
10086
- SESSION_CACHE = path22.join(os10.homedir(), ".exe-os", "session-cache");
10095
+ SPAWN_LOCK_DIR = path22.join(os11.homedir(), ".exe-os", "spawn-locks");
10096
+ SESSION_CACHE = path22.join(os11.homedir(), ".exe-os", "session-cache");
10087
10097
  BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
10088
10098
  VALID_SESSION_NAME = /^[a-z]+\d*-[a-zA-Z0-9_]+$/;
10089
10099
  VERIFY_PANE_LINES = 200;
10090
10100
  INTERCOM_DEBOUNCE_MS = 3e4;
10091
- INTERCOM_LOG2 = path22.join(os10.homedir(), ".exe-os", "intercom.log");
10101
+ INTERCOM_LOG2 = path22.join(os11.homedir(), ".exe-os", "intercom.log");
10092
10102
  DEBOUNCE_FILE = path22.join(SESSION_CACHE, "intercom-debounce.json");
10093
10103
  DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
10094
10104
  BUSY_PATTERN = /[✻✽✶✳·].*…|Running…/;
@@ -12317,7 +12327,7 @@ __export(setup_wizard_exports, {
12317
12327
  });
12318
12328
  import crypto11 from "crypto";
12319
12329
  import { existsSync as existsSync23, mkdirSync as mkdirSync15, readFileSync as readFileSync19, writeFileSync as writeFileSync15, unlinkSync as unlinkSync13 } from "fs";
12320
- import os11 from "os";
12330
+ import os12 from "os";
12321
12331
  import path28 from "path";
12322
12332
  import { createInterface as createInterface3 } from "readline";
12323
12333
  function findPackageRoot2() {
@@ -12363,7 +12373,33 @@ function ask2(rl, prompt) {
12363
12373
  doAsk();
12364
12374
  });
12365
12375
  }
12376
+ function getAvailableMemoryGB() {
12377
+ return os12.freemem() / (1024 * 1024 * 1024);
12378
+ }
12379
+ function getTotalMemoryGB() {
12380
+ return os12.totalmem() / (1024 * 1024 * 1024);
12381
+ }
12382
+ function isLowMemory() {
12383
+ return getAvailableMemoryGB() < 2;
12384
+ }
12366
12385
  async function validateModel(log) {
12386
+ const totalGB = getTotalMemoryGB();
12387
+ const freeGB = getAvailableMemoryGB();
12388
+ if (totalGB <= 8 || isLowMemory()) {
12389
+ log(`System memory: ${totalGB.toFixed(0)}GB total, ${freeGB.toFixed(1)}GB free`);
12390
+ log("Skipping in-memory model validation (low memory \u2014 will validate on first use).");
12391
+ const modelPath = path28.join(MODELS_DIR, LOCAL_FILENAME);
12392
+ if (existsSync23(modelPath)) {
12393
+ const { statSync: statSync2 } = await import("fs");
12394
+ const size = statSync2(modelPath).size;
12395
+ if (size > 300 * 1e6) {
12396
+ log(`Model file verified (${(size / 1e6).toFixed(0)} MB).`);
12397
+ return;
12398
+ }
12399
+ throw new Error(`Model file too small (${(size / 1e6).toFixed(0)} MB) \u2014 may be corrupted. Delete and re-run setup.`);
12400
+ }
12401
+ throw new Error("Model file not found after download.");
12402
+ }
12367
12403
  log("Validating model...");
12368
12404
  const { embedDirect: embedDirect2 } = await Promise.resolve().then(() => (init_embedder(), embedder_exports));
12369
12405
  const result = await embedDirect2("test embedding");
@@ -12555,6 +12591,15 @@ async function runSetupWizard(opts = {}) {
12555
12591
  log("");
12556
12592
  if (!state.completedSteps.includes(3)) {
12557
12593
  if (!skipModel) {
12594
+ const freeGB = getAvailableMemoryGB();
12595
+ const totalGB = getTotalMemoryGB();
12596
+ if (freeGB < 2) {
12597
+ log(`\u26A0 Low memory detected: ${freeGB.toFixed(1)}GB free of ${totalGB.toFixed(0)}GB total`);
12598
+ log(" Close other applications (browser, Slack, etc.) before continuing.");
12599
+ log(" The embedding model needs ~500MB to download and load.");
12600
+ log("");
12601
+ await ask2(rl, "Press Enter when ready, or Ctrl+C to abort and free memory first: ");
12602
+ }
12558
12603
  log("Note: jina-embeddings-v5-text-small is licensed CC-BY-NC-4.0 (non-commercial)");
12559
12604
  log("");
12560
12605
  await downloadModel({
@@ -12591,7 +12636,7 @@ async function runSetupWizard(opts = {}) {
12591
12636
  await saveConfig(config);
12592
12637
  log("");
12593
12638
  try {
12594
- const claudeJsonPath = path28.join(os11.homedir(), ".claude.json");
12639
+ const claudeJsonPath = path28.join(os12.homedir(), ".claude.json");
12595
12640
  let claudeJson = {};
12596
12641
  try {
12597
12642
  claudeJson = JSON.parse(readFileSync19(claudeJsonPath, "utf8"));
@@ -12599,7 +12644,7 @@ async function runSetupWizard(opts = {}) {
12599
12644
  }
12600
12645
  if (!claudeJson.projects) claudeJson.projects = {};
12601
12646
  const projects = claudeJson.projects;
12602
- for (const dir of [process.cwd(), os11.homedir()]) {
12647
+ for (const dir of [process.cwd(), os12.homedir()]) {
12603
12648
  if (!projects[dir]) projects[dir] = {};
12604
12649
  projects[dir].hasTrustDialogAccepted = true;
12605
12650
  }
@@ -12874,7 +12919,7 @@ async function runSetupWizard(opts = {}) {
12874
12919
  log(`Session shortcuts generated (${cooName}1, ${cooName}2, ...)`);
12875
12920
  }
12876
12921
  if (wrapResult.pathConfigured) {
12877
- const binDir = path28.join(os11.homedir(), ".exe-os", "bin");
12922
+ const binDir = path28.join(os12.homedir(), ".exe-os", "bin");
12878
12923
  process.env.PATH = `${binDir}:${process.env.PATH ?? ""}`;
12879
12924
  pathJustConfigured = true;
12880
12925
  }
@@ -12951,7 +12996,7 @@ var init_setup_wizard = __esm({
12951
12996
  init_config();
12952
12997
  init_keychain();
12953
12998
  init_model_downloader();
12954
- SETUP_STATE_PATH = path28.join(os11.homedir(), ".exe-os", "setup-state.json");
12999
+ SETUP_STATE_PATH = path28.join(os12.homedir(), ".exe-os", "setup-state.json");
12955
13000
  }
12956
13001
  });
12957
13002
 
@@ -21929,7 +21974,7 @@ var init_hooks = __esm({
21929
21974
 
21930
21975
  // src/runtime/safety-checks.ts
21931
21976
  import path30 from "path";
21932
- import os12 from "os";
21977
+ import os13 from "os";
21933
21978
  function checkPathSafety(filePath) {
21934
21979
  const resolved = path30.resolve(filePath);
21935
21980
  for (const { pattern, reason } of BYPASS_IMMUNE_PATTERNS) {
@@ -21956,7 +22001,7 @@ var HOME, BYPASS_IMMUNE_PATTERNS;
21956
22001
  var init_safety_checks = __esm({
21957
22002
  "src/runtime/safety-checks.ts"() {
21958
22003
  "use strict";
21959
- HOME = os12.homedir();
22004
+ HOME = os13.homedir();
21960
22005
  BYPASS_IMMUNE_PATTERNS = [
21961
22006
  {
21962
22007
  pattern: /\/\.git\/hooks\//,
@@ -27122,7 +27167,7 @@ Unhandled rejection: ${reason}
27122
27167
  // src/bin/cli.ts
27123
27168
  import { existsSync as existsSync25, readFileSync as readFileSync22, writeFileSync as writeFileSync16, readdirSync as readdirSync8, rmSync } from "fs";
27124
27169
  import path38 from "path";
27125
- import os13 from "os";
27170
+ import os14 from "os";
27126
27171
  var args = process.argv.slice(2);
27127
27172
  if (args.includes("--version") || args.includes("-v")) {
27128
27173
  try {
@@ -27265,7 +27310,7 @@ ID: ${result.id}`);
27265
27310
  });
27266
27311
  await init_App2().then(() => App_exports);
27267
27312
  } else {
27268
- const claudeDir = path38.join(os13.homedir(), ".claude");
27313
+ const claudeDir = path38.join(os14.homedir(), ".claude");
27269
27314
  const settingsPath = path38.join(claudeDir, "settings.json");
27270
27315
  const hasClaudeCode = existsSync25(settingsPath) && (() => {
27271
27316
  try {
@@ -27278,7 +27323,7 @@ ID: ${result.id}`);
27278
27323
  if (hasClaudeCode) {
27279
27324
  let cooName = "exe";
27280
27325
  try {
27281
- const rosterPath = path38.join(os13.homedir(), ".exe-os", "exe-employees.json");
27326
+ const rosterPath = path38.join(os14.homedir(), ".exe-os", "exe-employees.json");
27282
27327
  if (existsSync25(rosterPath)) {
27283
27328
  const roster = JSON.parse(readFileSync22(rosterPath, "utf8"));
27284
27329
  const coo = roster.find((e) => e.role === "COO");
@@ -27320,9 +27365,9 @@ async function runClaudeInstall() {
27320
27365
  }
27321
27366
  }
27322
27367
  async function runClaudeCheck() {
27323
- const claudeDir = path38.join(os13.homedir(), ".claude");
27368
+ const claudeDir = path38.join(os14.homedir(), ".claude");
27324
27369
  const settingsPath = path38.join(claudeDir, "settings.json");
27325
- const claudeJsonPath = path38.join(os13.homedir(), ".claude.json");
27370
+ const claudeJsonPath = path38.join(os14.homedir(), ".claude.json");
27326
27371
  let ok = true;
27327
27372
  if (existsSync25(settingsPath)) {
27328
27373
  let settings;
@@ -27392,7 +27437,7 @@ async function runClaudeCheck() {
27392
27437
  async function runClaudeUninstall(flags = []) {
27393
27438
  const dryRun = flags.includes("--dry-run");
27394
27439
  const purge = flags.includes("--purge");
27395
- const homeDir = os13.homedir();
27440
+ const homeDir = os14.homedir();
27396
27441
  const claudeDir = path38.join(homeDir, ".claude");
27397
27442
  const settingsPath = path38.join(claudeDir, "settings.json");
27398
27443
  const claudeJsonPath = path38.join(homeDir, ".claude.json");
@@ -245,6 +245,7 @@ var init_employees = __esm({
245
245
 
246
246
  // src/lib/exe-daemon-client.ts
247
247
  import net from "net";
248
+ import os3 from "os";
248
249
  import { spawn } from "child_process";
249
250
  import { randomUUID as randomUUID2 } from "crypto";
250
251
  import { existsSync as existsSync3, unlinkSync as unlinkSync2, readFileSync as readFileSync3, openSync, closeSync, statSync } from "fs";
@@ -308,6 +309,15 @@ function findPackageRoot() {
308
309
  return null;
309
310
  }
310
311
  function spawnDaemon() {
312
+ const freeGB = os3.freemem() / (1024 * 1024 * 1024);
313
+ const totalGB = os3.totalmem() / (1024 * 1024 * 1024);
314
+ if (freeGB < 1.5 && totalGB <= 8) {
315
+ process.stderr.write(
316
+ `[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.
317
+ `
318
+ );
319
+ return;
320
+ }
311
321
  const pkgRoot = findPackageRoot();
312
322
  if (!pkgRoot) {
313
323
  process.stderr.write("[exed-client] WARN: cannot find package root\n");
@@ -2171,11 +2181,11 @@ init_database();
2171
2181
  import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
2172
2182
  import { existsSync as existsSync4 } from "fs";
2173
2183
  import path4 from "path";
2174
- import os3 from "os";
2184
+ import os4 from "os";
2175
2185
  var SERVICE = "exe-mem";
2176
2186
  var ACCOUNT = "master-key";
2177
2187
  function getKeyDir() {
2178
- return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path4.join(os3.homedir(), ".exe-os");
2188
+ return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path4.join(os4.homedir(), ".exe-os");
2179
2189
  }
2180
2190
  function getKeyPath() {
2181
2191
  return path4.join(getKeyDir(), "master.key");
@@ -2201,7 +2211,7 @@ async function getMasterKey() {
2201
2211
  const keyPath = getKeyPath();
2202
2212
  if (!existsSync4(keyPath)) {
2203
2213
  process.stderr.write(
2204
- `[keychain] Key not found at ${keyPath} (HOME=${os3.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
2214
+ `[keychain] Key not found at ${keyPath} (HOME=${os4.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
2205
2215
  `
2206
2216
  );
2207
2217
  return null;
@@ -429,6 +429,7 @@ var init_db_retry = __esm({
429
429
 
430
430
  // src/lib/exe-daemon-client.ts
431
431
  import net from "net";
432
+ import os3 from "os";
432
433
  import { spawn } from "child_process";
433
434
  import { randomUUID } from "crypto";
434
435
  import { existsSync as existsSync3, unlinkSync as unlinkSync2, readFileSync as readFileSync3, openSync, closeSync, statSync } from "fs";
@@ -492,6 +493,15 @@ function findPackageRoot() {
492
493
  return null;
493
494
  }
494
495
  function spawnDaemon() {
496
+ const freeGB = os3.freemem() / (1024 * 1024 * 1024);
497
+ const totalGB = os3.totalmem() / (1024 * 1024 * 1024);
498
+ if (freeGB < 1.5 && totalGB <= 8) {
499
+ process.stderr.write(
500
+ `[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.
501
+ `
502
+ );
503
+ return;
504
+ }
495
505
  const pkgRoot = findPackageRoot();
496
506
  if (!pkgRoot) {
497
507
  process.stderr.write("[exed-client] WARN: cannot find package root\n");
@@ -2077,9 +2087,9 @@ __export(keychain_exports, {
2077
2087
  import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
2078
2088
  import { existsSync as existsSync4 } from "fs";
2079
2089
  import path4 from "path";
2080
- import os3 from "os";
2090
+ import os4 from "os";
2081
2091
  function getKeyDir() {
2082
- return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path4.join(os3.homedir(), ".exe-os");
2092
+ return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path4.join(os4.homedir(), ".exe-os");
2083
2093
  }
2084
2094
  function getKeyPath() {
2085
2095
  return path4.join(getKeyDir(), "master.key");
@@ -2105,7 +2115,7 @@ async function getMasterKey() {
2105
2115
  const keyPath = getKeyPath();
2106
2116
  if (!existsSync4(keyPath)) {
2107
2117
  process.stderr.write(
2108
- `[keychain] Key not found at ${keyPath} (HOME=${os3.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
2118
+ `[keychain] Key not found at ${keyPath} (HOME=${os4.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
2109
2119
  `
2110
2120
  );
2111
2121
  return null;
@@ -2588,7 +2598,7 @@ __export(session_registry_exports, {
2588
2598
  import { readFileSync as readFileSync4, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2, existsSync as existsSync6 } from "fs";
2589
2599
  import { execSync as execSync2 } from "child_process";
2590
2600
  import path6 from "path";
2591
- import os4 from "os";
2601
+ import os5 from "os";
2592
2602
  function registerSession(entry) {
2593
2603
  const dir = path6.dirname(REGISTRY_PATH);
2594
2604
  if (!existsSync6(dir)) {
@@ -2634,7 +2644,7 @@ var REGISTRY_PATH;
2634
2644
  var init_session_registry = __esm({
2635
2645
  "src/lib/session-registry.ts"() {
2636
2646
  "use strict";
2637
- REGISTRY_PATH = path6.join(os4.homedir(), ".exe-os", "session-registry.json");
2647
+ REGISTRY_PATH = path6.join(os5.homedir(), ".exe-os", "session-registry.json");
2638
2648
  }
2639
2649
  });
2640
2650
 
@@ -2907,7 +2917,7 @@ var init_agent_config = __esm({
2907
2917
  // src/lib/intercom-queue.ts
2908
2918
  import { readFileSync as readFileSync6, writeFileSync as writeFileSync4, renameSync as renameSync3, existsSync as existsSync8, mkdirSync as mkdirSync4 } from "fs";
2909
2919
  import path8 from "path";
2910
- import os5 from "os";
2920
+ import os6 from "os";
2911
2921
  function ensureDir() {
2912
2922
  const dir = path8.dirname(QUEUE_PATH);
2913
2923
  if (!existsSync8(dir)) mkdirSync4(dir, { recursive: true });
@@ -2947,9 +2957,9 @@ var QUEUE_PATH, TTL_MS, INTERCOM_LOG;
2947
2957
  var init_intercom_queue = __esm({
2948
2958
  "src/lib/intercom-queue.ts"() {
2949
2959
  "use strict";
2950
- QUEUE_PATH = path8.join(os5.homedir(), ".exe-os", "intercom-queue.json");
2960
+ QUEUE_PATH = path8.join(os6.homedir(), ".exe-os", "intercom-queue.json");
2951
2961
  TTL_MS = 60 * 60 * 1e3;
2952
- INTERCOM_LOG = path8.join(os5.homedir(), ".exe-os", "intercom.log");
2962
+ INTERCOM_LOG = path8.join(os6.homedir(), ".exe-os", "intercom.log");
2953
2963
  }
2954
2964
  });
2955
2965
 
@@ -3421,7 +3431,7 @@ var init_plan_limits = __esm({
3421
3431
  // src/lib/notifications.ts
3422
3432
  import crypto from "crypto";
3423
3433
  import path11 from "path";
3424
- import os6 from "os";
3434
+ import os7 from "os";
3425
3435
  import {
3426
3436
  readFileSync as readFileSync9,
3427
3437
  readdirSync as readdirSync2,
@@ -3539,7 +3549,7 @@ async function markDoneTaskNotificationsAsRead() {
3539
3549
  }
3540
3550
  }
3541
3551
  async function migrateJsonNotifications() {
3542
- const base = process.env.EXE_OS_DIR || process.env.EXE_MEM_DIR || path11.join(os6.homedir(), ".exe-os");
3552
+ const base = process.env.EXE_OS_DIR || process.env.EXE_MEM_DIR || path11.join(os7.homedir(), ".exe-os");
3543
3553
  const notifDir = path11.join(base, "notifications");
3544
3554
  if (!existsSync11(notifDir)) return 0;
3545
3555
  let migrated = 0;
@@ -3698,7 +3708,7 @@ var init_session_kill_telemetry = __esm({
3698
3708
  // src/lib/tasks-crud.ts
3699
3709
  import crypto3 from "crypto";
3700
3710
  import path12 from "path";
3701
- import os7 from "os";
3711
+ import os8 from "os";
3702
3712
  import { execSync as execSync5 } from "child_process";
3703
3713
  import { mkdir as mkdir4, writeFile as writeFile4, appendFile } from "fs/promises";
3704
3714
  import { existsSync as existsSync12, readFileSync as readFileSync10 } from "fs";
@@ -3913,7 +3923,7 @@ ${laneWarning}` : laneWarning;
3913
3923
  });
3914
3924
  if (input.baseDir) {
3915
3925
  try {
3916
- const EXE_OS_DIR = path12.join(os7.homedir(), ".exe-os");
3926
+ const EXE_OS_DIR = path12.join(os8.homedir(), ".exe-os");
3917
3927
  const mdPath = path12.join(EXE_OS_DIR, taskFile);
3918
3928
  const mdDir = path12.dirname(mdPath);
3919
3929
  if (!existsSync12(mdDir)) await mkdir4(mdDir, { recursive: true });
@@ -5568,7 +5578,7 @@ __export(tmux_routing_exports, {
5568
5578
  import { execFileSync as execFileSync2, execSync as execSync7 } from "child_process";
5569
5579
  import { readFileSync as readFileSync11, writeFileSync as writeFileSync7, mkdirSync as mkdirSync7, existsSync as existsSync14, appendFileSync } from "fs";
5570
5580
  import path17 from "path";
5571
- import os8 from "os";
5581
+ import os9 from "os";
5572
5582
  import { fileURLToPath as fileURLToPath2 } from "url";
5573
5583
  import { unlinkSync as unlinkSync6 } from "fs";
5574
5584
  function spawnLockPath(sessionName) {
@@ -5982,7 +5992,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
5982
5992
  const transport = getTransport();
5983
5993
  const sessionName = employeeSessionName(employeeName, exeSession, opts?.instance);
5984
5994
  const instanceLabel = opts?.instance != null && opts.instance > 0 ? `${employeeName}${opts.instance}` : employeeName;
5985
- const logDir = path17.join(os8.homedir(), ".exe-os", "session-logs");
5995
+ const logDir = path17.join(os9.homedir(), ".exe-os", "session-logs");
5986
5996
  const logFile = path17.join(logDir, `${instanceLabel}-${Date.now()}.log`);
5987
5997
  if (!existsSync14(logDir)) {
5988
5998
  mkdirSync7(logDir, { recursive: true });
@@ -5998,7 +6008,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
5998
6008
  } catch {
5999
6009
  }
6000
6010
  try {
6001
- const claudeJsonPath = path17.join(os8.homedir(), ".claude.json");
6011
+ const claudeJsonPath = path17.join(os9.homedir(), ".claude.json");
6002
6012
  let claudeJson = {};
6003
6013
  try {
6004
6014
  claudeJson = JSON.parse(readFileSync11(claudeJsonPath, "utf8"));
@@ -6013,7 +6023,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
6013
6023
  } catch {
6014
6024
  }
6015
6025
  try {
6016
- const settingsDir = path17.join(os8.homedir(), ".claude", "projects");
6026
+ const settingsDir = path17.join(os9.homedir(), ".claude", "projects");
6017
6027
  const normalizedKey = (opts?.cwd ?? projectDir).replace(/\//g, "-").replace(/^-/, "");
6018
6028
  const projSettingsDir = path17.join(settingsDir, normalizedKey);
6019
6029
  const settingsPath = path17.join(projSettingsDir, "settings.json");
@@ -6064,7 +6074,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
6064
6074
  let legacyFallbackWarned = false;
6065
6075
  if (!useExeAgent && !useBinSymlink) {
6066
6076
  const identityPath = path17.join(
6067
- os8.homedir(),
6077
+ os9.homedir(),
6068
6078
  ".exe-os",
6069
6079
  "identity",
6070
6080
  `${employeeName}.md`
@@ -6094,7 +6104,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
6094
6104
  }
6095
6105
  let sessionContextFlag = "";
6096
6106
  try {
6097
- const ctxDir = path17.join(os8.homedir(), ".exe-os", "session-cache");
6107
+ const ctxDir = path17.join(os9.homedir(), ".exe-os", "session-cache");
6098
6108
  mkdirSync7(ctxDir, { recursive: true });
6099
6109
  const ctxFile = path17.join(ctxDir, `session-context-${sessionName}.md`);
6100
6110
  const ctxContent = [
@@ -6255,13 +6265,13 @@ var init_tmux_routing = __esm({
6255
6265
  init_intercom_queue();
6256
6266
  init_plan_limits();
6257
6267
  init_employees();
6258
- SPAWN_LOCK_DIR = path17.join(os8.homedir(), ".exe-os", "spawn-locks");
6259
- SESSION_CACHE = path17.join(os8.homedir(), ".exe-os", "session-cache");
6268
+ SPAWN_LOCK_DIR = path17.join(os9.homedir(), ".exe-os", "spawn-locks");
6269
+ SESSION_CACHE = path17.join(os9.homedir(), ".exe-os", "session-cache");
6260
6270
  BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
6261
6271
  VALID_SESSION_NAME = /^[a-z]+\d*-[a-zA-Z0-9_]+$/;
6262
6272
  VERIFY_PANE_LINES = 200;
6263
6273
  INTERCOM_DEBOUNCE_MS = 3e4;
6264
- INTERCOM_LOG2 = path17.join(os8.homedir(), ".exe-os", "intercom.log");
6274
+ INTERCOM_LOG2 = path17.join(os9.homedir(), ".exe-os", "intercom.log");
6265
6275
  DEBOUNCE_FILE = path17.join(SESSION_CACHE, "intercom-debounce.json");
6266
6276
  DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
6267
6277
  BUSY_PATTERN = /[✻✽✶✳·].*…|Running…/;
@@ -8008,7 +8018,7 @@ init_employees();
8008
8018
  import path22 from "path";
8009
8019
  import { mkdir as mkdir5, writeFile as writeFile6 } from "fs/promises";
8010
8020
  import { existsSync as existsSync18, readFileSync as readFileSync15, readdirSync as readdirSync7, unlinkSync as unlinkSync11 } from "fs";
8011
- import os9 from "os";
8021
+ import os10 from "os";
8012
8022
 
8013
8023
  // src/lib/employee-templates.ts
8014
8024
  init_global_procedures();
@@ -9228,7 +9238,7 @@ async function boot(options) {
9228
9238
  ]);
9229
9239
  try {
9230
9240
  const configPath = path22.join(
9231
- process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path22.join(os9.homedir(), ".exe-os"),
9241
+ process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path22.join(os10.homedir(), ".exe-os"),
9232
9242
  "config.json"
9233
9243
  );
9234
9244
  if (existsSync18(configPath)) {
@@ -9427,7 +9437,7 @@ ${brief}`;
9427
9437
  console.log(brief);
9428
9438
  try {
9429
9439
  const configPath2 = path22.join(
9430
- process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path22.join(os9.homedir(), ".exe-os"),
9440
+ process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path22.join(os10.homedir(), ".exe-os"),
9431
9441
  "config.json"
9432
9442
  );
9433
9443
  if (existsSync18(configPath2)) {