@askexenow/exe-os 0.9.53 → 0.9.55

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 (67) hide show
  1. package/dist/bin/backfill-conversations.js +103 -0
  2. package/dist/bin/backfill-responses.js +103 -0
  3. package/dist/bin/backfill-vectors.js +103 -0
  4. package/dist/bin/cleanup-stale-review-tasks.js +103 -0
  5. package/dist/bin/cli.js +121 -10
  6. package/dist/bin/exe-assign.js +103 -0
  7. package/dist/bin/exe-boot.js +96 -10
  8. package/dist/bin/exe-call.js +25 -0
  9. package/dist/bin/exe-cloud.js +31 -10
  10. package/dist/bin/exe-dispatch.js +103 -0
  11. package/dist/bin/exe-doctor.js +152 -3
  12. package/dist/bin/exe-export-behaviors.js +103 -0
  13. package/dist/bin/exe-forget.js +103 -0
  14. package/dist/bin/exe-gateway.js +103 -0
  15. package/dist/bin/exe-heartbeat.js +103 -0
  16. package/dist/bin/exe-kill.js +103 -0
  17. package/dist/bin/exe-launch-agent.js +103 -0
  18. package/dist/bin/exe-link.js +31 -10
  19. package/dist/bin/exe-new-employee.js +25 -0
  20. package/dist/bin/exe-pending-messages.js +103 -0
  21. package/dist/bin/exe-pending-notifications.js +103 -0
  22. package/dist/bin/exe-pending-reviews.js +103 -0
  23. package/dist/bin/exe-rename.js +103 -0
  24. package/dist/bin/exe-review.js +103 -0
  25. package/dist/bin/exe-search.js +103 -0
  26. package/dist/bin/exe-session-cleanup.js +103 -0
  27. package/dist/bin/exe-start-codex.js +103 -0
  28. package/dist/bin/exe-start-opencode.js +103 -0
  29. package/dist/bin/exe-status.js +103 -0
  30. package/dist/bin/exe-team.js +103 -0
  31. package/dist/bin/git-sweep.js +103 -0
  32. package/dist/bin/graph-backfill.js +103 -0
  33. package/dist/bin/graph-export.js +103 -0
  34. package/dist/bin/intercom-check.js +103 -0
  35. package/dist/bin/scan-tasks.js +103 -0
  36. package/dist/bin/setup.js +56 -10
  37. package/dist/bin/shard-migrate.js +103 -0
  38. package/dist/gateway/index.js +103 -0
  39. package/dist/hooks/bug-report-worker.js +103 -0
  40. package/dist/hooks/codex-stop-task-finalizer.js +103 -0
  41. package/dist/hooks/commit-complete.js +103 -0
  42. package/dist/hooks/error-recall.js +103 -0
  43. package/dist/hooks/ingest.js +103 -0
  44. package/dist/hooks/instructions-loaded.js +103 -0
  45. package/dist/hooks/notification.js +103 -0
  46. package/dist/hooks/post-compact.js +103 -0
  47. package/dist/hooks/post-tool-combined.js +103 -0
  48. package/dist/hooks/pre-compact.js +103 -0
  49. package/dist/hooks/pre-tool-use.js +103 -0
  50. package/dist/hooks/prompt-submit.js +103 -0
  51. package/dist/hooks/session-end.js +103 -0
  52. package/dist/hooks/session-start.js +103 -0
  53. package/dist/hooks/stop.js +103 -0
  54. package/dist/hooks/subagent-stop.js +103 -0
  55. package/dist/hooks/summary-worker.js +96 -10
  56. package/dist/index.js +103 -0
  57. package/dist/lib/cloud-sync.js +31 -10
  58. package/dist/lib/employee-templates.js +25 -0
  59. package/dist/lib/exe-daemon.js +165 -14
  60. package/dist/lib/hybrid-search.js +103 -0
  61. package/dist/lib/keychain.js +31 -10
  62. package/dist/lib/schedules.js +103 -0
  63. package/dist/lib/store.js +103 -0
  64. package/dist/mcp/server.js +164 -13
  65. package/dist/runtime/index.js +103 -0
  66. package/dist/tui/App.js +96 -10
  67. package/package.json +1 -1
@@ -6686,6 +6686,15 @@ function readMachineId() {
6686
6686
  return "";
6687
6687
  }
6688
6688
  }
6689
+ function encryptWithMachineKey(plaintext, machineKey) {
6690
+ const crypto8 = __require("crypto");
6691
+ const iv = crypto8.randomBytes(12);
6692
+ const cipher = crypto8.createCipheriv("aes-256-gcm", machineKey, iv);
6693
+ let encrypted = cipher.update(plaintext, "utf-8", "base64");
6694
+ encrypted += cipher.final("base64");
6695
+ const authTag = cipher.getAuthTag().toString("base64");
6696
+ return `${ENCRYPTED_PREFIX}${iv.toString("base64")}:${authTag}:${encrypted}`;
6697
+ }
6689
6698
  function decryptWithMachineKey(encrypted, machineKey) {
6690
6699
  if (!encrypted.startsWith(ENCRYPTED_PREFIX)) return null;
6691
6700
  try {
@@ -6704,6 +6713,21 @@ function decryptWithMachineKey(encrypted, machineKey) {
6704
6713
  return null;
6705
6714
  }
6706
6715
  }
6716
+ async function writeMachineBoundFileFallback(b64) {
6717
+ const dir = getKeyDir();
6718
+ await mkdir4(dir, { recursive: true });
6719
+ const keyPath = getKeyPath();
6720
+ const machineKey = deriveMachineKey();
6721
+ if (machineKey) {
6722
+ const encrypted = encryptWithMachineKey(b64, machineKey);
6723
+ await writeFile5(keyPath, encrypted + "\n", "utf-8");
6724
+ await chmod2(keyPath, 384);
6725
+ return "encrypted";
6726
+ }
6727
+ await writeFile5(keyPath, b64 + "\n", "utf-8");
6728
+ await chmod2(keyPath, 384);
6729
+ return "plaintext";
6730
+ }
6707
6731
  async function getMasterKey() {
6708
6732
  const nativeValue = macKeychainGet() ?? linuxSecretGet();
6709
6733
  if (nativeValue) {
@@ -6755,6 +6779,20 @@ async function getMasterKey() {
6755
6779
  const migrated = macKeychainSet(b64Value) || linuxSecretSet(b64Value);
6756
6780
  if (migrated) {
6757
6781
  process.stderr.write("[keychain] Migrated key from file to native keychain.\n");
6782
+ try {
6783
+ await unlink(keyPath);
6784
+ process.stderr.write("[keychain] Removed legacy master.key file after native keychain migration.\n");
6785
+ } catch {
6786
+ }
6787
+ } else if (!content.startsWith(ENCRYPTED_PREFIX)) {
6788
+ const fallback = await writeMachineBoundFileFallback(b64Value);
6789
+ if (fallback === "encrypted") {
6790
+ process.stderr.write("[keychain] Upgraded legacy plaintext master.key to machine-bound encrypted fallback.\n");
6791
+ } else {
6792
+ process.stderr.write(
6793
+ "[keychain] WARNING: Could not encrypt legacy master.key \u2014 plaintext fallback remains.\n"
6794
+ );
6795
+ }
6758
6796
  }
6759
6797
  return key;
6760
6798
  } catch (err) {
@@ -6972,6 +7010,7 @@ var init_memory_write_governor = __esm({
6972
7010
  // src/lib/shard-manager.ts
6973
7011
  var shard_manager_exports = {};
6974
7012
  __export(shard_manager_exports, {
7013
+ auditShardHealth: () => auditShardHealth,
6975
7014
  disposeShards: () => disposeShards,
6976
7015
  ensureShardSchema: () => ensureShardSchema,
6977
7016
  getOpenShardCount: () => getOpenShardCount,
@@ -7038,6 +7077,70 @@ function listShards() {
7038
7077
  if (!existsSync16(SHARDS_DIR)) return [];
7039
7078
  return readdirSync4(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
7040
7079
  }
7080
+ async function auditShardHealth(options = {}) {
7081
+ if (!_encryptionKey) {
7082
+ throw new Error("Shard manager not initialized. Call initShardManager() first.");
7083
+ }
7084
+ const repair = options.repair === true;
7085
+ const dryRun = options.dryRun === true;
7086
+ const names = listShards();
7087
+ const shards = [];
7088
+ for (const name of names) {
7089
+ const dbPath = path20.join(SHARDS_DIR, `${name}.db`);
7090
+ const stat = statSync2(dbPath);
7091
+ const item = {
7092
+ name,
7093
+ path: dbPath,
7094
+ ok: false,
7095
+ unreadable: false,
7096
+ error: null,
7097
+ size: stat.size,
7098
+ mtime: stat.mtime.toISOString(),
7099
+ memoryCount: null
7100
+ };
7101
+ const client = createClient2({
7102
+ url: `file:${dbPath}`,
7103
+ encryptionKey: _encryptionKey
7104
+ });
7105
+ try {
7106
+ await client.execute("SELECT COUNT(*) as cnt FROM sqlite_schema");
7107
+ const hasMemories = await client.execute(
7108
+ "SELECT COUNT(*) as cnt FROM sqlite_schema WHERE type = 'table' AND name = 'memories'"
7109
+ );
7110
+ if (Number(hasMemories.rows[0]?.cnt ?? 0) > 0) {
7111
+ const mem = await client.execute("SELECT COUNT(*) as cnt FROM memories");
7112
+ item.memoryCount = Number(mem.rows[0]?.cnt ?? 0);
7113
+ }
7114
+ item.ok = true;
7115
+ } catch (err) {
7116
+ const message = err instanceof Error ? err.message : String(err);
7117
+ item.error = message;
7118
+ item.unreadable = /SQLITE_NOTADB|file is not a database/i.test(message);
7119
+ if (item.unreadable && repair && !dryRun) {
7120
+ client.close();
7121
+ _shards.delete(name);
7122
+ _shardLastAccess.delete(name);
7123
+ const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
7124
+ const archivedPath = path20.join(SHARDS_DIR, `${name}.db.broken-${stamp}`);
7125
+ renameSync4(dbPath, archivedPath);
7126
+ item.archivedPath = archivedPath;
7127
+ }
7128
+ } finally {
7129
+ try {
7130
+ client.close();
7131
+ } catch {
7132
+ }
7133
+ }
7134
+ shards.push(item);
7135
+ }
7136
+ return {
7137
+ total: shards.length,
7138
+ ok: shards.filter((s) => s.ok).length,
7139
+ unreadable: shards.filter((s) => s.unreadable).length,
7140
+ archived: shards.filter((s) => Boolean(s.archivedPath)).length,
7141
+ shards
7142
+ };
7143
+ }
7041
7144
  async function ensureShardSchema(client) {
7042
7145
  await client.execute("PRAGMA journal_mode = WAL");
7043
7146
  await client.execute("PRAGMA busy_timeout = 30000");
package/dist/tui/App.js CHANGED
@@ -10555,6 +10555,21 @@ function decryptWithMachineKey(encrypted, machineKey) {
10555
10555
  return null;
10556
10556
  }
10557
10557
  }
10558
+ async function writeMachineBoundFileFallback(b64) {
10559
+ const dir = getKeyDir();
10560
+ await mkdir4(dir, { recursive: true });
10561
+ const keyPath = getKeyPath();
10562
+ const machineKey = deriveMachineKey();
10563
+ if (machineKey) {
10564
+ const encrypted = encryptWithMachineKey(b64, machineKey);
10565
+ await writeFile5(keyPath, encrypted + "\n", "utf-8");
10566
+ await chmod2(keyPath, 384);
10567
+ return "encrypted";
10568
+ }
10569
+ await writeFile5(keyPath, b64 + "\n", "utf-8");
10570
+ await chmod2(keyPath, 384);
10571
+ return "plaintext";
10572
+ }
10558
10573
  async function getMasterKey() {
10559
10574
  const nativeValue = macKeychainGet() ?? linuxSecretGet();
10560
10575
  if (nativeValue) {
@@ -10606,6 +10621,20 @@ async function getMasterKey() {
10606
10621
  const migrated = macKeychainSet(b64Value) || linuxSecretSet(b64Value);
10607
10622
  if (migrated) {
10608
10623
  process.stderr.write("[keychain] Migrated key from file to native keychain.\n");
10624
+ try {
10625
+ await unlink(keyPath);
10626
+ process.stderr.write("[keychain] Removed legacy master.key file after native keychain migration.\n");
10627
+ } catch {
10628
+ }
10629
+ } else if (!content.startsWith(ENCRYPTED_PREFIX)) {
10630
+ const fallback = await writeMachineBoundFileFallback(b64Value);
10631
+ if (fallback === "encrypted") {
10632
+ process.stderr.write("[keychain] Upgraded legacy plaintext master.key to machine-bound encrypted fallback.\n");
10633
+ } else {
10634
+ process.stderr.write(
10635
+ "[keychain] WARNING: Could not encrypt legacy master.key \u2014 plaintext fallback remains.\n"
10636
+ );
10637
+ }
10609
10638
  }
10610
10639
  return key;
10611
10640
  } catch (err) {
@@ -10629,18 +10658,10 @@ async function setMasterKey(key) {
10629
10658
  } catch {
10630
10659
  }
10631
10660
  }
10632
- const dir = getKeyDir();
10633
- await mkdir4(dir, { recursive: true });
10634
- const keyPath = getKeyPath();
10635
- const machineKey = deriveMachineKey();
10636
- if (machineKey) {
10637
- const encrypted = encryptWithMachineKey(b64, machineKey);
10638
- await writeFile5(keyPath, encrypted + "\n", "utf-8");
10639
- await chmod2(keyPath, 384);
10661
+ const fallback = await writeMachineBoundFileFallback(b64);
10662
+ if (fallback === "encrypted") {
10640
10663
  process.stderr.write("[keychain] Key stored encrypted (machine-bound).\n");
10641
10664
  } else {
10642
- await writeFile5(keyPath, b64 + "\n", "utf-8");
10643
- await chmod2(keyPath, 384);
10644
10665
  process.stderr.write(
10645
10666
  "[keychain] WARNING: Key stored in plaintext file \u2014 no OS keychain available.\n"
10646
10667
  );
@@ -11288,6 +11309,7 @@ var init_memory_write_governor = __esm({
11288
11309
  // src/lib/shard-manager.ts
11289
11310
  var shard_manager_exports = {};
11290
11311
  __export(shard_manager_exports, {
11312
+ auditShardHealth: () => auditShardHealth,
11291
11313
  disposeShards: () => disposeShards,
11292
11314
  ensureShardSchema: () => ensureShardSchema,
11293
11315
  getOpenShardCount: () => getOpenShardCount,
@@ -11354,6 +11376,70 @@ function listShards() {
11354
11376
  if (!existsSync17(SHARDS_DIR)) return [];
11355
11377
  return readdirSync4(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
11356
11378
  }
11379
+ async function auditShardHealth(options = {}) {
11380
+ if (!_encryptionKey) {
11381
+ throw new Error("Shard manager not initialized. Call initShardManager() first.");
11382
+ }
11383
+ const repair = options.repair === true;
11384
+ const dryRun = options.dryRun === true;
11385
+ const names = listShards();
11386
+ const shards = [];
11387
+ for (const name of names) {
11388
+ const dbPath = path27.join(SHARDS_DIR, `${name}.db`);
11389
+ const stat = statSync2(dbPath);
11390
+ const item = {
11391
+ name,
11392
+ path: dbPath,
11393
+ ok: false,
11394
+ unreadable: false,
11395
+ error: null,
11396
+ size: stat.size,
11397
+ mtime: stat.mtime.toISOString(),
11398
+ memoryCount: null
11399
+ };
11400
+ const client = createClient2({
11401
+ url: `file:${dbPath}`,
11402
+ encryptionKey: _encryptionKey
11403
+ });
11404
+ try {
11405
+ await client.execute("SELECT COUNT(*) as cnt FROM sqlite_schema");
11406
+ const hasMemories = await client.execute(
11407
+ "SELECT COUNT(*) as cnt FROM sqlite_schema WHERE type = 'table' AND name = 'memories'"
11408
+ );
11409
+ if (Number(hasMemories.rows[0]?.cnt ?? 0) > 0) {
11410
+ const mem = await client.execute("SELECT COUNT(*) as cnt FROM memories");
11411
+ item.memoryCount = Number(mem.rows[0]?.cnt ?? 0);
11412
+ }
11413
+ item.ok = true;
11414
+ } catch (err) {
11415
+ const message = err instanceof Error ? err.message : String(err);
11416
+ item.error = message;
11417
+ item.unreadable = /SQLITE_NOTADB|file is not a database/i.test(message);
11418
+ if (item.unreadable && repair && !dryRun) {
11419
+ client.close();
11420
+ _shards.delete(name);
11421
+ _shardLastAccess.delete(name);
11422
+ const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
11423
+ const archivedPath = path27.join(SHARDS_DIR, `${name}.db.broken-${stamp}`);
11424
+ renameSync4(dbPath, archivedPath);
11425
+ item.archivedPath = archivedPath;
11426
+ }
11427
+ } finally {
11428
+ try {
11429
+ client.close();
11430
+ } catch {
11431
+ }
11432
+ }
11433
+ shards.push(item);
11434
+ }
11435
+ return {
11436
+ total: shards.length,
11437
+ ok: shards.filter((s) => s.ok).length,
11438
+ unreadable: shards.filter((s) => s.unreadable).length,
11439
+ archived: shards.filter((s) => Boolean(s.archivedPath)).length,
11440
+ shards
11441
+ };
11442
+ }
11357
11443
  async function ensureShardSchema(client) {
11358
11444
  await client.execute("PRAGMA journal_mode = WAL");
11359
11445
  await client.execute("PRAGMA busy_timeout = 30000");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@askexenow/exe-os",
3
- "version": "0.9.53",
3
+ "version": "0.9.55",
4
4
  "description": "AI employee operating system — persistent memory, task management, and multi-agent coordination for Claude Code.",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "type": "module",