@askexenow/exe-os 0.9.85 → 0.9.86

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 (80) hide show
  1. package/dist/bin/agentic-ontology-backfill.js +32 -14
  2. package/dist/bin/agentic-reflection-backfill.js +32 -14
  3. package/dist/bin/agentic-semantic-label.js +32 -14
  4. package/dist/bin/backfill-conversations.js +32 -14
  5. package/dist/bin/backfill-responses.js +32 -14
  6. package/dist/bin/backfill-vectors.js +32 -14
  7. package/dist/bin/bulk-sync-postgres.js +32 -14
  8. package/dist/bin/cleanup-stale-review-tasks.js +35 -17
  9. package/dist/bin/cli.js +152 -77
  10. package/dist/bin/exe-assign.js +32 -14
  11. package/dist/bin/exe-boot.js +57 -39
  12. package/dist/bin/exe-cloud.js +22 -4
  13. package/dist/bin/exe-dispatch.js +43 -25
  14. package/dist/bin/exe-doctor.js +22 -4
  15. package/dist/bin/exe-export-behaviors.js +32 -14
  16. package/dist/bin/exe-forget.js +32 -14
  17. package/dist/bin/exe-gateway.js +47 -29
  18. package/dist/bin/exe-heartbeat.js +37 -19
  19. package/dist/bin/exe-kill.js +36 -18
  20. package/dist/bin/exe-launch-agent.js +40 -22
  21. package/dist/bin/exe-pending-messages.js +35 -17
  22. package/dist/bin/exe-pending-notifications.js +35 -17
  23. package/dist/bin/exe-pending-reviews.js +37 -19
  24. package/dist/bin/exe-rename.js +34 -16
  25. package/dist/bin/exe-review.js +32 -14
  26. package/dist/bin/exe-search.js +40 -22
  27. package/dist/bin/exe-session-cleanup.js +67 -44
  28. package/dist/bin/exe-start-codex.js +39 -21
  29. package/dist/bin/exe-start-opencode.js +37 -19
  30. package/dist/bin/exe-status.js +44 -26
  31. package/dist/bin/exe-team.js +32 -14
  32. package/dist/bin/git-sweep.js +45 -27
  33. package/dist/bin/graph-backfill.js +32 -14
  34. package/dist/bin/graph-export.js +32 -14
  35. package/dist/bin/intercom-check.js +49 -31
  36. package/dist/bin/scan-tasks.js +45 -27
  37. package/dist/bin/setup.js +29 -11
  38. package/dist/bin/shard-migrate.js +32 -14
  39. package/dist/bin/stack-update.js +59 -2
  40. package/dist/bin/update.js +1 -1
  41. package/dist/gateway/index.js +47 -29
  42. package/dist/hooks/bug-report-worker.js +47 -29
  43. package/dist/hooks/codex-stop-task-finalizer.js +41 -23
  44. package/dist/hooks/commit-complete.js +46 -28
  45. package/dist/hooks/error-recall.js +44 -26
  46. package/dist/hooks/ingest-worker.js +4 -4
  47. package/dist/hooks/ingest.js +38 -20
  48. package/dist/hooks/instructions-loaded.js +32 -14
  49. package/dist/hooks/notification.js +32 -14
  50. package/dist/hooks/post-compact.js +32 -14
  51. package/dist/hooks/post-tool-combined.js +45 -27
  52. package/dist/hooks/pre-compact.js +43 -25
  53. package/dist/hooks/pre-tool-use.js +40 -22
  54. package/dist/hooks/prompt-submit.js +60 -42
  55. package/dist/hooks/session-end.js +48 -30
  56. package/dist/hooks/session-start.js +50 -32
  57. package/dist/hooks/stop.js +35 -17
  58. package/dist/hooks/subagent-stop.js +32 -14
  59. package/dist/hooks/summary-worker.js +37 -19
  60. package/dist/index.js +43 -25
  61. package/dist/lib/cloud-sync.js +32 -14
  62. package/dist/lib/database.js +22 -4
  63. package/dist/lib/db-daemon-client.js +16 -4
  64. package/dist/lib/db.js +22 -4
  65. package/dist/lib/device-registry.js +22 -4
  66. package/dist/lib/embedder.js +16 -4
  67. package/dist/lib/exe-daemon-client.js +16 -4
  68. package/dist/lib/exe-daemon.js +165 -66
  69. package/dist/lib/hybrid-search.js +40 -22
  70. package/dist/lib/schedules.js +35 -17
  71. package/dist/lib/skill-learning.js +16 -4
  72. package/dist/lib/store.js +32 -14
  73. package/dist/lib/tasks.js +16 -4
  74. package/dist/lib/tmux-routing.js +18 -6
  75. package/dist/mcp/server.js +142 -60
  76. package/dist/mcp/tools/create-task.js +18 -6
  77. package/dist/mcp/tools/update-task.js +18 -6
  78. package/dist/runtime/index.js +43 -25
  79. package/dist/tui/App.js +73 -55
  80. package/package.json +1 -1
package/dist/bin/cli.js CHANGED
@@ -3665,7 +3665,7 @@ __export(exe_daemon_client_exports, {
3665
3665
  });
3666
3666
  import net from "net";
3667
3667
  import os10 from "os";
3668
- import { spawn } from "child_process";
3668
+ import { spawn, execSync as execSync4 } from "child_process";
3669
3669
  import { randomUUID } from "crypto";
3670
3670
  import { existsSync as existsSync12, unlinkSync as unlinkSync3, readFileSync as readFileSync9, openSync, closeSync, statSync as statSync2 } from "fs";
3671
3671
  import path12 from "path";
@@ -3695,6 +3695,14 @@ function handleData(chunk) {
3695
3695
  }
3696
3696
  }
3697
3697
  }
3698
+ function isZombie(pid) {
3699
+ try {
3700
+ const state = execSync4(`ps -p ${pid} -o state=`, { encoding: "utf8", timeout: 2e3 }).trim();
3701
+ return state.startsWith("Z");
3702
+ } catch {
3703
+ return false;
3704
+ }
3705
+ }
3698
3706
  function cleanupStaleFiles() {
3699
3707
  if (existsSync12(PID_PATH)) {
3700
3708
  try {
@@ -3702,7 +3710,11 @@ function cleanupStaleFiles() {
3702
3710
  if (pid > 0) {
3703
3711
  try {
3704
3712
  process.kill(pid, 0);
3705
- return;
3713
+ if (!isZombie(pid)) {
3714
+ return;
3715
+ }
3716
+ process.stderr.write(`[exed-client] PID ${pid} is a zombie \u2014 cleaning up stale files
3717
+ `);
3706
3718
  } catch {
3707
3719
  }
3708
3720
  }
@@ -3730,8 +3742,8 @@ function findPackageRoot() {
3730
3742
  function getAvailableMemoryGB() {
3731
3743
  if (process.platform === "darwin") {
3732
3744
  try {
3733
- const { execSync: execSync18 } = __require("child_process");
3734
- const vmstat = execSync18("vm_stat", { encoding: "utf8" });
3745
+ const { execSync: execSync19 } = __require("child_process");
3746
+ const vmstat = execSync19("vm_stat", { encoding: "utf8" });
3735
3747
  const pageSize = 16384;
3736
3748
  const pageSizeMatch = vmstat.match(/page size of (\d+) bytes/);
3737
3749
  const actualPageSize = pageSizeMatch ? parseInt(pageSizeMatch[1], 10) : pageSize;
@@ -5686,6 +5698,12 @@ async function disposeDatabase() {
5686
5698
  clearInterval(_walCheckpointTimer);
5687
5699
  _walCheckpointTimer = null;
5688
5700
  }
5701
+ if (_client) {
5702
+ try {
5703
+ await _client.execute("PRAGMA wal_checkpoint(PASSIVE)");
5704
+ } catch {
5705
+ }
5706
+ }
5689
5707
  if (_daemonClient) {
5690
5708
  _daemonClient.close();
5691
5709
  _daemonClient = null;
@@ -10436,7 +10454,7 @@ import { createInterface as createInterface2 } from "readline";
10436
10454
  import { existsSync as existsSync19, statSync as statSync6, mkdirSync as mkdirSync12, copyFileSync as copyFileSync3, renameSync as renameSync4, rmSync, writeFileSync as writeFileSync12 } from "fs";
10437
10455
  import path19 from "path";
10438
10456
  import os12 from "os";
10439
- import { execSync as execSync4 } from "child_process";
10457
+ import { execSync as execSync5 } from "child_process";
10440
10458
  import { createClient as createClient3 } from "@libsql/client";
10441
10459
  function isInteractiveTerminal2() {
10442
10460
  return Boolean(process.stdin.isTTY && process.stdout.isTTY && !process.env.CI);
@@ -10467,7 +10485,7 @@ function dbSidecarPaths(dbPath) {
10467
10485
  function daemonStatus() {
10468
10486
  const pidPath = path19.join(dataDir(), "exed.pid");
10469
10487
  if (!existsSync19(pidPath)) return { pid: null, alive: false };
10470
- const pid = execSync4(`cat ${JSON.stringify(pidPath)}`, { encoding: "utf8" }).trim();
10488
+ const pid = execSync5(`cat ${JSON.stringify(pidPath)}`, { encoding: "utf8" }).trim();
10471
10489
  if (!pid) return { pid: null, alive: false };
10472
10490
  try {
10473
10491
  process.kill(Number(pid), 0);
@@ -10481,7 +10499,7 @@ async function stopDaemonIfAlive() {
10481
10499
  if (!daemon.alive || !daemon.pid) return;
10482
10500
  if (Number(daemon.pid) <= 1) {
10483
10501
  try {
10484
- execSync4("docker inspect exed >/dev/null 2>&1 && docker stop exed >/dev/null", { timeout: 3e4 });
10502
+ execSync5("docker inspect exed >/dev/null 2>&1 && docker stop exed >/dev/null", { timeout: 3e4 });
10485
10503
  return;
10486
10504
  } catch {
10487
10505
  throw new Error("Refusing to signal PID 1. Stop the exed Docker container manually, then retry.");
@@ -12950,7 +12968,7 @@ __export(session_registry_exports, {
12950
12968
  registerSession: () => registerSession
12951
12969
  });
12952
12970
  import { readFileSync as readFileSync18, writeFileSync as writeFileSync17, mkdirSync as mkdirSync17, existsSync as existsSync22 } from "fs";
12953
- import { execSync as execSync5 } from "child_process";
12971
+ import { execSync as execSync6 } from "child_process";
12954
12972
  import path25 from "path";
12955
12973
  import os14 from "os";
12956
12974
  function registerSession(entry) {
@@ -12990,7 +13008,7 @@ function pruneStaleSessions() {
12990
13008
  if (sessions.length === 0) return 0;
12991
13009
  let liveSessions = [];
12992
13010
  try {
12993
- liveSessions = execSync5("tmux list-sessions -F '#{session_name}' 2>/dev/null", {
13011
+ liveSessions = execSync6("tmux list-sessions -F '#{session_name}' 2>/dev/null", {
12994
13012
  encoding: "utf8"
12995
13013
  }).trim().split("\n").filter(Boolean);
12996
13014
  } catch {
@@ -13013,7 +13031,7 @@ var init_session_registry = __esm({
13013
13031
  });
13014
13032
 
13015
13033
  // src/lib/session-key.ts
13016
- import { execSync as execSync6 } from "child_process";
13034
+ import { execSync as execSync7 } from "child_process";
13017
13035
  function normalizeCommand(command) {
13018
13036
  const trimmed = command.trim().toLowerCase();
13019
13037
  const parts = trimmed.split(/[\\/]/);
@@ -13032,7 +13050,7 @@ function resolveRuntimeProcess() {
13032
13050
  let pid = process.ppid;
13033
13051
  for (let i = 0; i < 10; i++) {
13034
13052
  try {
13035
- const info = execSync6(`ps -p ${pid} -o ppid=,comm=`, {
13053
+ const info = execSync7(`ps -p ${pid} -o ppid=,comm=`, {
13036
13054
  encoding: "utf8",
13037
13055
  timeout: 2e3
13038
13056
  }).trim();
@@ -13206,14 +13224,14 @@ var init_transport = __esm({
13206
13224
  });
13207
13225
 
13208
13226
  // src/lib/cc-agent-support.ts
13209
- import { execSync as execSync7 } from "child_process";
13227
+ import { execSync as execSync8 } from "child_process";
13210
13228
  function _resetCcAgentSupportCache() {
13211
13229
  _cachedSupport = null;
13212
13230
  }
13213
13231
  function claudeSupportsAgentFlag() {
13214
13232
  if (_cachedSupport !== null) return _cachedSupport;
13215
13233
  try {
13216
- const helpOutput = execSync7("claude --help 2>&1", {
13234
+ const helpOutput = execSync8("claude --help 2>&1", {
13217
13235
  encoding: "utf-8",
13218
13236
  timeout: 5e3
13219
13237
  });
@@ -13590,7 +13608,7 @@ var init_session_kill_telemetry = __esm({
13590
13608
  });
13591
13609
 
13592
13610
  // src/lib/project-name.ts
13593
- import { execSync as execSync8 } from "child_process";
13611
+ import { execSync as execSync9 } from "child_process";
13594
13612
  import path29 from "path";
13595
13613
  function getProjectName(cwd2) {
13596
13614
  const dir = cwd2 ?? process.cwd();
@@ -13598,7 +13616,7 @@ function getProjectName(cwd2) {
13598
13616
  try {
13599
13617
  let repoRoot;
13600
13618
  try {
13601
- const gitCommonDir = execSync8("git rev-parse --path-format=absolute --git-common-dir", {
13619
+ const gitCommonDir = execSync9("git rev-parse --path-format=absolute --git-common-dir", {
13602
13620
  cwd: dir,
13603
13621
  encoding: "utf8",
13604
13622
  timeout: 2e3,
@@ -13606,7 +13624,7 @@ function getProjectName(cwd2) {
13606
13624
  }).trim();
13607
13625
  repoRoot = path29.dirname(gitCommonDir);
13608
13626
  } catch {
13609
- repoRoot = execSync8("git rev-parse --show-toplevel", {
13627
+ repoRoot = execSync9("git rev-parse --show-toplevel", {
13610
13628
  cwd: dir,
13611
13629
  encoding: "utf8",
13612
13630
  timeout: 2e3,
@@ -13713,7 +13731,7 @@ __export(tasks_crud_exports, {
13713
13731
  import crypto9 from "crypto";
13714
13732
  import path30 from "path";
13715
13733
  import os17 from "os";
13716
- import { execSync as execSync9 } from "child_process";
13734
+ import { execSync as execSync10 } from "child_process";
13717
13735
  import { mkdir as mkdir5, writeFile as writeFile5, appendFile } from "fs/promises";
13718
13736
  import { existsSync as existsSync26, readFileSync as readFileSync22 } from "fs";
13719
13737
  async function writeCheckpoint(input) {
@@ -14058,14 +14076,14 @@ function isTmuxSessionAlive(identifier) {
14058
14076
  if (!identifier || identifier === "unknown") return true;
14059
14077
  try {
14060
14078
  if (identifier.startsWith("%")) {
14061
- const output2 = execSync9("tmux list-panes -a -F '#{pane_id}'", {
14079
+ const output2 = execSync10("tmux list-panes -a -F '#{pane_id}'", {
14062
14080
  timeout: 2e3,
14063
14081
  encoding: "utf8",
14064
14082
  stdio: ["pipe", "pipe", "pipe"]
14065
14083
  });
14066
14084
  return output2.split("\n").some((l) => l.trim() === identifier);
14067
14085
  } else {
14068
- execSync9(`tmux has-session -t ${JSON.stringify(identifier)}`, {
14086
+ execSync10(`tmux has-session -t ${JSON.stringify(identifier)}`, {
14069
14087
  timeout: 2e3,
14070
14088
  stdio: ["pipe", "pipe", "pipe"]
14071
14089
  });
@@ -14074,7 +14092,7 @@ function isTmuxSessionAlive(identifier) {
14074
14092
  } catch {
14075
14093
  if (identifier.startsWith("%")) return true;
14076
14094
  try {
14077
- execSync9("tmux list-sessions", {
14095
+ execSync10("tmux list-sessions", {
14078
14096
  timeout: 2e3,
14079
14097
  stdio: ["pipe", "pipe", "pipe"]
14080
14098
  });
@@ -14089,12 +14107,12 @@ function checkStaleCompletion(taskContext, taskCreatedAt) {
14089
14107
  if (!DELEGATION_KEYWORDS.test(taskContext)) return null;
14090
14108
  try {
14091
14109
  const since = new Date(taskCreatedAt).toISOString();
14092
- const branch = execSync9(
14110
+ const branch = execSync10(
14093
14111
  "git rev-parse --abbrev-ref HEAD 2>/dev/null",
14094
14112
  { encoding: "utf8", timeout: 3e3 }
14095
14113
  ).trim();
14096
14114
  const branchArg = branch && branch !== "HEAD" ? branch : "";
14097
- const commitCount = execSync9(
14115
+ const commitCount = execSync10(
14098
14116
  `git log --oneline --since="${since}" ${branchArg} 2>/dev/null | wc -l`,
14099
14117
  { encoding: "utf8", timeout: 5e3 }
14100
14118
  ).trim();
@@ -15693,7 +15711,7 @@ __export(tmux_routing_exports, {
15693
15711
  spawnEmployee: () => spawnEmployee,
15694
15712
  verifyPaneAtCapacity: () => verifyPaneAtCapacity
15695
15713
  });
15696
- import { execFileSync as execFileSync3, execSync as execSync10 } from "child_process";
15714
+ import { execFileSync as execFileSync3, execSync as execSync11 } from "child_process";
15697
15715
  import { readFileSync as readFileSync23, writeFileSync as writeFileSync20, mkdirSync as mkdirSync20, existsSync as existsSync28, appendFileSync as appendFileSync2, readdirSync as readdirSync7 } from "fs";
15698
15716
  import path34 from "path";
15699
15717
  import os18 from "os";
@@ -16414,7 +16432,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
16414
16432
  let booted = false;
16415
16433
  for (let i = 0; i < 30; i++) {
16416
16434
  try {
16417
- execSync10("sleep 0.5");
16435
+ execSync11("sleep 0.5");
16418
16436
  } catch {
16419
16437
  }
16420
16438
  try {
@@ -16787,7 +16805,7 @@ __export(active_agent_exports, {
16787
16805
  writeActiveAgent: () => writeActiveAgent
16788
16806
  });
16789
16807
  import { readFileSync as readFileSync24, writeFileSync as writeFileSync21, mkdirSync as mkdirSync21, unlinkSync as unlinkSync12, readdirSync as readdirSync8 } from "fs";
16790
- import { execSync as execSync11 } from "child_process";
16808
+ import { execSync as execSync12 } from "child_process";
16791
16809
  import path35 from "path";
16792
16810
  function isNameWithOptionalInstance(candidate, baseName) {
16793
16811
  if (candidate === baseName) return true;
@@ -16881,7 +16899,7 @@ function getActiveAgent() {
16881
16899
  } catch {
16882
16900
  }
16883
16901
  try {
16884
- const sessionName = execSync11(
16902
+ const sessionName = execSync12(
16885
16903
  "tmux display-message -p '#{session_name}' 2>/dev/null",
16886
16904
  { encoding: "utf8", timeout: 2e3 }
16887
16905
  ).trim();
@@ -17606,7 +17624,7 @@ __export(exe_rename_exports, {
17606
17624
  renameEmployee: () => renameEmployee
17607
17625
  });
17608
17626
  import { readFileSync as readFileSync25, writeFileSync as writeFileSync22, renameSync as renameSync6, unlinkSync as unlinkSync13, existsSync as existsSync29 } from "fs";
17609
- import { execSync as execSync12 } from "child_process";
17627
+ import { execSync as execSync13 } from "child_process";
17610
17628
  import path36 from "path";
17611
17629
  import { homedir as homedir4 } from "os";
17612
17630
  async function renameEmployee(oldName, newName, opts = {}) {
@@ -17747,7 +17765,7 @@ function rewriteRenamedEmployeeContent(content, oldName, newName) {
17747
17765
  }
17748
17766
  function findExeBin2() {
17749
17767
  try {
17750
- return execSync12(process.platform === "win32" ? "where exe-os" : "which exe-os", { encoding: "utf8" }).trim();
17768
+ return execSync13(process.platform === "win32" ? "where exe-os" : "which exe-os", { encoding: "utf8" }).trim();
17751
17769
  } catch {
17752
17770
  return null;
17753
17771
  }
@@ -18453,7 +18471,7 @@ import {
18453
18471
  readdirSync as readdirSync9,
18454
18472
  unlinkSync as unlinkSync15
18455
18473
  } from "fs";
18456
- import { execSync as execSync13 } from "child_process";
18474
+ import { execSync as execSync14 } from "child_process";
18457
18475
  import path38 from "path";
18458
18476
  import { homedir as homedir5 } from "os";
18459
18477
  function generateSessionWrappers(packageRoot, homeDir) {
@@ -18550,12 +18568,12 @@ function writeWrapper(wrapperPath, content) {
18550
18568
  }
18551
18569
  function resolveGlobalBinDir() {
18552
18570
  try {
18553
- const exeOsPath = execSync13("command -v exe-os", { encoding: "utf8", timeout: 3e3 }).trim().split("\n")[0];
18571
+ const exeOsPath = execSync14("command -v exe-os", { encoding: "utf8", timeout: 3e3 }).trim().split("\n")[0];
18554
18572
  if (exeOsPath) return path38.dirname(exeOsPath);
18555
18573
  } catch {
18556
18574
  }
18557
18575
  try {
18558
- const prefix = execSync13("npm prefix -g", { encoding: "utf8", timeout: 3e3 }).trim();
18576
+ const prefix = execSync14("npm prefix -g", { encoding: "utf8", timeout: 3e3 }).trim();
18559
18577
  if (prefix) return path38.join(prefix, "bin");
18560
18578
  } catch {
18561
18579
  }
@@ -18662,8 +18680,8 @@ function ask3(rl, prompt) {
18662
18680
  function getAvailableMemoryGB2() {
18663
18681
  if (process.platform === "darwin") {
18664
18682
  try {
18665
- const { execSync: execSync18 } = __require("child_process");
18666
- const vmstat = execSync18("vm_stat", { encoding: "utf8" });
18683
+ const { execSync: execSync19 } = __require("child_process");
18684
+ const vmstat = execSync19("vm_stat", { encoding: "utf8" });
18667
18685
  const pageSizeMatch = vmstat.match(/page size of (\d+) bytes/);
18668
18686
  const pageSize = pageSizeMatch ? parseInt(pageSizeMatch[1], 10) : 16384;
18669
18687
  const free = vmstat.match(/Pages free:\s+(\d+)/);
@@ -19524,7 +19542,7 @@ var init_update_backup = __esm({
19524
19542
  });
19525
19543
 
19526
19544
  // src/lib/update-check.ts
19527
- import { execSync as execSync14 } from "child_process";
19545
+ import { execSync as execSync15 } from "child_process";
19528
19546
  import { readFileSync as readFileSync28 } from "fs";
19529
19547
  import path41 from "path";
19530
19548
  function getLocalVersion(packageRoot) {
@@ -19534,7 +19552,7 @@ function getLocalVersion(packageRoot) {
19534
19552
  }
19535
19553
  function getRemoteVersion() {
19536
19554
  try {
19537
- const output2 = execSync14("npm view @askexenow/exe-os version", {
19555
+ const output2 = execSync15("npm view @askexenow/exe-os version", {
19538
19556
  encoding: "utf-8",
19539
19557
  timeout: 15e3,
19540
19558
  stdio: ["pipe", "pipe", "pipe"]
@@ -19573,7 +19591,7 @@ __export(update_exports, {
19573
19591
  getRemoteVersion: () => getRemoteVersion,
19574
19592
  runUpdate: () => runUpdate
19575
19593
  });
19576
- import { execSync as execSync15 } from "child_process";
19594
+ import { execSync as execSync16 } from "child_process";
19577
19595
  import { createInterface as createInterface5 } from "readline";
19578
19596
  async function runRestore() {
19579
19597
  console.log("\n\u{1F504} Restoring from update backup...");
@@ -19584,7 +19602,7 @@ async function runRestore() {
19584
19602
  console.log(`
19585
19603
  \u{1F4E5} Reinstalling @askexenow/exe-os@${manifest.version}...`);
19586
19604
  try {
19587
- execSync15(`npm install -g @askexenow/exe-os@${manifest.version}`, {
19605
+ execSync16(`npm install -g @askexenow/exe-os@${manifest.version}`, {
19588
19606
  stdio: ["pipe", "pipe", "inherit"],
19589
19607
  timeout: 3e5
19590
19608
  });
@@ -19609,7 +19627,7 @@ async function runRestore() {
19609
19627
  }
19610
19628
  async function runUpdate(cliArgs) {
19611
19629
  const args2 = cliArgs ?? process.argv.slice(2);
19612
- const autoMode = args2.includes("--auto") || args2.includes("-y");
19630
+ const autoMode = args2.includes("--auto") || args2.includes("--yes") || args2.includes("-y");
19613
19631
  const checkOnly = args2.includes("--check");
19614
19632
  const restoreMode = args2.includes("--restore");
19615
19633
  if (restoreMode) {
@@ -19661,7 +19679,7 @@ async function runUpdate(cliArgs) {
19661
19679
  }
19662
19680
  console.log("\u{1F9F9} Clearing npm cache...");
19663
19681
  try {
19664
- execSync15("npm cache clean --force", { stdio: "pipe" });
19682
+ execSync16("npm cache clean --force", { stdio: "pipe" });
19665
19683
  console.log(" Done");
19666
19684
  } catch {
19667
19685
  console.log(" Skipped (non-critical)");
@@ -19669,7 +19687,7 @@ async function runUpdate(cliArgs) {
19669
19687
  console.log("\u{1F4E5} Installing @askexenow/exe-os@latest...");
19670
19688
  console.log(" This may take a minute...\n");
19671
19689
  try {
19672
- execSync15("npm install -g @askexenow/exe-os@latest", {
19690
+ execSync16("npm install -g @askexenow/exe-os@latest", {
19673
19691
  stdio: ["pipe", "pipe", "inherit"],
19674
19692
  timeout: 3e5
19675
19693
  });
@@ -19687,7 +19705,7 @@ async function runUpdate(cliArgs) {
19687
19705
  newVersion = getLocalVersion(packageRoot);
19688
19706
  } catch {
19689
19707
  try {
19690
- const out = execSync15("npm list -g @askexenow/exe-os --depth=0 2>/dev/null", { encoding: "utf8" });
19708
+ const out = execSync16("npm list -g @askexenow/exe-os --depth=0 2>/dev/null", { encoding: "utf8" });
19691
19709
  const match = out.match(/@askexenow\/exe-os@(\S+)/);
19692
19710
  newVersion = match?.[1] ?? "unknown";
19693
19711
  } catch {
@@ -19716,7 +19734,7 @@ async function runUpdate(cliArgs) {
19716
19734
  }
19717
19735
  console.log("\u{1F527} Re-registering MCP, hooks, wrappers, and daemon...");
19718
19736
  try {
19719
- execSync15("exe-os-install --global", {
19737
+ execSync16("exe-os-install --global", {
19720
19738
  stdio: ["pipe", "inherit", "inherit"],
19721
19739
  timeout: 3e5
19722
19740
  });
@@ -19751,7 +19769,7 @@ async function runUpdate(cliArgs) {
19751
19769
  }
19752
19770
  try {
19753
19771
  console.log("\u{1FA7A} Checking AskExe support intake...");
19754
- execSync15("exe-os support health", {
19772
+ execSync16("exe-os support health", {
19755
19773
  stdio: ["pipe", "inherit", "inherit"],
19756
19774
  timeout: 3e4
19757
19775
  });
@@ -20074,6 +20092,9 @@ function installDockerUbuntu(exec2) {
20074
20092
  function randomSecret(bytes = 32) {
20075
20093
  return randomBytes2(bytes).toString("base64url");
20076
20094
  }
20095
+ function randomHexSecret(bytes = 24) {
20096
+ return randomBytes2(bytes).toString("hex");
20097
+ }
20077
20098
  function hydrateEnv(raw, opts) {
20078
20099
  let next = raw;
20079
20100
  const license = opts.licenseKey || process.env.EXE_LICENSE_KEY || loadLicense() || "";
@@ -20083,6 +20104,8 @@ function hydrateEnv(raw, opts) {
20083
20104
  for (const [key, value] of env.entries()) {
20084
20105
  if (!/CHANGEME/.test(value)) continue;
20085
20106
  if (key === "EXE_LICENSE_KEY" && license) replacements[key] = license;
20107
+ else if (key === "MONITOR_AGENT_KEY") continue;
20108
+ else if (key === "EXE_GATEWAY_WS_RELAY_AUTH_TOKEN") replacements[key] = randomHexSecret(24);
20086
20109
  else if (key.endsWith("_PASSWORD")) replacements[key] = randomSecret(24);
20087
20110
  else if (key.endsWith("_SECRET") || key.endsWith("_TOKEN") || key.endsWith("_KEY") || key.endsWith("_SALT")) replacements[key] = value.replace(/CHANGEME[A-Z0-9_]*/g, randomSecret(32));
20088
20111
  else if (key === "EXED_MCP_TOKEN") replacements[key] = randomSecret(32);
@@ -20342,7 +20365,9 @@ function defaultStackPaths() {
20342
20365
  // Packaged manifests keep cold-start installs unblocked even before update-service entitlements are provisioned.
20343
20366
  auditUrl: process.env.EXE_STACK_AUDIT_URL || (/^https?:\/\//.test(manifestRef) ? "https://update.askexe.com/v1/deploy-audits" : void 0),
20344
20367
  imageCredentialsUrl: process.env.EXE_STACK_IMAGE_CREDENTIALS_URL || (/^https?:\/\//.test(manifestRef) ? "https://update.askexe.com/v1/image-credentials" : void 0),
20345
- manifestAuthToken: process.env.EXE_STACK_UPDATE_TOKEN || process.env.EXE_LICENSE_KEY || loadLicense() || void 0,
20368
+ // License key IS the auth token for update.askexe.com no separate update token needed.
20369
+ // EXE_STACK_UPDATE_TOKEN kept as legacy fallback during migration.
20370
+ manifestAuthToken: process.env.EXE_LICENSE_KEY || loadLicense() || process.env.EXE_STACK_UPDATE_TOKEN || void 0,
20346
20371
  manifestPublicKey: loadDefaultPublicKey()
20347
20372
  };
20348
20373
  }
@@ -20482,7 +20507,14 @@ function printChanges(changes, composeFile, envFile) {
20482
20507
  if (changes.length === 0) {
20483
20508
  const running = areCliContainersRunning(composeFile, envFile);
20484
20509
  if (running) {
20485
- console.log("\u2705 Stack already matches target manifest.");
20510
+ console.log("Stack .env matches target manifest. Checking container health...\n");
20511
+ const unhealthy = printContainerHealth(composeFile, envFile);
20512
+ if (unhealthy > 0) {
20513
+ console.log(`
20514
+ \u{1F534} ${unhealthy} service(s) unhealthy or crashlooping. Run \`docker compose logs <service>\` to diagnose.`);
20515
+ } else {
20516
+ console.log("\n\u2705 Stack already matches target manifest. All services healthy.");
20517
+ }
20486
20518
  } else {
20487
20519
  console.log("\u26A0\uFE0F Stack .env matches target manifest but containers are not running. Will start them.");
20488
20520
  }
@@ -20505,6 +20537,49 @@ function areCliContainersRunning(composeFile, envFile) {
20505
20537
  return false;
20506
20538
  }
20507
20539
  }
20540
+ function getContainerHealth(composeFile, envFile) {
20541
+ try {
20542
+ const result = spawnSync2(
20543
+ "docker",
20544
+ ["compose", "--file", composeFile, "--env-file", envFile, "ps", "--format", "json"],
20545
+ { stdio: ["pipe", "pipe", "pipe"], timeout: 15e3 }
20546
+ );
20547
+ if (result.status !== 0) return [];
20548
+ const raw = result.stdout?.toString().trim() ?? "";
20549
+ if (!raw) return [];
20550
+ return raw.split("\n").filter(Boolean).map((line) => {
20551
+ try {
20552
+ const obj = JSON.parse(line);
20553
+ return {
20554
+ service: obj.Service ?? obj.Name ?? "unknown",
20555
+ state: obj.State ?? "unknown",
20556
+ health: obj.Health ?? "",
20557
+ restartCount: typeof obj.RestartCount === "number" ? obj.RestartCount : 0
20558
+ };
20559
+ } catch {
20560
+ return null;
20561
+ }
20562
+ }).filter((x) => x !== null);
20563
+ } catch {
20564
+ return [];
20565
+ }
20566
+ }
20567
+ function printContainerHealth(composeFile, envFile) {
20568
+ const containers = getContainerHealth(composeFile, envFile);
20569
+ if (containers.length === 0) return 0;
20570
+ let unhealthy = 0;
20571
+ for (const c of containers) {
20572
+ const isRestarting = c.state === "restarting" || c.restartCount > 2;
20573
+ const isUnhealthy = c.health === "unhealthy" || c.state === "dead" || c.state === "exited";
20574
+ if (isRestarting || isUnhealthy) {
20575
+ unhealthy++;
20576
+ console.log(` \u274C ${c.service}: ${c.state} (restarts: ${c.restartCount}${c.health ? `, health: ${c.health}` : ""})`);
20577
+ } else {
20578
+ console.log(` \u2705 ${c.service}: ${c.state}${c.health ? ` (${c.health})` : ""}`);
20579
+ }
20580
+ }
20581
+ return unhealthy;
20582
+ }
20508
20583
  function printBreaking(changes) {
20509
20584
  if (changes.length === 0) return;
20510
20585
  console.log("\nBreaking-change notices:");
@@ -27253,13 +27328,13 @@ __export(tmux_status_exports, {
27253
27328
  parseActivity: () => parseActivity,
27254
27329
  parseContextPercentage: () => parseContextPercentage
27255
27330
  });
27256
- import { execSync as execSync16 } from "child_process";
27331
+ import { execSync as execSync17 } from "child_process";
27257
27332
  function inTmux() {
27258
27333
  if (process.env.TMUX || process.env.TMUX_PANE) return true;
27259
27334
  const term = process.env.TERM ?? "";
27260
27335
  if (term.startsWith("tmux") || term.startsWith("screen")) return true;
27261
27336
  try {
27262
- execSync16("tmux display-message -p '#{session_name}' 2>/dev/null", {
27337
+ execSync17("tmux display-message -p '#{session_name}' 2>/dev/null", {
27263
27338
  encoding: "utf8",
27264
27339
  timeout: 2e3
27265
27340
  });
@@ -27269,12 +27344,12 @@ function inTmux() {
27269
27344
  try {
27270
27345
  let pid = process.ppid;
27271
27346
  for (let depth = 0; depth < 8 && pid > 1; depth++) {
27272
- const comm = execSync16(`ps -p ${pid} -o comm= 2>/dev/null`, {
27347
+ const comm = execSync17(`ps -p ${pid} -o comm= 2>/dev/null`, {
27273
27348
  encoding: "utf8",
27274
27349
  timeout: 1e3
27275
27350
  }).trim();
27276
27351
  if (/tmux/.test(comm)) return true;
27277
- const ppid = execSync16(`ps -p ${pid} -o ppid= 2>/dev/null`, {
27352
+ const ppid = execSync17(`ps -p ${pid} -o ppid= 2>/dev/null`, {
27278
27353
  encoding: "utf8",
27279
27354
  timeout: 1e3
27280
27355
  }).trim();
@@ -27287,7 +27362,7 @@ function inTmux() {
27287
27362
  }
27288
27363
  function listTmuxSessions() {
27289
27364
  try {
27290
- const out = execSync16("tmux list-sessions -F '#{session_name}' 2>/dev/null", {
27365
+ const out = execSync17("tmux list-sessions -F '#{session_name}' 2>/dev/null", {
27291
27366
  encoding: "utf8",
27292
27367
  timeout: 3e3
27293
27368
  });
@@ -27298,7 +27373,7 @@ function listTmuxSessions() {
27298
27373
  }
27299
27374
  function capturePaneLines(windowName, lines = 10) {
27300
27375
  try {
27301
- const out = execSync16(
27376
+ const out = execSync17(
27302
27377
  `tmux capture-pane -t ${JSON.stringify(windowName)} -p 2>/dev/null | tail -${lines}`,
27303
27378
  { encoding: "utf8", timeout: 3e3 }
27304
27379
  );
@@ -27309,7 +27384,7 @@ function capturePaneLines(windowName, lines = 10) {
27309
27384
  }
27310
27385
  function getPaneCwd(windowName) {
27311
27386
  try {
27312
- const out = execSync16(
27387
+ const out = execSync17(
27313
27388
  `tmux display-message -t ${JSON.stringify(windowName)} -p '#{pane_current_path}' 2>/dev/null`,
27314
27389
  { encoding: "utf8", timeout: 3e3 }
27315
27390
  );
@@ -27320,7 +27395,7 @@ function getPaneCwd(windowName) {
27320
27395
  }
27321
27396
  function projectFromPath(dir) {
27322
27397
  try {
27323
- const root = execSync16("git -C " + JSON.stringify(dir) + " rev-parse --show-toplevel 2>/dev/null", {
27398
+ const root = execSync17("git -C " + JSON.stringify(dir) + " rev-parse --show-toplevel 2>/dev/null", {
27324
27399
  encoding: "utf8",
27325
27400
  timeout: 3e3
27326
27401
  }).trim();
@@ -27389,7 +27464,7 @@ function getEmployeeStatuses(employeeNames) {
27389
27464
  }
27390
27465
  let paneAlive = true;
27391
27466
  try {
27392
- const paneStatus = execSync16(
27467
+ const paneStatus = execSync17(
27393
27468
  `tmux list-panes -t ${JSON.stringify(sessionName)} -F '#{pane_dead}' 2>/dev/null`,
27394
27469
  { encoding: "utf8", timeout: 3e3 }
27395
27470
  ).trim();
@@ -27579,8 +27654,8 @@ function Footer() {
27579
27654
  setSessions(allSessions.length);
27580
27655
  if (!currentSession) {
27581
27656
  try {
27582
- const { execSync: execSync18 } = await import("child_process");
27583
- const name = execSync18("tmux display-message -p '#{session_name}' 2>/dev/null", {
27657
+ const { execSync: execSync19 } = await import("child_process");
27658
+ const name = execSync19("tmux display-message -p '#{session_name}' 2>/dev/null", {
27584
27659
  encoding: "utf8",
27585
27660
  timeout: 2e3
27586
27661
  }).trim();
@@ -30934,8 +31009,8 @@ function TmuxPane({ sessionName, employeeName, employeeRole, projectName, onDeta
30934
31009
  }
30935
31010
  const capture = () => {
30936
31011
  try {
30937
- const { execSync: execSync18 } = __require("child_process");
30938
- const output2 = execSync18(
31012
+ const { execSync: execSync19 } = __require("child_process");
31013
+ const output2 = execSync19(
30939
31014
  `tmux capture-pane -t ${JSON.stringify(sessionName)} -p -e 2>/dev/null | tail -${CAPTURE_LINES}`,
30940
31015
  { encoding: "utf8", timeout: 3e3 }
30941
31016
  );
@@ -30959,8 +31034,8 @@ function TmuxPane({ sessionName, employeeName, employeeRole, projectName, onDeta
30959
31034
  if (key.return) {
30960
31035
  if (!demo && inputBuffer.trim()) {
30961
31036
  try {
30962
- const { execSync: execSync18 } = __require("child_process");
30963
- execSync18(
31037
+ const { execSync: execSync19 } = __require("child_process");
31038
+ execSync19(
30964
31039
  `tmux send-keys -t ${JSON.stringify(sessionName)} ${JSON.stringify(inputBuffer)} Enter`,
30965
31040
  { timeout: 2e3 }
30966
31041
  );
@@ -30968,8 +31043,8 @@ function TmuxPane({ sessionName, employeeName, employeeRole, projectName, onDeta
30968
31043
  }
30969
31044
  } else if (!demo) {
30970
31045
  try {
30971
- const { execSync: execSync18 } = __require("child_process");
30972
- execSync18(`tmux send-keys -t ${JSON.stringify(sessionName)} Enter`, { timeout: 2e3 });
31046
+ const { execSync: execSync19 } = __require("child_process");
31047
+ execSync19(`tmux send-keys -t ${JSON.stringify(sessionName)} Enter`, { timeout: 2e3 });
30973
31048
  } catch {
30974
31049
  }
30975
31050
  }
@@ -31656,12 +31731,12 @@ function SessionsView({
31656
31731
  return;
31657
31732
  }
31658
31733
  } else {
31659
- const { execSync: execSync18 } = await import("child_process");
31734
+ const { execSync: execSync19 } = await import("child_process");
31660
31735
  const dir = projectDir || process.cwd();
31661
- execSync18(`tmux new-session -d -s ${JSON.stringify(entry.sessionName)} -c ${JSON.stringify(dir)}`, { timeout: 5e3 });
31662
- execSync18(`tmux send-keys -t ${JSON.stringify(entry.sessionName)} "claude --dangerously-skip-permissions" Enter`, { timeout: 3e3 });
31736
+ execSync19(`tmux new-session -d -s ${JSON.stringify(entry.sessionName)} -c ${JSON.stringify(dir)}`, { timeout: 5e3 });
31737
+ execSync19(`tmux send-keys -t ${JSON.stringify(entry.sessionName)} "claude --dangerously-skip-permissions" Enter`, { timeout: 3e3 });
31663
31738
  await new Promise((r) => setTimeout(r, 3e3));
31664
- execSync18(`tmux send-keys -t ${JSON.stringify(entry.sessionName)} "/exe" Enter`, { timeout: 3e3 });
31739
+ execSync19(`tmux send-keys -t ${JSON.stringify(entry.sessionName)} "/exe" Enter`, { timeout: 3e3 });
31665
31740
  }
31666
31741
  const updated = { ...entry, status: "active", activity: "Starting...", attached: false };
31667
31742
  setViewingEmployee(updated);
@@ -31764,7 +31839,7 @@ function SessionsView({
31764
31839
  const { listTmuxSessions: listTmuxSessions2, inTmux: inTmux2, capturePaneLines: capturePaneLines2, parseActivity: parseActivity2 } = await Promise.resolve().then(() => (init_tmux_status(), tmux_status_exports));
31765
31840
  const { getCoordinatorName: getCoordinatorName2, isCoordinatorRole: isCoordinatorRole2, loadEmployees: loadEmployees2 } = await Promise.resolve().then(() => (init_employees(), employees_exports));
31766
31841
  const { isExeSession: isExeSession2 } = await Promise.resolve().then(() => (init_tmux_routing(), tmux_routing_exports));
31767
- const { execSync: execSync18 } = await import("child_process");
31842
+ const { execSync: execSync19 } = await import("child_process");
31768
31843
  if (!inTmux2()) {
31769
31844
  setTmuxAvailable(false);
31770
31845
  setProjects([]);
@@ -31773,7 +31848,7 @@ function SessionsView({
31773
31848
  setTmuxAvailable(true);
31774
31849
  const attachedMap = /* @__PURE__ */ new Map();
31775
31850
  try {
31776
- const out = execSync18("tmux list-sessions -F '#{session_name}:#{session_attached}' 2>/dev/null", {
31851
+ const out = execSync19("tmux list-sessions -F '#{session_name}:#{session_attached}' 2>/dev/null", {
31777
31852
  encoding: "utf8",
31778
31853
  timeout: 3e3
31779
31854
  });
@@ -32809,8 +32884,8 @@ function upsertConversation(conversations, platform, senderId, message) {
32809
32884
  async function loadGatewayConfig() {
32810
32885
  const state = { running: false, port: 3100, adapters: [], agents: [], gatewayUrl: "" };
32811
32886
  try {
32812
- const { execSync: execSync18 } = await import("child_process");
32813
- const ps = execSync18("pgrep -f exe-gateway 2>/dev/null", { encoding: "utf8", timeout: 3e3 });
32887
+ const { execSync: execSync19 } = await import("child_process");
32888
+ const ps = execSync19("pgrep -f exe-gateway 2>/dev/null", { encoding: "utf8", timeout: 3e3 });
32814
32889
  state.running = ps.trim().length > 0;
32815
32890
  } catch {
32816
32891
  state.running = false;
@@ -33287,10 +33362,10 @@ var init_Gateway = __esm({
33287
33362
  });
33288
33363
 
33289
33364
  // src/tui/utils/agent-status.ts
33290
- import { execSync as execSync17 } from "child_process";
33365
+ import { execSync as execSync18 } from "child_process";
33291
33366
  function getAgentStatus(agentId) {
33292
33367
  try {
33293
- const sessions = execSync17("tmux list-sessions -F '#{session_name}' 2>/dev/null", {
33368
+ const sessions = execSync18("tmux list-sessions -F '#{session_name}' 2>/dev/null", {
33294
33369
  encoding: "utf8",
33295
33370
  timeout: 2e3
33296
33371
  }).trim().split("\n");
@@ -33301,7 +33376,7 @@ function getAgentStatus(agentId) {
33301
33376
  return /^\d?-/.test(suffix) || /^\d+$/.test(suffix);
33302
33377
  });
33303
33378
  if (!agentSession) return { label: "offline", color: "gray" };
33304
- const pane = execSync17(`tmux capture-pane -t "${agentSession}" -p 2>/dev/null | tail -3`, {
33379
+ const pane = execSync18(`tmux capture-pane -t "${agentSession}" -p 2>/dev/null | tail -3`, {
33305
33380
  encoding: "utf8",
33306
33381
  timeout: 2e3
33307
33382
  });
@@ -34224,8 +34299,8 @@ function SettingsView({ onBack }) {
34224
34299
  };
34225
34300
  });
34226
34301
  try {
34227
- const { execSync: execSync18 } = await import("child_process");
34228
- execSync18("curl -s --max-time 1 http://localhost:11434/api/tags", { timeout: 2e3 });
34302
+ const { execSync: execSync19 } = await import("child_process");
34303
+ execSync19("curl -s --max-time 1 http://localhost:11434/api/tags", { timeout: 2e3 });
34229
34304
  providerList.push({ name: "Ollama", configured: true, detail: "localhost:11434" });
34230
34305
  } catch {
34231
34306
  providerList.push({ name: "Ollama", configured: false, detail: "not running" });
@@ -37024,10 +37099,10 @@ async function runClaudeUninstall(flags = []) {
37024
37099
  }
37025
37100
  }
37026
37101
  try {
37027
- const { execSync: execSync18 } = await import("child_process");
37102
+ const { execSync: execSync19 } = await import("child_process");
37028
37103
  const findExeBin3 = () => {
37029
37104
  try {
37030
- return execSync18(process.platform === "win32" ? "where exe-os" : "which exe-os", { encoding: "utf8" }).trim();
37105
+ return execSync19(process.platform === "win32" ? "where exe-os" : "which exe-os", { encoding: "utf8" }).trim();
37031
37106
  } catch {
37032
37107
  return null;
37033
37108
  }