@askexenow/exe-os 0.9.30 → 0.9.32

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 (64) hide show
  1. package/dist/bin/backfill-conversations.js +135 -7
  2. package/dist/bin/backfill-responses.js +135 -7
  3. package/dist/bin/backfill-vectors.js +135 -7
  4. package/dist/bin/cleanup-stale-review-tasks.js +139 -11
  5. package/dist/bin/cli.js +812 -486
  6. package/dist/bin/exe-assign.js +135 -7
  7. package/dist/bin/exe-boot.js +422 -113
  8. package/dist/bin/exe-cloud.js +160 -9
  9. package/dist/bin/exe-dispatch.js +136 -8
  10. package/dist/bin/exe-doctor.js +255 -13
  11. package/dist/bin/exe-export-behaviors.js +136 -8
  12. package/dist/bin/exe-forget.js +136 -8
  13. package/dist/bin/exe-gateway.js +171 -24
  14. package/dist/bin/exe-heartbeat.js +141 -13
  15. package/dist/bin/exe-kill.js +140 -12
  16. package/dist/bin/exe-launch-agent.js +143 -15
  17. package/dist/bin/exe-link.js +357 -48
  18. package/dist/bin/exe-pending-messages.js +136 -8
  19. package/dist/bin/exe-pending-notifications.js +136 -8
  20. package/dist/bin/exe-pending-reviews.js +138 -10
  21. package/dist/bin/exe-review.js +136 -8
  22. package/dist/bin/exe-search.js +155 -20
  23. package/dist/bin/exe-session-cleanup.js +166 -38
  24. package/dist/bin/exe-start-codex.js +142 -14
  25. package/dist/bin/exe-start-opencode.js +140 -12
  26. package/dist/bin/exe-status.js +148 -20
  27. package/dist/bin/exe-team.js +136 -8
  28. package/dist/bin/git-sweep.js +138 -10
  29. package/dist/bin/graph-backfill.js +135 -7
  30. package/dist/bin/graph-export.js +136 -8
  31. package/dist/bin/intercom-check.js +153 -25
  32. package/dist/bin/scan-tasks.js +138 -10
  33. package/dist/bin/setup.js +447 -121
  34. package/dist/bin/shard-migrate.js +135 -7
  35. package/dist/gateway/index.js +151 -23
  36. package/dist/hooks/bug-report-worker.js +151 -23
  37. package/dist/hooks/codex-stop-task-finalizer.js +145 -17
  38. package/dist/hooks/commit-complete.js +138 -10
  39. package/dist/hooks/error-recall.js +159 -24
  40. package/dist/hooks/ingest.js +142 -14
  41. package/dist/hooks/instructions-loaded.js +136 -8
  42. package/dist/hooks/notification.js +136 -8
  43. package/dist/hooks/post-compact.js +136 -8
  44. package/dist/hooks/post-tool-combined.js +159 -24
  45. package/dist/hooks/pre-compact.js +136 -8
  46. package/dist/hooks/pre-tool-use.js +144 -16
  47. package/dist/hooks/prompt-submit.js +195 -55
  48. package/dist/hooks/session-end.js +141 -13
  49. package/dist/hooks/session-start.js +165 -30
  50. package/dist/hooks/stop.js +136 -8
  51. package/dist/hooks/subagent-stop.js +136 -8
  52. package/dist/hooks/summary-worker.js +374 -65
  53. package/dist/index.js +136 -8
  54. package/dist/lib/cloud-sync.js +355 -46
  55. package/dist/lib/consolidation.js +1 -0
  56. package/dist/lib/exe-daemon.js +469 -127
  57. package/dist/lib/hybrid-search.js +155 -20
  58. package/dist/lib/keychain.js +191 -7
  59. package/dist/lib/schedules.js +138 -10
  60. package/dist/lib/store.js +135 -7
  61. package/dist/mcp/server.js +706 -213
  62. package/dist/runtime/index.js +136 -8
  63. package/dist/tui/App.js +208 -31
  64. package/package.json +1 -1
@@ -1040,8 +1040,8 @@ function findPackageRoot() {
1040
1040
  function getAvailableMemoryGB() {
1041
1041
  if (process.platform === "darwin") {
1042
1042
  try {
1043
- const { execSync: execSync2 } = __require("child_process");
1044
- const vmstat = execSync2("vm_stat", { encoding: "utf8" });
1043
+ const { execSync: execSync3 } = __require("child_process");
1044
+ const vmstat = execSync3("vm_stat", { encoding: "utf8" });
1045
1045
  const pageSize = 16384;
1046
1046
  const pageSizeMatch = vmstat.match(/page size of (\d+) bytes/);
1047
1047
  const actualPageSize = pageSizeMatch ? parseInt(pageSizeMatch[1], 10) : pageSize;
@@ -2780,6 +2780,7 @@ var init_database = __esm({
2780
2780
  // src/lib/keychain.ts
2781
2781
  import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
2782
2782
  import { existsSync as existsSync6 } from "fs";
2783
+ import { execSync as execSync2 } from "child_process";
2783
2784
  import path6 from "path";
2784
2785
  import os5 from "os";
2785
2786
  function getKeyDir() {
@@ -2788,6 +2789,59 @@ function getKeyDir() {
2788
2789
  function getKeyPath() {
2789
2790
  return path6.join(getKeyDir(), "master.key");
2790
2791
  }
2792
+ function macKeychainGet() {
2793
+ if (process.platform !== "darwin") return null;
2794
+ try {
2795
+ return execSync2(
2796
+ `security find-generic-password -s "${SERVICE}" -a "${ACCOUNT}" -w 2>/dev/null`,
2797
+ { encoding: "utf-8", timeout: 5e3 }
2798
+ ).trim();
2799
+ } catch {
2800
+ return null;
2801
+ }
2802
+ }
2803
+ function macKeychainSet(value) {
2804
+ if (process.platform !== "darwin") return false;
2805
+ try {
2806
+ try {
2807
+ execSync2(
2808
+ `security delete-generic-password -s "${SERVICE}" -a "${ACCOUNT}" 2>/dev/null`,
2809
+ { timeout: 5e3 }
2810
+ );
2811
+ } catch {
2812
+ }
2813
+ execSync2(
2814
+ `security add-generic-password -s "${SERVICE}" -a "${ACCOUNT}" -w "${value}"`,
2815
+ { timeout: 5e3 }
2816
+ );
2817
+ return true;
2818
+ } catch {
2819
+ return false;
2820
+ }
2821
+ }
2822
+ function linuxSecretGet() {
2823
+ if (process.platform !== "linux") return null;
2824
+ try {
2825
+ return execSync2(
2826
+ `secret-tool lookup service "${SERVICE}" account "${ACCOUNT}" 2>/dev/null`,
2827
+ { encoding: "utf-8", timeout: 5e3 }
2828
+ ).trim();
2829
+ } catch {
2830
+ return null;
2831
+ }
2832
+ }
2833
+ function linuxSecretSet(value) {
2834
+ if (process.platform !== "linux") return false;
2835
+ try {
2836
+ execSync2(
2837
+ `echo -n "${value}" | secret-tool store --label="exe-os master key" service "${SERVICE}" account "${ACCOUNT}"`,
2838
+ { timeout: 5e3 }
2839
+ );
2840
+ return true;
2841
+ } catch {
2842
+ return false;
2843
+ }
2844
+ }
2791
2845
  async function tryKeytar() {
2792
2846
  try {
2793
2847
  return await import("keytar");
@@ -2795,13 +2849,63 @@ async function tryKeytar() {
2795
2849
  return null;
2796
2850
  }
2797
2851
  }
2852
+ function deriveMachineKey() {
2853
+ try {
2854
+ const crypto2 = __require("crypto");
2855
+ const material = [
2856
+ os5.hostname(),
2857
+ os5.userInfo().username,
2858
+ os5.arch(),
2859
+ os5.platform(),
2860
+ // Machine ID on Linux (stable across reboots)
2861
+ process.platform === "linux" ? readMachineId() : ""
2862
+ ].join("|");
2863
+ return crypto2.createHash("sha256").update(material).digest();
2864
+ } catch {
2865
+ return null;
2866
+ }
2867
+ }
2868
+ function readMachineId() {
2869
+ try {
2870
+ const { readFileSync: readFileSync5 } = __require("fs");
2871
+ return readFileSync5("/etc/machine-id", "utf-8").trim();
2872
+ } catch {
2873
+ return "";
2874
+ }
2875
+ }
2876
+ function decryptWithMachineKey(encrypted, machineKey) {
2877
+ if (!encrypted.startsWith(ENCRYPTED_PREFIX)) return null;
2878
+ try {
2879
+ const crypto2 = __require("crypto");
2880
+ const parts = encrypted.slice(ENCRYPTED_PREFIX.length).split(":");
2881
+ if (parts.length !== 3) return null;
2882
+ const [ivB64, tagB64, cipherB64] = parts;
2883
+ const iv = Buffer.from(ivB64, "base64");
2884
+ const authTag = Buffer.from(tagB64, "base64");
2885
+ const decipher = crypto2.createDecipheriv("aes-256-gcm", machineKey, iv);
2886
+ decipher.setAuthTag(authTag);
2887
+ let decrypted = decipher.update(cipherB64, "base64", "utf-8");
2888
+ decrypted += decipher.final("utf-8");
2889
+ return decrypted;
2890
+ } catch {
2891
+ return null;
2892
+ }
2893
+ }
2798
2894
  async function getMasterKey() {
2895
+ const nativeValue = macKeychainGet() ?? linuxSecretGet();
2896
+ if (nativeValue) {
2897
+ return Buffer.from(nativeValue, "base64");
2898
+ }
2799
2899
  const keytar = await tryKeytar();
2800
2900
  if (keytar) {
2801
2901
  try {
2802
- const stored = await keytar.getPassword(SERVICE, ACCOUNT);
2803
- if (stored) {
2804
- return Buffer.from(stored, "base64");
2902
+ const keytarValue = await keytar.getPassword(SERVICE, ACCOUNT);
2903
+ if (keytarValue) {
2904
+ const migrated = macKeychainSet(keytarValue) || linuxSecretSet(keytarValue);
2905
+ if (migrated) {
2906
+ process.stderr.write("[keychain] Migrated key from keytar to native keychain.\n");
2907
+ }
2908
+ return Buffer.from(keytarValue, "base64");
2805
2909
  }
2806
2910
  } catch {
2807
2911
  }
@@ -2815,8 +2919,31 @@ async function getMasterKey() {
2815
2919
  return null;
2816
2920
  }
2817
2921
  try {
2818
- const content = await readFile3(keyPath, "utf-8");
2819
- return Buffer.from(content.trim(), "base64");
2922
+ const content = (await readFile3(keyPath, "utf-8")).trim();
2923
+ let b64Value;
2924
+ if (content.startsWith(ENCRYPTED_PREFIX)) {
2925
+ const machineKey = deriveMachineKey();
2926
+ if (!machineKey) {
2927
+ process.stderr.write("[keychain] Cannot derive machine key to decrypt stored key.\n");
2928
+ return null;
2929
+ }
2930
+ const decrypted = decryptWithMachineKey(content, machineKey);
2931
+ if (!decrypted) {
2932
+ process.stderr.write(
2933
+ "[keychain] Key decryption failed \u2014 machine may have changed.\n Use your 24-word recovery phrase: exe-os link import\n"
2934
+ );
2935
+ return null;
2936
+ }
2937
+ b64Value = decrypted;
2938
+ } else {
2939
+ b64Value = content;
2940
+ }
2941
+ const key = Buffer.from(b64Value, "base64");
2942
+ const migrated = macKeychainSet(b64Value) || linuxSecretSet(b64Value);
2943
+ if (migrated) {
2944
+ process.stderr.write("[keychain] Migrated key from file to native keychain.\n");
2945
+ }
2946
+ return key;
2820
2947
  } catch (err) {
2821
2948
  process.stderr.write(
2822
2949
  `[keychain] Key read failed at ${keyPath}: ${err instanceof Error ? err.message : String(err)}
@@ -2825,12 +2952,13 @@ async function getMasterKey() {
2825
2952
  return null;
2826
2953
  }
2827
2954
  }
2828
- var SERVICE, ACCOUNT;
2955
+ var SERVICE, ACCOUNT, ENCRYPTED_PREFIX;
2829
2956
  var init_keychain = __esm({
2830
2957
  "src/lib/keychain.ts"() {
2831
2958
  "use strict";
2832
2959
  SERVICE = "exe-mem";
2833
2960
  ACCOUNT = "master-key";
2961
+ ENCRYPTED_PREFIX = "enc:";
2834
2962
  }
2835
2963
  });
2836
2964
 
@@ -1740,8 +1740,8 @@ function findPackageRoot() {
1740
1740
  function getAvailableMemoryGB() {
1741
1741
  if (process.platform === "darwin") {
1742
1742
  try {
1743
- const { execSync: execSync7 } = __require("child_process");
1744
- const vmstat = execSync7("vm_stat", { encoding: "utf8" });
1743
+ const { execSync: execSync8 } = __require("child_process");
1744
+ const vmstat = execSync8("vm_stat", { encoding: "utf8" });
1745
1745
  const pageSize = 16384;
1746
1746
  const pageSizeMatch = vmstat.match(/page size of (\d+) bytes/);
1747
1747
  const actualPageSize = pageSizeMatch ? parseInt(pageSizeMatch[1], 10) : pageSize;
@@ -3493,6 +3493,7 @@ var init_embedder = __esm({
3493
3493
  // src/lib/keychain.ts
3494
3494
  import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
3495
3495
  import { existsSync as existsSync7 } from "fs";
3496
+ import { execSync as execSync2 } from "child_process";
3496
3497
  import path8 from "path";
3497
3498
  import os6 from "os";
3498
3499
  function getKeyDir() {
@@ -3501,6 +3502,59 @@ function getKeyDir() {
3501
3502
  function getKeyPath() {
3502
3503
  return path8.join(getKeyDir(), "master.key");
3503
3504
  }
3505
+ function macKeychainGet() {
3506
+ if (process.platform !== "darwin") return null;
3507
+ try {
3508
+ return execSync2(
3509
+ `security find-generic-password -s "${SERVICE}" -a "${ACCOUNT}" -w 2>/dev/null`,
3510
+ { encoding: "utf-8", timeout: 5e3 }
3511
+ ).trim();
3512
+ } catch {
3513
+ return null;
3514
+ }
3515
+ }
3516
+ function macKeychainSet(value) {
3517
+ if (process.platform !== "darwin") return false;
3518
+ try {
3519
+ try {
3520
+ execSync2(
3521
+ `security delete-generic-password -s "${SERVICE}" -a "${ACCOUNT}" 2>/dev/null`,
3522
+ { timeout: 5e3 }
3523
+ );
3524
+ } catch {
3525
+ }
3526
+ execSync2(
3527
+ `security add-generic-password -s "${SERVICE}" -a "${ACCOUNT}" -w "${value}"`,
3528
+ { timeout: 5e3 }
3529
+ );
3530
+ return true;
3531
+ } catch {
3532
+ return false;
3533
+ }
3534
+ }
3535
+ function linuxSecretGet() {
3536
+ if (process.platform !== "linux") return null;
3537
+ try {
3538
+ return execSync2(
3539
+ `secret-tool lookup service "${SERVICE}" account "${ACCOUNT}" 2>/dev/null`,
3540
+ { encoding: "utf-8", timeout: 5e3 }
3541
+ ).trim();
3542
+ } catch {
3543
+ return null;
3544
+ }
3545
+ }
3546
+ function linuxSecretSet(value) {
3547
+ if (process.platform !== "linux") return false;
3548
+ try {
3549
+ execSync2(
3550
+ `echo -n "${value}" | secret-tool store --label="exe-os master key" service "${SERVICE}" account "${ACCOUNT}"`,
3551
+ { timeout: 5e3 }
3552
+ );
3553
+ return true;
3554
+ } catch {
3555
+ return false;
3556
+ }
3557
+ }
3504
3558
  async function tryKeytar() {
3505
3559
  try {
3506
3560
  return await import("keytar");
@@ -3508,13 +3562,63 @@ async function tryKeytar() {
3508
3562
  return null;
3509
3563
  }
3510
3564
  }
3565
+ function deriveMachineKey() {
3566
+ try {
3567
+ const crypto10 = __require("crypto");
3568
+ const material = [
3569
+ os6.hostname(),
3570
+ os6.userInfo().username,
3571
+ os6.arch(),
3572
+ os6.platform(),
3573
+ // Machine ID on Linux (stable across reboots)
3574
+ process.platform === "linux" ? readMachineId() : ""
3575
+ ].join("|");
3576
+ return crypto10.createHash("sha256").update(material).digest();
3577
+ } catch {
3578
+ return null;
3579
+ }
3580
+ }
3581
+ function readMachineId() {
3582
+ try {
3583
+ const { readFileSync: readFileSync16 } = __require("fs");
3584
+ return readFileSync16("/etc/machine-id", "utf-8").trim();
3585
+ } catch {
3586
+ return "";
3587
+ }
3588
+ }
3589
+ function decryptWithMachineKey(encrypted, machineKey) {
3590
+ if (!encrypted.startsWith(ENCRYPTED_PREFIX)) return null;
3591
+ try {
3592
+ const crypto10 = __require("crypto");
3593
+ const parts = encrypted.slice(ENCRYPTED_PREFIX.length).split(":");
3594
+ if (parts.length !== 3) return null;
3595
+ const [ivB64, tagB64, cipherB64] = parts;
3596
+ const iv = Buffer.from(ivB64, "base64");
3597
+ const authTag = Buffer.from(tagB64, "base64");
3598
+ const decipher = crypto10.createDecipheriv("aes-256-gcm", machineKey, iv);
3599
+ decipher.setAuthTag(authTag);
3600
+ let decrypted = decipher.update(cipherB64, "base64", "utf-8");
3601
+ decrypted += decipher.final("utf-8");
3602
+ return decrypted;
3603
+ } catch {
3604
+ return null;
3605
+ }
3606
+ }
3511
3607
  async function getMasterKey() {
3608
+ const nativeValue = macKeychainGet() ?? linuxSecretGet();
3609
+ if (nativeValue) {
3610
+ return Buffer.from(nativeValue, "base64");
3611
+ }
3512
3612
  const keytar = await tryKeytar();
3513
3613
  if (keytar) {
3514
3614
  try {
3515
- const stored = await keytar.getPassword(SERVICE, ACCOUNT);
3516
- if (stored) {
3517
- return Buffer.from(stored, "base64");
3615
+ const keytarValue = await keytar.getPassword(SERVICE, ACCOUNT);
3616
+ if (keytarValue) {
3617
+ const migrated = macKeychainSet(keytarValue) || linuxSecretSet(keytarValue);
3618
+ if (migrated) {
3619
+ process.stderr.write("[keychain] Migrated key from keytar to native keychain.\n");
3620
+ }
3621
+ return Buffer.from(keytarValue, "base64");
3518
3622
  }
3519
3623
  } catch {
3520
3624
  }
@@ -3528,8 +3632,31 @@ async function getMasterKey() {
3528
3632
  return null;
3529
3633
  }
3530
3634
  try {
3531
- const content = await readFile3(keyPath, "utf-8");
3532
- return Buffer.from(content.trim(), "base64");
3635
+ const content = (await readFile3(keyPath, "utf-8")).trim();
3636
+ let b64Value;
3637
+ if (content.startsWith(ENCRYPTED_PREFIX)) {
3638
+ const machineKey = deriveMachineKey();
3639
+ if (!machineKey) {
3640
+ process.stderr.write("[keychain] Cannot derive machine key to decrypt stored key.\n");
3641
+ return null;
3642
+ }
3643
+ const decrypted = decryptWithMachineKey(content, machineKey);
3644
+ if (!decrypted) {
3645
+ process.stderr.write(
3646
+ "[keychain] Key decryption failed \u2014 machine may have changed.\n Use your 24-word recovery phrase: exe-os link import\n"
3647
+ );
3648
+ return null;
3649
+ }
3650
+ b64Value = decrypted;
3651
+ } else {
3652
+ b64Value = content;
3653
+ }
3654
+ const key = Buffer.from(b64Value, "base64");
3655
+ const migrated = macKeychainSet(b64Value) || linuxSecretSet(b64Value);
3656
+ if (migrated) {
3657
+ process.stderr.write("[keychain] Migrated key from file to native keychain.\n");
3658
+ }
3659
+ return key;
3533
3660
  } catch (err) {
3534
3661
  process.stderr.write(
3535
3662
  `[keychain] Key read failed at ${keyPath}: ${err instanceof Error ? err.message : String(err)}
@@ -3538,12 +3665,13 @@ async function getMasterKey() {
3538
3665
  return null;
3539
3666
  }
3540
3667
  }
3541
- var SERVICE, ACCOUNT;
3668
+ var SERVICE, ACCOUNT, ENCRYPTED_PREFIX;
3542
3669
  var init_keychain = __esm({
3543
3670
  "src/lib/keychain.ts"() {
3544
3671
  "use strict";
3545
3672
  SERVICE = "exe-mem";
3546
3673
  ACCOUNT = "master-key";
3674
+ ENCRYPTED_PREFIX = "enc:";
3547
3675
  }
3548
3676
  });
3549
3677
 
@@ -7972,7 +8100,7 @@ var init_session_registry = __esm({
7972
8100
  });
7973
8101
 
7974
8102
  // src/lib/session-key.ts
7975
- import { execSync as execSync2 } from "child_process";
8103
+ import { execSync as execSync3 } from "child_process";
7976
8104
  function normalizeCommand(command) {
7977
8105
  const trimmed = command.trim().toLowerCase();
7978
8106
  const parts = trimmed.split(/[\\/]/);
@@ -7991,7 +8119,7 @@ function resolveRuntimeProcess() {
7991
8119
  let pid = process.ppid;
7992
8120
  for (let i = 0; i < 10; i++) {
7993
8121
  try {
7994
- const info = execSync2(`ps -p ${pid} -o ppid=,comm=`, {
8122
+ const info = execSync3(`ps -p ${pid} -o ppid=,comm=`, {
7995
8123
  encoding: "utf8",
7996
8124
  timeout: 2e3
7997
8125
  }).trim();
@@ -8157,14 +8285,14 @@ var init_transport = __esm({
8157
8285
  });
8158
8286
 
8159
8287
  // src/lib/cc-agent-support.ts
8160
- import { execSync as execSync3 } from "child_process";
8288
+ import { execSync as execSync4 } from "child_process";
8161
8289
  function _resetCcAgentSupportCache() {
8162
8290
  _cachedSupport = null;
8163
8291
  }
8164
8292
  function claudeSupportsAgentFlag() {
8165
8293
  if (_cachedSupport !== null) return _cachedSupport;
8166
8294
  try {
8167
- const helpOutput = execSync3("claude --help 2>&1", {
8295
+ const helpOutput = execSync4("claude --help 2>&1", {
8168
8296
  encoding: "utf-8",
8169
8297
  timeout: 5e3
8170
8298
  });
@@ -8558,7 +8686,7 @@ var init_session_kill_telemetry = __esm({
8558
8686
  });
8559
8687
 
8560
8688
  // src/lib/project-name.ts
8561
- import { execSync as execSync4 } from "child_process";
8689
+ import { execSync as execSync5 } from "child_process";
8562
8690
  import path16 from "path";
8563
8691
  function getProjectName(cwd) {
8564
8692
  const dir = cwd ?? process.cwd();
@@ -8566,7 +8694,7 @@ function getProjectName(cwd) {
8566
8694
  try {
8567
8695
  let repoRoot;
8568
8696
  try {
8569
- const gitCommonDir = execSync4("git rev-parse --path-format=absolute --git-common-dir", {
8697
+ const gitCommonDir = execSync5("git rev-parse --path-format=absolute --git-common-dir", {
8570
8698
  cwd: dir,
8571
8699
  encoding: "utf8",
8572
8700
  timeout: 2e3,
@@ -8574,7 +8702,7 @@ function getProjectName(cwd) {
8574
8702
  }).trim();
8575
8703
  repoRoot = path16.dirname(gitCommonDir);
8576
8704
  } catch {
8577
- repoRoot = execSync4("git rev-parse --show-toplevel", {
8705
+ repoRoot = execSync5("git rev-parse --show-toplevel", {
8578
8706
  cwd: dir,
8579
8707
  encoding: "utf8",
8580
8708
  timeout: 2e3,
@@ -8665,7 +8793,7 @@ var init_session_scope = __esm({
8665
8793
  import crypto6 from "crypto";
8666
8794
  import path17 from "path";
8667
8795
  import os12 from "os";
8668
- import { execSync as execSync5 } from "child_process";
8796
+ import { execSync as execSync6 } from "child_process";
8669
8797
  import { mkdir as mkdir4, writeFile as writeFile4, appendFile } from "fs/promises";
8670
8798
  import { existsSync as existsSync14, readFileSync as readFileSync12 } from "fs";
8671
8799
  async function writeCheckpoint(input) {
@@ -9010,14 +9138,14 @@ function isTmuxSessionAlive(identifier) {
9010
9138
  if (!identifier || identifier === "unknown") return true;
9011
9139
  try {
9012
9140
  if (identifier.startsWith("%")) {
9013
- const output = execSync5("tmux list-panes -a -F '#{pane_id}'", {
9141
+ const output = execSync6("tmux list-panes -a -F '#{pane_id}'", {
9014
9142
  timeout: 2e3,
9015
9143
  encoding: "utf8",
9016
9144
  stdio: ["pipe", "pipe", "pipe"]
9017
9145
  });
9018
9146
  return output.split("\n").some((l) => l.trim() === identifier);
9019
9147
  } else {
9020
- execSync5(`tmux has-session -t ${JSON.stringify(identifier)}`, {
9148
+ execSync6(`tmux has-session -t ${JSON.stringify(identifier)}`, {
9021
9149
  timeout: 2e3,
9022
9150
  stdio: ["pipe", "pipe", "pipe"]
9023
9151
  });
@@ -9026,7 +9154,7 @@ function isTmuxSessionAlive(identifier) {
9026
9154
  } catch {
9027
9155
  if (identifier.startsWith("%")) return true;
9028
9156
  try {
9029
- execSync5("tmux list-sessions", {
9157
+ execSync6("tmux list-sessions", {
9030
9158
  timeout: 2e3,
9031
9159
  stdio: ["pipe", "pipe", "pipe"]
9032
9160
  });
@@ -9041,12 +9169,12 @@ function checkStaleCompletion(taskContext, taskCreatedAt) {
9041
9169
  if (!DELEGATION_KEYWORDS.test(taskContext)) return null;
9042
9170
  try {
9043
9171
  const since = new Date(taskCreatedAt).toISOString();
9044
- const branch = execSync5(
9172
+ const branch = execSync6(
9045
9173
  "git rev-parse --abbrev-ref HEAD 2>/dev/null",
9046
9174
  { encoding: "utf8", timeout: 3e3 }
9047
9175
  ).trim();
9048
9176
  const branchArg = branch && branch !== "HEAD" ? branch : "";
9049
- const commitCount = execSync5(
9177
+ const commitCount = execSync6(
9050
9178
  `git log --oneline --since="${since}" ${branchArg} 2>/dev/null | wc -l`,
9051
9179
  { encoding: "utf8", timeout: 5e3 }
9052
9180
  ).trim();
@@ -10576,7 +10704,7 @@ __export(tmux_routing_exports, {
10576
10704
  spawnEmployee: () => spawnEmployee,
10577
10705
  verifyPaneAtCapacity: () => verifyPaneAtCapacity
10578
10706
  });
10579
- import { execFileSync as execFileSync2, execSync as execSync6 } from "child_process";
10707
+ import { execFileSync as execFileSync2, execSync as execSync7 } from "child_process";
10580
10708
  import { readFileSync as readFileSync13, writeFileSync as writeFileSync8, mkdirSync as mkdirSync8, existsSync as existsSync16, appendFileSync, readdirSync as readdirSync4 } from "fs";
10581
10709
  import path21 from "path";
10582
10710
  import os13 from "os";
@@ -11286,7 +11414,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
11286
11414
  let booted = false;
11287
11415
  for (let i = 0; i < 30; i++) {
11288
11416
  try {
11289
- execSync6("sleep 0.5");
11417
+ execSync7("sleep 0.5");
11290
11418
  } catch {
11291
11419
  }
11292
11420
  try {
@@ -13208,6 +13336,20 @@ init_employees();
13208
13336
  var CONFIG_DIR = process.env.EXE_GATEWAY_HOME || path23.join(os15.homedir(), ".exe-os");
13209
13337
  var CONFIG_PATH3 = process.env.EXE_GATEWAY_CONFIG || path23.join(CONFIG_DIR, "gateway.json");
13210
13338
  var DEFAULT_PORT = 3100;
13339
+ var LOCAL_SIGNAL_HTTP_HOSTS = /^(localhost|127\.0\.0\.1|::1|exe-signal-cli|signal-cli)$/i;
13340
+ function assertSecureSignalUrl(endpoint) {
13341
+ let parsed;
13342
+ try {
13343
+ parsed = new URL(endpoint);
13344
+ } catch {
13345
+ throw new Error(`Malformed Signal URL rejected: "${endpoint}".`);
13346
+ }
13347
+ if (parsed.protocol === "https:") return;
13348
+ if (parsed.protocol === "http:" && LOCAL_SIGNAL_HTTP_HOSTS.test(parsed.hostname)) return;
13349
+ throw new Error(
13350
+ `Insecure Signal URL rejected: "${endpoint}". Use https:// for remote hosts. Plain http:// is only allowed for localhost or Docker-internal signal services.`
13351
+ );
13352
+ }
13211
13353
  function validateApiRouterProductionEnv(env = process.env, logger = console) {
13212
13354
  if (env.NODE_ENV !== "production") return;
13213
13355
  const apiRouterUrl = env.API_ROUTER_URL;
@@ -13303,7 +13445,11 @@ async function main() {
13303
13445
  platform: "signal",
13304
13446
  permissions: { canRead: true, canWrite: true, canExecute: true },
13305
13447
  credentials: {
13306
- baseUrl: signalAccount?.signalCliUrl ?? "http://exe-signal-cli:8080",
13448
+ baseUrl: (() => {
13449
+ const baseUrl = signalAccount?.signalCliUrl ?? "http://exe-signal-cli:8080";
13450
+ assertSecureSignalUrl(baseUrl);
13451
+ return baseUrl;
13452
+ })(),
13307
13453
  account: signalAccount?.account ?? ""
13308
13454
  }
13309
13455
  });
@@ -13412,5 +13558,6 @@ if (isDirectExecution()) {
13412
13558
  });
13413
13559
  }
13414
13560
  export {
13561
+ assertSecureSignalUrl,
13415
13562
  validateApiRouterProductionEnv
13416
13563
  };