@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
@@ -1621,8 +1621,8 @@ function findPackageRoot() {
1621
1621
  function getAvailableMemoryGB() {
1622
1622
  if (process.platform === "darwin") {
1623
1623
  try {
1624
- const { execSync: execSync10 } = __require("child_process");
1625
- const vmstat = execSync10("vm_stat", { encoding: "utf8" });
1624
+ const { execSync: execSync11 } = __require("child_process");
1625
+ const vmstat = execSync11("vm_stat", { encoding: "utf8" });
1626
1626
  const pageSize = 16384;
1627
1627
  const pageSizeMatch = vmstat.match(/page size of (\d+) bytes/);
1628
1628
  const actualPageSize = pageSizeMatch ? parseInt(pageSizeMatch[1], 10) : pageSize;
@@ -6722,6 +6722,7 @@ var init_task_scope = __esm({
6722
6722
  // src/lib/keychain.ts
6723
6723
  import { readFile as readFile4, writeFile as writeFile5, unlink, mkdir as mkdir4, chmod as chmod2 } from "fs/promises";
6724
6724
  import { existsSync as existsSync16 } from "fs";
6725
+ import { execSync as execSync8 } from "child_process";
6725
6726
  import path20 from "path";
6726
6727
  import os12 from "os";
6727
6728
  function getKeyDir() {
@@ -6730,6 +6731,59 @@ function getKeyDir() {
6730
6731
  function getKeyPath() {
6731
6732
  return path20.join(getKeyDir(), "master.key");
6732
6733
  }
6734
+ function macKeychainGet() {
6735
+ if (process.platform !== "darwin") return null;
6736
+ try {
6737
+ return execSync8(
6738
+ `security find-generic-password -s "${SERVICE}" -a "${ACCOUNT}" -w 2>/dev/null`,
6739
+ { encoding: "utf-8", timeout: 5e3 }
6740
+ ).trim();
6741
+ } catch {
6742
+ return null;
6743
+ }
6744
+ }
6745
+ function macKeychainSet(value) {
6746
+ if (process.platform !== "darwin") return false;
6747
+ try {
6748
+ try {
6749
+ execSync8(
6750
+ `security delete-generic-password -s "${SERVICE}" -a "${ACCOUNT}" 2>/dev/null`,
6751
+ { timeout: 5e3 }
6752
+ );
6753
+ } catch {
6754
+ }
6755
+ execSync8(
6756
+ `security add-generic-password -s "${SERVICE}" -a "${ACCOUNT}" -w "${value}"`,
6757
+ { timeout: 5e3 }
6758
+ );
6759
+ return true;
6760
+ } catch {
6761
+ return false;
6762
+ }
6763
+ }
6764
+ function linuxSecretGet() {
6765
+ if (process.platform !== "linux") return null;
6766
+ try {
6767
+ return execSync8(
6768
+ `secret-tool lookup service "${SERVICE}" account "${ACCOUNT}" 2>/dev/null`,
6769
+ { encoding: "utf-8", timeout: 5e3 }
6770
+ ).trim();
6771
+ } catch {
6772
+ return null;
6773
+ }
6774
+ }
6775
+ function linuxSecretSet(value) {
6776
+ if (process.platform !== "linux") return false;
6777
+ try {
6778
+ execSync8(
6779
+ `echo -n "${value}" | secret-tool store --label="exe-os master key" service "${SERVICE}" account "${ACCOUNT}"`,
6780
+ { timeout: 5e3 }
6781
+ );
6782
+ return true;
6783
+ } catch {
6784
+ return false;
6785
+ }
6786
+ }
6733
6787
  async function tryKeytar() {
6734
6788
  try {
6735
6789
  return await import("keytar");
@@ -6737,13 +6791,63 @@ async function tryKeytar() {
6737
6791
  return null;
6738
6792
  }
6739
6793
  }
6794
+ function deriveMachineKey() {
6795
+ try {
6796
+ const crypto7 = __require("crypto");
6797
+ const material = [
6798
+ os12.hostname(),
6799
+ os12.userInfo().username,
6800
+ os12.arch(),
6801
+ os12.platform(),
6802
+ // Machine ID on Linux (stable across reboots)
6803
+ process.platform === "linux" ? readMachineId() : ""
6804
+ ].join("|");
6805
+ return crypto7.createHash("sha256").update(material).digest();
6806
+ } catch {
6807
+ return null;
6808
+ }
6809
+ }
6810
+ function readMachineId() {
6811
+ try {
6812
+ const { readFileSync: readFileSync16 } = __require("fs");
6813
+ return readFileSync16("/etc/machine-id", "utf-8").trim();
6814
+ } catch {
6815
+ return "";
6816
+ }
6817
+ }
6818
+ function decryptWithMachineKey(encrypted, machineKey) {
6819
+ if (!encrypted.startsWith(ENCRYPTED_PREFIX)) return null;
6820
+ try {
6821
+ const crypto7 = __require("crypto");
6822
+ const parts = encrypted.slice(ENCRYPTED_PREFIX.length).split(":");
6823
+ if (parts.length !== 3) return null;
6824
+ const [ivB64, tagB64, cipherB64] = parts;
6825
+ const iv = Buffer.from(ivB64, "base64");
6826
+ const authTag = Buffer.from(tagB64, "base64");
6827
+ const decipher = crypto7.createDecipheriv("aes-256-gcm", machineKey, iv);
6828
+ decipher.setAuthTag(authTag);
6829
+ let decrypted = decipher.update(cipherB64, "base64", "utf-8");
6830
+ decrypted += decipher.final("utf-8");
6831
+ return decrypted;
6832
+ } catch {
6833
+ return null;
6834
+ }
6835
+ }
6740
6836
  async function getMasterKey() {
6837
+ const nativeValue = macKeychainGet() ?? linuxSecretGet();
6838
+ if (nativeValue) {
6839
+ return Buffer.from(nativeValue, "base64");
6840
+ }
6741
6841
  const keytar = await tryKeytar();
6742
6842
  if (keytar) {
6743
6843
  try {
6744
- const stored = await keytar.getPassword(SERVICE, ACCOUNT);
6745
- if (stored) {
6746
- return Buffer.from(stored, "base64");
6844
+ const keytarValue = await keytar.getPassword(SERVICE, ACCOUNT);
6845
+ if (keytarValue) {
6846
+ const migrated = macKeychainSet(keytarValue) || linuxSecretSet(keytarValue);
6847
+ if (migrated) {
6848
+ process.stderr.write("[keychain] Migrated key from keytar to native keychain.\n");
6849
+ }
6850
+ return Buffer.from(keytarValue, "base64");
6747
6851
  }
6748
6852
  } catch {
6749
6853
  }
@@ -6757,8 +6861,31 @@ async function getMasterKey() {
6757
6861
  return null;
6758
6862
  }
6759
6863
  try {
6760
- const content = await readFile4(keyPath, "utf-8");
6761
- return Buffer.from(content.trim(), "base64");
6864
+ const content = (await readFile4(keyPath, "utf-8")).trim();
6865
+ let b64Value;
6866
+ if (content.startsWith(ENCRYPTED_PREFIX)) {
6867
+ const machineKey = deriveMachineKey();
6868
+ if (!machineKey) {
6869
+ process.stderr.write("[keychain] Cannot derive machine key to decrypt stored key.\n");
6870
+ return null;
6871
+ }
6872
+ const decrypted = decryptWithMachineKey(content, machineKey);
6873
+ if (!decrypted) {
6874
+ process.stderr.write(
6875
+ "[keychain] Key decryption failed \u2014 machine may have changed.\n Use your 24-word recovery phrase: exe-os link import\n"
6876
+ );
6877
+ return null;
6878
+ }
6879
+ b64Value = decrypted;
6880
+ } else {
6881
+ b64Value = content;
6882
+ }
6883
+ const key = Buffer.from(b64Value, "base64");
6884
+ const migrated = macKeychainSet(b64Value) || linuxSecretSet(b64Value);
6885
+ if (migrated) {
6886
+ process.stderr.write("[keychain] Migrated key from file to native keychain.\n");
6887
+ }
6888
+ return key;
6762
6889
  } catch (err) {
6763
6890
  process.stderr.write(
6764
6891
  `[keychain] Key read failed at ${keyPath}: ${err instanceof Error ? err.message : String(err)}
@@ -6767,12 +6894,13 @@ async function getMasterKey() {
6767
6894
  return null;
6768
6895
  }
6769
6896
  }
6770
- var SERVICE, ACCOUNT;
6897
+ var SERVICE, ACCOUNT, ENCRYPTED_PREFIX;
6771
6898
  var init_keychain = __esm({
6772
6899
  "src/lib/keychain.ts"() {
6773
6900
  "use strict";
6774
6901
  SERVICE = "exe-mem";
6775
6902
  ACCOUNT = "master-key";
6903
+ ENCRYPTED_PREFIX = "enc:";
6776
6904
  }
6777
6905
  });
6778
6906
 
@@ -8099,11 +8227,11 @@ __export(git_staleness_exports, {
8099
8227
  detectStaleFiles: () => detectStaleFiles,
8100
8228
  recordFileRead: () => recordFileRead
8101
8229
  });
8102
- import { execSync as execSync8 } from "child_process";
8230
+ import { execSync as execSync9 } from "child_process";
8103
8231
  import path23 from "path";
8104
8232
  function getHeadCommit(cwd) {
8105
8233
  try {
8106
- return execSync8("git rev-parse --short HEAD", {
8234
+ return execSync9("git rev-parse --short HEAD", {
8107
8235
  cwd,
8108
8236
  timeout: GIT_TIMEOUT_MS,
8109
8237
  encoding: "utf-8"
@@ -8166,7 +8294,7 @@ async function detectStaleFiles(agentId, cwd) {
8166
8294
  const readAt = String(record.read_at ?? "");
8167
8295
  if (!filePath || !readAt) continue;
8168
8296
  try {
8169
- const gitSummary = execSync8(
8297
+ const gitSummary = execSync9(
8170
8298
  `git log -1 --oneline --after=${JSON.stringify(readAt)} --format="%h %an: %s" -- ${JSON.stringify(filePath)}`,
8171
8299
  {
8172
8300
  cwd,
@@ -8210,7 +8338,7 @@ __export(git_task_sweep_exports, {
8210
8338
  matchScore: () => matchScore,
8211
8339
  sweepTasks: () => sweepTasks
8212
8340
  });
8213
- import { execSync as execSync9 } from "child_process";
8341
+ import { execSync as execSync10 } from "child_process";
8214
8342
  function extractKeywords(text) {
8215
8343
  return text.toLowerCase().replace(/[^a-z0-9\s-]/g, " ").split(/\s+/).filter((w) => w.length >= 3 && !STOP_WORDS.has(w));
8216
8344
  }
@@ -8239,7 +8367,7 @@ function matchScore(task, commitMessage, changedFiles) {
8239
8367
  function getRecentCommits(limit = DEFAULT_COMMIT_LIMIT) {
8240
8368
  try {
8241
8369
  const SEPARATOR = "<<SEP>>";
8242
- const output = execSync9(
8370
+ const output = execSync10(
8243
8371
  `git log --format="%h${SEPARATOR}%s${SEPARATOR}%aI" --name-only -n ${limit} -z`,
8244
8372
  { encoding: "utf8", timeout: 1e4 }
8245
8373
  );
@@ -1439,8 +1439,8 @@ function findPackageRoot() {
1439
1439
  function getAvailableMemoryGB() {
1440
1440
  if (process.platform === "darwin") {
1441
1441
  try {
1442
- const { execSync: execSync9 } = __require("child_process");
1443
- const vmstat = execSync9("vm_stat", { encoding: "utf8" });
1442
+ const { execSync: execSync10 } = __require("child_process");
1443
+ const vmstat = execSync10("vm_stat", { encoding: "utf8" });
1444
1444
  const pageSize = 16384;
1445
1445
  const pageSizeMatch = vmstat.match(/page size of (\d+) bytes/);
1446
1446
  const actualPageSize = pageSizeMatch ? parseInt(pageSizeMatch[1], 10) : pageSize;
@@ -3179,6 +3179,7 @@ var init_database = __esm({
3179
3179
  // src/lib/keychain.ts
3180
3180
  import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
3181
3181
  import { existsSync as existsSync7 } from "fs";
3182
+ import { execSync as execSync2 } from "child_process";
3182
3183
  import path7 from "path";
3183
3184
  import os5 from "os";
3184
3185
  function getKeyDir() {
@@ -3187,6 +3188,59 @@ function getKeyDir() {
3187
3188
  function getKeyPath() {
3188
3189
  return path7.join(getKeyDir(), "master.key");
3189
3190
  }
3191
+ function macKeychainGet() {
3192
+ if (process.platform !== "darwin") return null;
3193
+ try {
3194
+ return execSync2(
3195
+ `security find-generic-password -s "${SERVICE}" -a "${ACCOUNT}" -w 2>/dev/null`,
3196
+ { encoding: "utf-8", timeout: 5e3 }
3197
+ ).trim();
3198
+ } catch {
3199
+ return null;
3200
+ }
3201
+ }
3202
+ function macKeychainSet(value) {
3203
+ if (process.platform !== "darwin") return false;
3204
+ try {
3205
+ try {
3206
+ execSync2(
3207
+ `security delete-generic-password -s "${SERVICE}" -a "${ACCOUNT}" 2>/dev/null`,
3208
+ { timeout: 5e3 }
3209
+ );
3210
+ } catch {
3211
+ }
3212
+ execSync2(
3213
+ `security add-generic-password -s "${SERVICE}" -a "${ACCOUNT}" -w "${value}"`,
3214
+ { timeout: 5e3 }
3215
+ );
3216
+ return true;
3217
+ } catch {
3218
+ return false;
3219
+ }
3220
+ }
3221
+ function linuxSecretGet() {
3222
+ if (process.platform !== "linux") return null;
3223
+ try {
3224
+ return execSync2(
3225
+ `secret-tool lookup service "${SERVICE}" account "${ACCOUNT}" 2>/dev/null`,
3226
+ { encoding: "utf-8", timeout: 5e3 }
3227
+ ).trim();
3228
+ } catch {
3229
+ return null;
3230
+ }
3231
+ }
3232
+ function linuxSecretSet(value) {
3233
+ if (process.platform !== "linux") return false;
3234
+ try {
3235
+ execSync2(
3236
+ `echo -n "${value}" | secret-tool store --label="exe-os master key" service "${SERVICE}" account "${ACCOUNT}"`,
3237
+ { timeout: 5e3 }
3238
+ );
3239
+ return true;
3240
+ } catch {
3241
+ return false;
3242
+ }
3243
+ }
3190
3244
  async function tryKeytar() {
3191
3245
  try {
3192
3246
  return await import("keytar");
@@ -3194,13 +3248,63 @@ async function tryKeytar() {
3194
3248
  return null;
3195
3249
  }
3196
3250
  }
3251
+ function deriveMachineKey() {
3252
+ try {
3253
+ const crypto3 = __require("crypto");
3254
+ const material = [
3255
+ os5.hostname(),
3256
+ os5.userInfo().username,
3257
+ os5.arch(),
3258
+ os5.platform(),
3259
+ // Machine ID on Linux (stable across reboots)
3260
+ process.platform === "linux" ? readMachineId() : ""
3261
+ ].join("|");
3262
+ return crypto3.createHash("sha256").update(material).digest();
3263
+ } catch {
3264
+ return null;
3265
+ }
3266
+ }
3267
+ function readMachineId() {
3268
+ try {
3269
+ const { readFileSync: readFileSync13 } = __require("fs");
3270
+ return readFileSync13("/etc/machine-id", "utf-8").trim();
3271
+ } catch {
3272
+ return "";
3273
+ }
3274
+ }
3275
+ function decryptWithMachineKey(encrypted, machineKey) {
3276
+ if (!encrypted.startsWith(ENCRYPTED_PREFIX)) return null;
3277
+ try {
3278
+ const crypto3 = __require("crypto");
3279
+ const parts = encrypted.slice(ENCRYPTED_PREFIX.length).split(":");
3280
+ if (parts.length !== 3) return null;
3281
+ const [ivB64, tagB64, cipherB64] = parts;
3282
+ const iv = Buffer.from(ivB64, "base64");
3283
+ const authTag = Buffer.from(tagB64, "base64");
3284
+ const decipher = crypto3.createDecipheriv("aes-256-gcm", machineKey, iv);
3285
+ decipher.setAuthTag(authTag);
3286
+ let decrypted = decipher.update(cipherB64, "base64", "utf-8");
3287
+ decrypted += decipher.final("utf-8");
3288
+ return decrypted;
3289
+ } catch {
3290
+ return null;
3291
+ }
3292
+ }
3197
3293
  async function getMasterKey() {
3294
+ const nativeValue = macKeychainGet() ?? linuxSecretGet();
3295
+ if (nativeValue) {
3296
+ return Buffer.from(nativeValue, "base64");
3297
+ }
3198
3298
  const keytar = await tryKeytar();
3199
3299
  if (keytar) {
3200
3300
  try {
3201
- const stored = await keytar.getPassword(SERVICE, ACCOUNT);
3202
- if (stored) {
3203
- return Buffer.from(stored, "base64");
3301
+ const keytarValue = await keytar.getPassword(SERVICE, ACCOUNT);
3302
+ if (keytarValue) {
3303
+ const migrated = macKeychainSet(keytarValue) || linuxSecretSet(keytarValue);
3304
+ if (migrated) {
3305
+ process.stderr.write("[keychain] Migrated key from keytar to native keychain.\n");
3306
+ }
3307
+ return Buffer.from(keytarValue, "base64");
3204
3308
  }
3205
3309
  } catch {
3206
3310
  }
@@ -3214,8 +3318,31 @@ async function getMasterKey() {
3214
3318
  return null;
3215
3319
  }
3216
3320
  try {
3217
- const content = await readFile3(keyPath, "utf-8");
3218
- return Buffer.from(content.trim(), "base64");
3321
+ const content = (await readFile3(keyPath, "utf-8")).trim();
3322
+ let b64Value;
3323
+ if (content.startsWith(ENCRYPTED_PREFIX)) {
3324
+ const machineKey = deriveMachineKey();
3325
+ if (!machineKey) {
3326
+ process.stderr.write("[keychain] Cannot derive machine key to decrypt stored key.\n");
3327
+ return null;
3328
+ }
3329
+ const decrypted = decryptWithMachineKey(content, machineKey);
3330
+ if (!decrypted) {
3331
+ process.stderr.write(
3332
+ "[keychain] Key decryption failed \u2014 machine may have changed.\n Use your 24-word recovery phrase: exe-os link import\n"
3333
+ );
3334
+ return null;
3335
+ }
3336
+ b64Value = decrypted;
3337
+ } else {
3338
+ b64Value = content;
3339
+ }
3340
+ const key = Buffer.from(b64Value, "base64");
3341
+ const migrated = macKeychainSet(b64Value) || linuxSecretSet(b64Value);
3342
+ if (migrated) {
3343
+ process.stderr.write("[keychain] Migrated key from file to native keychain.\n");
3344
+ }
3345
+ return key;
3219
3346
  } catch (err) {
3220
3347
  process.stderr.write(
3221
3348
  `[keychain] Key read failed at ${keyPath}: ${err instanceof Error ? err.message : String(err)}
@@ -3224,12 +3351,13 @@ async function getMasterKey() {
3224
3351
  return null;
3225
3352
  }
3226
3353
  }
3227
- var SERVICE, ACCOUNT;
3354
+ var SERVICE, ACCOUNT, ENCRYPTED_PREFIX;
3228
3355
  var init_keychain = __esm({
3229
3356
  "src/lib/keychain.ts"() {
3230
3357
  "use strict";
3231
3358
  SERVICE = "exe-mem";
3232
3359
  ACCOUNT = "master-key";
3360
+ ENCRYPTED_PREFIX = "enc:";
3233
3361
  }
3234
3362
  });
3235
3363
 
@@ -4752,7 +4880,7 @@ __export(project_name_exports, {
4752
4880
  _resetCache: () => _resetCache,
4753
4881
  getProjectName: () => getProjectName
4754
4882
  });
4755
- import { execSync as execSync2 } from "child_process";
4883
+ import { execSync as execSync3 } from "child_process";
4756
4884
  import path10 from "path";
4757
4885
  function getProjectName(cwd) {
4758
4886
  const dir = cwd ?? process.cwd();
@@ -4760,7 +4888,7 @@ function getProjectName(cwd) {
4760
4888
  try {
4761
4889
  let repoRoot;
4762
4890
  try {
4763
- const gitCommonDir = execSync2("git rev-parse --path-format=absolute --git-common-dir", {
4891
+ const gitCommonDir = execSync3("git rev-parse --path-format=absolute --git-common-dir", {
4764
4892
  cwd: dir,
4765
4893
  encoding: "utf8",
4766
4894
  timeout: 2e3,
@@ -4768,7 +4896,7 @@ function getProjectName(cwd) {
4768
4896
  }).trim();
4769
4897
  repoRoot = path10.dirname(gitCommonDir);
4770
4898
  } catch {
4771
- repoRoot = execSync2("git rev-parse --show-toplevel", {
4899
+ repoRoot = execSync3("git rev-parse --show-toplevel", {
4772
4900
  cwd: dir,
4773
4901
  encoding: "utf8",
4774
4902
  timeout: 2e3,
@@ -4802,14 +4930,14 @@ var file_grep_exports = {};
4802
4930
  __export(file_grep_exports, {
4803
4931
  grepProjectFiles: () => grepProjectFiles
4804
4932
  });
4805
- import { execSync as execSync3 } from "child_process";
4933
+ import { execSync as execSync4 } from "child_process";
4806
4934
  import { readFileSync as readFileSync6, readdirSync as readdirSync2, statSync as statSync2, existsSync as existsSync10 } from "fs";
4807
4935
  import path11 from "path";
4808
4936
  import crypto2 from "crypto";
4809
4937
  function hasRipgrep() {
4810
4938
  if (_hasRg === null) {
4811
4939
  try {
4812
- execSync3("rg --version", { stdio: "ignore", timeout: 2e3 });
4940
+ execSync4("rg --version", { stdio: "ignore", timeout: 2e3 });
4813
4941
  _hasRg = true;
4814
4942
  } catch {
4815
4943
  _hasRg = false;
@@ -4875,7 +5003,7 @@ function grepWithRipgrep(pattern, projectRoot, patterns) {
4875
5003
  const globs = (patterns ?? DEFAULT_PATTERNS).map((p) => `--glob '${p}'`).join(" ");
4876
5004
  const excludes = EXCLUDE_DIRS.map((d) => `--glob '!${d}'`).join(" ");
4877
5005
  const cmd = `rg -i -c --hidden --no-config --no-ignore '${pattern.replace(/'/g, "\\'")}' . ${globs} ${excludes} --max-filesize ${MAX_FILE_SIZE} 2>/dev/null || true`;
4878
- const output = execSync3(cmd, {
5006
+ const output = execSync4(cmd, {
4879
5007
  cwd: projectRoot,
4880
5008
  encoding: "utf8",
4881
5009
  timeout: 3e3,
@@ -4890,12 +5018,12 @@ function grepWithRipgrep(pattern, projectRoot, patterns) {
4890
5018
  const matchCount = parseInt(line.slice(colonIdx + 1));
4891
5019
  if (isNaN(matchCount) || matchCount === 0) continue;
4892
5020
  try {
4893
- const firstMatch = execSync3(
5021
+ const firstMatch = execSync4(
4894
5022
  `rg -i -n --hidden '${pattern.replace(/'/g, "\\'")}' '${filePath}' --max-count 1 2>/dev/null | head -1`,
4895
5023
  { cwd: projectRoot, encoding: "utf8", timeout: 1e3 }
4896
5024
  ).trim();
4897
5025
  const lineNum = parseInt(firstMatch.split(":")[0] ?? "1");
4898
- const totalLines = execSync3(`wc -l < '${filePath}'`, {
5026
+ const totalLines = execSync4(`wc -l < '${filePath}'`, {
4899
5027
  cwd: projectRoot,
4900
5028
  encoding: "utf8",
4901
5029
  timeout: 1e3
@@ -5524,10 +5652,17 @@ async function applyEntityBoost(results, query, client) {
5524
5652
  if (ENTITY_BOOST_WEIGHT === 0 || results.length === 0) {
5525
5653
  return emptyResult;
5526
5654
  }
5527
- console.time("entity-boost");
5655
+ const debugStart = process.env.EXE_DEBUG_HOOKS ? performance.now() : 0;
5656
+ const debugEnd = () => {
5657
+ if (!process.env.EXE_DEBUG_HOOKS) return;
5658
+ process.stderr.write(
5659
+ `[entity-boost] ${(performance.now() - debugStart).toFixed(3)}ms
5660
+ `
5661
+ );
5662
+ };
5528
5663
  const entities = await matchEntities(query, client);
5529
5664
  if (entities.length === 0) {
5530
- console.timeEnd("entity-boost");
5665
+ debugEnd();
5531
5666
  return emptyResult;
5532
5667
  }
5533
5668
  const boostMap = /* @__PURE__ */ new Map();
@@ -5549,7 +5684,7 @@ async function applyEntityBoost(results, query, client) {
5549
5684
  await traverseAndScore(entities, client, boostMap, resultIds, graphContextMap);
5550
5685
  await applyHyperedgeBoost(entities, client, boostMap, resultIds);
5551
5686
  if (boostMap.size === 0) {
5552
- console.timeEnd("entity-boost");
5687
+ debugEnd();
5553
5688
  return emptyResult;
5554
5689
  }
5555
5690
  const scored = results.map((r, i) => ({
@@ -5560,7 +5695,7 @@ async function applyEntityBoost(results, query, client) {
5560
5695
  scored.sort(
5561
5696
  (a, b) => b.baseScore + b.entityBoost - (a.baseScore + a.entityBoost)
5562
5697
  );
5563
- console.timeEnd("entity-boost");
5698
+ debugEnd();
5564
5699
  return {
5565
5700
  results: scored.map((s) => s.record),
5566
5701
  graphContext: graphContextMap
@@ -6205,7 +6340,7 @@ var init_hybrid_search = __esm({
6205
6340
  });
6206
6341
 
6207
6342
  // src/lib/session-key.ts
6208
- import { execSync as execSync4 } from "child_process";
6343
+ import { execSync as execSync5 } from "child_process";
6209
6344
  function normalizeCommand(command) {
6210
6345
  const trimmed = command.trim().toLowerCase();
6211
6346
  const parts = trimmed.split(/[\\/]/);
@@ -6224,7 +6359,7 @@ function resolveRuntimeProcess() {
6224
6359
  let pid = process.ppid;
6225
6360
  for (let i = 0; i < 10; i++) {
6226
6361
  try {
6227
- const info = execSync4(`ps -p ${pid} -o ppid=,comm=`, {
6362
+ const info = execSync5(`ps -p ${pid} -o ppid=,comm=`, {
6228
6363
  encoding: "utf8",
6229
6364
  timeout: 2e3
6230
6365
  }).trim();
@@ -6274,7 +6409,7 @@ var init_session_key = __esm({
6274
6409
 
6275
6410
  // src/lib/active-agent.ts
6276
6411
  import { readFileSync as readFileSync7, writeFileSync as writeFileSync4, mkdirSync as mkdirSync3, unlinkSync as unlinkSync3, readdirSync as readdirSync3 } from "fs";
6277
- import { execSync as execSync5 } from "child_process";
6412
+ import { execSync as execSync6 } from "child_process";
6278
6413
  import path12 from "path";
6279
6414
  function isNameWithOptionalInstance(candidate, baseName) {
6280
6415
  if (candidate === baseName) return true;
@@ -6366,7 +6501,7 @@ function getActiveAgent() {
6366
6501
  } catch {
6367
6502
  }
6368
6503
  try {
6369
- const sessionName = execSync5(
6504
+ const sessionName = execSync6(
6370
6505
  "tmux display-message -p '#{session_name}' 2>/dev/null",
6371
6506
  { encoding: "utf8", timeout: 2e3 }
6372
6507
  ).trim();
@@ -6584,7 +6719,7 @@ var init_transport = __esm({
6584
6719
  });
6585
6720
 
6586
6721
  // src/lib/cc-agent-support.ts
6587
- import { execSync as execSync6 } from "child_process";
6722
+ import { execSync as execSync7 } from "child_process";
6588
6723
  var init_cc_agent_support = __esm({
6589
6724
  "src/lib/cc-agent-support.ts"() {
6590
6725
  "use strict";
@@ -6843,7 +6978,7 @@ var catchup_brief_exports = {};
6843
6978
  __export(catchup_brief_exports, {
6844
6979
  buildCatchupBrief: () => buildCatchupBrief
6845
6980
  });
6846
- import { execSync as execSync7 } from "child_process";
6981
+ import { execSync as execSync8 } from "child_process";
6847
6982
  function clipText(text, maxChars) {
6848
6983
  if (text.length <= maxChars) return text;
6849
6984
  if (maxChars <= 1) return "\u2026";
@@ -6889,7 +7024,7 @@ ${clipText(checkpoint.raw_text, MAX_CHECKPOINT_CHARS)}`
6889
7024
  } catch {
6890
7025
  }
6891
7026
  try {
6892
- const gitLog = execSync7(
7027
+ const gitLog = execSync8(
6893
7028
  `git log --oneline --since=${JSON.stringify(lastTimestamp)} --format="%h %an: %s" | head -10`,
6894
7029
  { cwd, timeout: 3e3, encoding: "utf-8" }
6895
7030
  ).trim();
@@ -6967,11 +7102,11 @@ __export(git_staleness_exports, {
6967
7102
  detectStaleFiles: () => detectStaleFiles,
6968
7103
  recordFileRead: () => recordFileRead
6969
7104
  });
6970
- import { execSync as execSync8 } from "child_process";
7105
+ import { execSync as execSync9 } from "child_process";
6971
7106
  import path18 from "path";
6972
7107
  function getHeadCommit(cwd) {
6973
7108
  try {
6974
- return execSync8("git rev-parse --short HEAD", {
7109
+ return execSync9("git rev-parse --short HEAD", {
6975
7110
  cwd,
6976
7111
  timeout: GIT_TIMEOUT_MS,
6977
7112
  encoding: "utf-8"
@@ -7034,7 +7169,7 @@ async function detectStaleFiles(agentId, cwd) {
7034
7169
  const readAt = String(record.read_at ?? "");
7035
7170
  if (!filePath || !readAt) continue;
7036
7171
  try {
7037
- const gitSummary = execSync8(
7172
+ const gitSummary = execSync9(
7038
7173
  `git log -1 --oneline --after=${JSON.stringify(readAt)} --format="%h %an: %s" -- ${JSON.stringify(filePath)}`,
7039
7174
  {
7040
7175
  cwd,