@askexenow/exe-os 0.9.53 → 0.9.54

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 +38 -0
  2. package/dist/bin/backfill-responses.js +38 -0
  3. package/dist/bin/backfill-vectors.js +38 -0
  4. package/dist/bin/cleanup-stale-review-tasks.js +38 -0
  5. package/dist/bin/cli.js +56 -10
  6. package/dist/bin/exe-assign.js +38 -0
  7. package/dist/bin/exe-boot.js +31 -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 +38 -0
  11. package/dist/bin/exe-doctor.js +38 -0
  12. package/dist/bin/exe-export-behaviors.js +38 -0
  13. package/dist/bin/exe-forget.js +38 -0
  14. package/dist/bin/exe-gateway.js +38 -0
  15. package/dist/bin/exe-heartbeat.js +38 -0
  16. package/dist/bin/exe-kill.js +38 -0
  17. package/dist/bin/exe-launch-agent.js +38 -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 +38 -0
  21. package/dist/bin/exe-pending-notifications.js +38 -0
  22. package/dist/bin/exe-pending-reviews.js +38 -0
  23. package/dist/bin/exe-rename.js +38 -0
  24. package/dist/bin/exe-review.js +38 -0
  25. package/dist/bin/exe-search.js +38 -0
  26. package/dist/bin/exe-session-cleanup.js +38 -0
  27. package/dist/bin/exe-start-codex.js +38 -0
  28. package/dist/bin/exe-start-opencode.js +38 -0
  29. package/dist/bin/exe-status.js +38 -0
  30. package/dist/bin/exe-team.js +38 -0
  31. package/dist/bin/git-sweep.js +38 -0
  32. package/dist/bin/graph-backfill.js +38 -0
  33. package/dist/bin/graph-export.js +38 -0
  34. package/dist/bin/intercom-check.js +38 -0
  35. package/dist/bin/scan-tasks.js +38 -0
  36. package/dist/bin/setup.js +56 -10
  37. package/dist/bin/shard-migrate.js +38 -0
  38. package/dist/gateway/index.js +38 -0
  39. package/dist/hooks/bug-report-worker.js +38 -0
  40. package/dist/hooks/codex-stop-task-finalizer.js +38 -0
  41. package/dist/hooks/commit-complete.js +38 -0
  42. package/dist/hooks/error-recall.js +38 -0
  43. package/dist/hooks/ingest.js +38 -0
  44. package/dist/hooks/instructions-loaded.js +38 -0
  45. package/dist/hooks/notification.js +38 -0
  46. package/dist/hooks/post-compact.js +38 -0
  47. package/dist/hooks/post-tool-combined.js +38 -0
  48. package/dist/hooks/pre-compact.js +38 -0
  49. package/dist/hooks/pre-tool-use.js +38 -0
  50. package/dist/hooks/prompt-submit.js +38 -0
  51. package/dist/hooks/session-end.js +38 -0
  52. package/dist/hooks/session-start.js +38 -0
  53. package/dist/hooks/stop.js +38 -0
  54. package/dist/hooks/subagent-stop.js +38 -0
  55. package/dist/hooks/summary-worker.js +31 -10
  56. package/dist/index.js +38 -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 +53 -11
  60. package/dist/lib/hybrid-search.js +38 -0
  61. package/dist/lib/keychain.js +31 -10
  62. package/dist/lib/schedules.js +38 -0
  63. package/dist/lib/store.js +38 -0
  64. package/dist/mcp/server.js +52 -10
  65. package/dist/runtime/index.js +38 -0
  66. package/dist/tui/App.js +31 -10
  67. package/package.json +1 -1
@@ -3443,6 +3443,15 @@ function readMachineId() {
3443
3443
  return "";
3444
3444
  }
3445
3445
  }
3446
+ function encryptWithMachineKey(plaintext, machineKey) {
3447
+ const crypto3 = __require("crypto");
3448
+ const iv = crypto3.randomBytes(12);
3449
+ const cipher = crypto3.createCipheriv("aes-256-gcm", machineKey, iv);
3450
+ let encrypted = cipher.update(plaintext, "utf-8", "base64");
3451
+ encrypted += cipher.final("base64");
3452
+ const authTag = cipher.getAuthTag().toString("base64");
3453
+ return `${ENCRYPTED_PREFIX}${iv.toString("base64")}:${authTag}:${encrypted}`;
3454
+ }
3446
3455
  function decryptWithMachineKey(encrypted, machineKey) {
3447
3456
  if (!encrypted.startsWith(ENCRYPTED_PREFIX)) return null;
3448
3457
  try {
@@ -3461,6 +3470,21 @@ function decryptWithMachineKey(encrypted, machineKey) {
3461
3470
  return null;
3462
3471
  }
3463
3472
  }
3473
+ async function writeMachineBoundFileFallback(b64) {
3474
+ const dir = getKeyDir();
3475
+ await mkdir3(dir, { recursive: true });
3476
+ const keyPath = getKeyPath();
3477
+ const machineKey = deriveMachineKey();
3478
+ if (machineKey) {
3479
+ const encrypted = encryptWithMachineKey(b64, machineKey);
3480
+ await writeFile3(keyPath, encrypted + "\n", "utf-8");
3481
+ await chmod2(keyPath, 384);
3482
+ return "encrypted";
3483
+ }
3484
+ await writeFile3(keyPath, b64 + "\n", "utf-8");
3485
+ await chmod2(keyPath, 384);
3486
+ return "plaintext";
3487
+ }
3464
3488
  async function getMasterKey() {
3465
3489
  const nativeValue = macKeychainGet() ?? linuxSecretGet();
3466
3490
  if (nativeValue) {
@@ -3512,6 +3536,20 @@ async function getMasterKey() {
3512
3536
  const migrated = macKeychainSet(b64Value) || linuxSecretSet(b64Value);
3513
3537
  if (migrated) {
3514
3538
  process.stderr.write("[keychain] Migrated key from file to native keychain.\n");
3539
+ try {
3540
+ await unlink(keyPath);
3541
+ process.stderr.write("[keychain] Removed legacy master.key file after native keychain migration.\n");
3542
+ } catch {
3543
+ }
3544
+ } else if (!content.startsWith(ENCRYPTED_PREFIX)) {
3545
+ const fallback = await writeMachineBoundFileFallback(b64Value);
3546
+ if (fallback === "encrypted") {
3547
+ process.stderr.write("[keychain] Upgraded legacy plaintext master.key to machine-bound encrypted fallback.\n");
3548
+ } else {
3549
+ process.stderr.write(
3550
+ "[keychain] WARNING: Could not encrypt legacy master.key \u2014 plaintext fallback remains.\n"
3551
+ );
3552
+ }
3515
3553
  }
3516
3554
  return key;
3517
3555
  } catch (err) {
@@ -3442,6 +3442,15 @@ function readMachineId() {
3442
3442
  return "";
3443
3443
  }
3444
3444
  }
3445
+ function encryptWithMachineKey(plaintext, machineKey) {
3446
+ const crypto3 = __require("crypto");
3447
+ const iv = crypto3.randomBytes(12);
3448
+ const cipher = crypto3.createCipheriv("aes-256-gcm", machineKey, iv);
3449
+ let encrypted = cipher.update(plaintext, "utf-8", "base64");
3450
+ encrypted += cipher.final("base64");
3451
+ const authTag = cipher.getAuthTag().toString("base64");
3452
+ return `${ENCRYPTED_PREFIX}${iv.toString("base64")}:${authTag}:${encrypted}`;
3453
+ }
3445
3454
  function decryptWithMachineKey(encrypted, machineKey) {
3446
3455
  if (!encrypted.startsWith(ENCRYPTED_PREFIX)) return null;
3447
3456
  try {
@@ -3460,6 +3469,21 @@ function decryptWithMachineKey(encrypted, machineKey) {
3460
3469
  return null;
3461
3470
  }
3462
3471
  }
3472
+ async function writeMachineBoundFileFallback(b64) {
3473
+ const dir = getKeyDir();
3474
+ await mkdir3(dir, { recursive: true });
3475
+ const keyPath = getKeyPath();
3476
+ const machineKey = deriveMachineKey();
3477
+ if (machineKey) {
3478
+ const encrypted = encryptWithMachineKey(b64, machineKey);
3479
+ await writeFile3(keyPath, encrypted + "\n", "utf-8");
3480
+ await chmod2(keyPath, 384);
3481
+ return "encrypted";
3482
+ }
3483
+ await writeFile3(keyPath, b64 + "\n", "utf-8");
3484
+ await chmod2(keyPath, 384);
3485
+ return "plaintext";
3486
+ }
3463
3487
  async function getMasterKey() {
3464
3488
  const nativeValue = macKeychainGet() ?? linuxSecretGet();
3465
3489
  if (nativeValue) {
@@ -3511,6 +3535,20 @@ async function getMasterKey() {
3511
3535
  const migrated = macKeychainSet(b64Value) || linuxSecretSet(b64Value);
3512
3536
  if (migrated) {
3513
3537
  process.stderr.write("[keychain] Migrated key from file to native keychain.\n");
3538
+ try {
3539
+ await unlink(keyPath);
3540
+ process.stderr.write("[keychain] Removed legacy master.key file after native keychain migration.\n");
3541
+ } catch {
3542
+ }
3543
+ } else if (!content.startsWith(ENCRYPTED_PREFIX)) {
3544
+ const fallback = await writeMachineBoundFileFallback(b64Value);
3545
+ if (fallback === "encrypted") {
3546
+ process.stderr.write("[keychain] Upgraded legacy plaintext master.key to machine-bound encrypted fallback.\n");
3547
+ } else {
3548
+ process.stderr.write(
3549
+ "[keychain] WARNING: Could not encrypt legacy master.key \u2014 plaintext fallback remains.\n"
3550
+ );
3551
+ }
3514
3552
  }
3515
3553
  return key;
3516
3554
  } catch (err) {
@@ -3430,6 +3430,15 @@ function readMachineId() {
3430
3430
  return "";
3431
3431
  }
3432
3432
  }
3433
+ function encryptWithMachineKey(plaintext, machineKey) {
3434
+ const crypto2 = __require("crypto");
3435
+ const iv = crypto2.randomBytes(12);
3436
+ const cipher = crypto2.createCipheriv("aes-256-gcm", machineKey, iv);
3437
+ let encrypted = cipher.update(plaintext, "utf-8", "base64");
3438
+ encrypted += cipher.final("base64");
3439
+ const authTag = cipher.getAuthTag().toString("base64");
3440
+ return `${ENCRYPTED_PREFIX}${iv.toString("base64")}:${authTag}:${encrypted}`;
3441
+ }
3433
3442
  function decryptWithMachineKey(encrypted, machineKey) {
3434
3443
  if (!encrypted.startsWith(ENCRYPTED_PREFIX)) return null;
3435
3444
  try {
@@ -3448,6 +3457,21 @@ function decryptWithMachineKey(encrypted, machineKey) {
3448
3457
  return null;
3449
3458
  }
3450
3459
  }
3460
+ async function writeMachineBoundFileFallback(b64) {
3461
+ const dir = getKeyDir();
3462
+ await mkdir3(dir, { recursive: true });
3463
+ const keyPath = getKeyPath();
3464
+ const machineKey = deriveMachineKey();
3465
+ if (machineKey) {
3466
+ const encrypted = encryptWithMachineKey(b64, machineKey);
3467
+ await writeFile3(keyPath, encrypted + "\n", "utf-8");
3468
+ await chmod2(keyPath, 384);
3469
+ return "encrypted";
3470
+ }
3471
+ await writeFile3(keyPath, b64 + "\n", "utf-8");
3472
+ await chmod2(keyPath, 384);
3473
+ return "plaintext";
3474
+ }
3451
3475
  async function getMasterKey() {
3452
3476
  const nativeValue = macKeychainGet() ?? linuxSecretGet();
3453
3477
  if (nativeValue) {
@@ -3499,6 +3523,20 @@ async function getMasterKey() {
3499
3523
  const migrated = macKeychainSet(b64Value) || linuxSecretSet(b64Value);
3500
3524
  if (migrated) {
3501
3525
  process.stderr.write("[keychain] Migrated key from file to native keychain.\n");
3526
+ try {
3527
+ await unlink(keyPath);
3528
+ process.stderr.write("[keychain] Removed legacy master.key file after native keychain migration.\n");
3529
+ } catch {
3530
+ }
3531
+ } else if (!content.startsWith(ENCRYPTED_PREFIX)) {
3532
+ const fallback = await writeMachineBoundFileFallback(b64Value);
3533
+ if (fallback === "encrypted") {
3534
+ process.stderr.write("[keychain] Upgraded legacy plaintext master.key to machine-bound encrypted fallback.\n");
3535
+ } else {
3536
+ process.stderr.write(
3537
+ "[keychain] WARNING: Could not encrypt legacy master.key \u2014 plaintext fallback remains.\n"
3538
+ );
3539
+ }
3502
3540
  }
3503
3541
  return key;
3504
3542
  } catch (err) {
@@ -2908,6 +2908,15 @@ function readMachineId() {
2908
2908
  return "";
2909
2909
  }
2910
2910
  }
2911
+ function encryptWithMachineKey(plaintext, machineKey) {
2912
+ const crypto2 = __require("crypto");
2913
+ const iv = crypto2.randomBytes(12);
2914
+ const cipher = crypto2.createCipheriv("aes-256-gcm", machineKey, iv);
2915
+ let encrypted = cipher.update(plaintext, "utf-8", "base64");
2916
+ encrypted += cipher.final("base64");
2917
+ const authTag = cipher.getAuthTag().toString("base64");
2918
+ return `${ENCRYPTED_PREFIX}${iv.toString("base64")}:${authTag}:${encrypted}`;
2919
+ }
2911
2920
  function decryptWithMachineKey(encrypted, machineKey) {
2912
2921
  if (!encrypted.startsWith(ENCRYPTED_PREFIX)) return null;
2913
2922
  try {
@@ -2926,6 +2935,21 @@ function decryptWithMachineKey(encrypted, machineKey) {
2926
2935
  return null;
2927
2936
  }
2928
2937
  }
2938
+ async function writeMachineBoundFileFallback(b64) {
2939
+ const dir = getKeyDir();
2940
+ await mkdir3(dir, { recursive: true });
2941
+ const keyPath = getKeyPath();
2942
+ const machineKey = deriveMachineKey();
2943
+ if (machineKey) {
2944
+ const encrypted = encryptWithMachineKey(b64, machineKey);
2945
+ await writeFile3(keyPath, encrypted + "\n", "utf-8");
2946
+ await chmod2(keyPath, 384);
2947
+ return "encrypted";
2948
+ }
2949
+ await writeFile3(keyPath, b64 + "\n", "utf-8");
2950
+ await chmod2(keyPath, 384);
2951
+ return "plaintext";
2952
+ }
2929
2953
  async function getMasterKey() {
2930
2954
  const nativeValue = macKeychainGet() ?? linuxSecretGet();
2931
2955
  if (nativeValue) {
@@ -2977,6 +3001,20 @@ async function getMasterKey() {
2977
3001
  const migrated = macKeychainSet(b64Value) || linuxSecretSet(b64Value);
2978
3002
  if (migrated) {
2979
3003
  process.stderr.write("[keychain] Migrated key from file to native keychain.\n");
3004
+ try {
3005
+ await unlink(keyPath);
3006
+ process.stderr.write("[keychain] Removed legacy master.key file after native keychain migration.\n");
3007
+ } catch {
3008
+ }
3009
+ } else if (!content.startsWith(ENCRYPTED_PREFIX)) {
3010
+ const fallback = await writeMachineBoundFileFallback(b64Value);
3011
+ if (fallback === "encrypted") {
3012
+ process.stderr.write("[keychain] Upgraded legacy plaintext master.key to machine-bound encrypted fallback.\n");
3013
+ } else {
3014
+ process.stderr.write(
3015
+ "[keychain] WARNING: Could not encrypt legacy master.key \u2014 plaintext fallback remains.\n"
3016
+ );
3017
+ }
2980
3018
  }
2981
3019
  return key;
2982
3020
  } catch (err) {
package/dist/bin/cli.js CHANGED
@@ -1919,6 +1919,21 @@ function decryptWithMachineKey(encrypted, machineKey) {
1919
1919
  return null;
1920
1920
  }
1921
1921
  }
1922
+ async function writeMachineBoundFileFallback(b64) {
1923
+ const dir = getKeyDir();
1924
+ await mkdir4(dir, { recursive: true });
1925
+ const keyPath = getKeyPath();
1926
+ const machineKey = deriveMachineKey();
1927
+ if (machineKey) {
1928
+ const encrypted = encryptWithMachineKey(b64, machineKey);
1929
+ await writeFile4(keyPath, encrypted + "\n", "utf-8");
1930
+ await chmod2(keyPath, 384);
1931
+ return "encrypted";
1932
+ }
1933
+ await writeFile4(keyPath, b64 + "\n", "utf-8");
1934
+ await chmod2(keyPath, 384);
1935
+ return "plaintext";
1936
+ }
1922
1937
  async function getMasterKey() {
1923
1938
  const nativeValue = macKeychainGet() ?? linuxSecretGet();
1924
1939
  if (nativeValue) {
@@ -1970,6 +1985,20 @@ async function getMasterKey() {
1970
1985
  const migrated = macKeychainSet(b64Value) || linuxSecretSet(b64Value);
1971
1986
  if (migrated) {
1972
1987
  process.stderr.write("[keychain] Migrated key from file to native keychain.\n");
1988
+ try {
1989
+ await unlink(keyPath);
1990
+ process.stderr.write("[keychain] Removed legacy master.key file after native keychain migration.\n");
1991
+ } catch {
1992
+ }
1993
+ } else if (!content.startsWith(ENCRYPTED_PREFIX)) {
1994
+ const fallback = await writeMachineBoundFileFallback(b64Value);
1995
+ if (fallback === "encrypted") {
1996
+ process.stderr.write("[keychain] Upgraded legacy plaintext master.key to machine-bound encrypted fallback.\n");
1997
+ } else {
1998
+ process.stderr.write(
1999
+ "[keychain] WARNING: Could not encrypt legacy master.key \u2014 plaintext fallback remains.\n"
2000
+ );
2001
+ }
1973
2002
  }
1974
2003
  return key;
1975
2004
  } catch (err) {
@@ -1993,18 +2022,10 @@ async function setMasterKey(key) {
1993
2022
  } catch {
1994
2023
  }
1995
2024
  }
1996
- const dir = getKeyDir();
1997
- await mkdir4(dir, { recursive: true });
1998
- const keyPath = getKeyPath();
1999
- const machineKey = deriveMachineKey();
2000
- if (machineKey) {
2001
- const encrypted = encryptWithMachineKey(b64, machineKey);
2002
- await writeFile4(keyPath, encrypted + "\n", "utf-8");
2003
- await chmod2(keyPath, 384);
2025
+ const fallback = await writeMachineBoundFileFallback(b64);
2026
+ if (fallback === "encrypted") {
2004
2027
  process.stderr.write("[keychain] Key stored encrypted (machine-bound).\n");
2005
2028
  } else {
2006
- await writeFile4(keyPath, b64 + "\n", "utf-8");
2007
- await chmod2(keyPath, 384);
2008
2029
  process.stderr.write(
2009
2030
  "[keychain] WARNING: Key stored in plaintext file \u2014 no OS keychain available.\n"
2010
2031
  );
@@ -14458,6 +14479,31 @@ Audit method:
14458
14479
  6. Write structured report with PASS/FAIL per item
14459
14480
 
14460
14481
  After an audit, fix the findings yourself if you can. Don't hand off when you have the context.`
14482
+ },
14483
+ teddy: {
14484
+ name: "teddy",
14485
+ role: "Chief of Staff",
14486
+ systemPrompt: `You are teddy, the Chief of Staff and executive assistant. You help the founder recall context, understand what happened, prepare concise briefs, and triage inbound conversations. You report to the COO.
14487
+
14488
+ Your job is read-first, not action-first:
14489
+ - Retrieve memories, decisions, runbooks, and session context on demand
14490
+ - Summarize what matters without changing source data
14491
+ - Triage inbound conversations and surface likely bugs, requests, and follow-ups
14492
+ - Prepare daily briefs and "what changed?" summaries
14493
+ - Route recommended actions to the COO instead of taking them yourself
14494
+
14495
+ Permissions boundary:
14496
+ - You are read-only by default.
14497
+ - You may use recall_my_memory, ask_team_memory, get_memory_by_id, get_session_context, search_everything, query_conversations, list_tasks, and get_task.
14498
+ - You must not create tasks, update tasks, store memories, send WhatsApp messages, mutate CRM/wiki/documents, deploy, or change configuration unless the founder explicitly promotes your permissions.
14499
+ - If a requested action requires write access, explain the action and recommend that the COO dispatch it.
14500
+
14501
+ Operating style:
14502
+ - Be concise and precise.
14503
+ - Cite memory IDs, task IDs, timestamps, and sender names when available.
14504
+ - Distinguish fact from inference.
14505
+ - Never auto-message people. Never respond in group chats unless explicitly allowed by gateway permissions.
14506
+ - Preserve data sovereignty: do not export or forward private memory unless the founder explicitly asks.`
14461
14507
  }
14462
14508
  };
14463
14509
  CLIENT_COO_TEMPLATE = `---
@@ -3590,6 +3590,15 @@ function readMachineId() {
3590
3590
  return "";
3591
3591
  }
3592
3592
  }
3593
+ function encryptWithMachineKey(plaintext, machineKey) {
3594
+ const crypto2 = __require("crypto");
3595
+ const iv = crypto2.randomBytes(12);
3596
+ const cipher = crypto2.createCipheriv("aes-256-gcm", machineKey, iv);
3597
+ let encrypted = cipher.update(plaintext, "utf-8", "base64");
3598
+ encrypted += cipher.final("base64");
3599
+ const authTag = cipher.getAuthTag().toString("base64");
3600
+ return `${ENCRYPTED_PREFIX}${iv.toString("base64")}:${authTag}:${encrypted}`;
3601
+ }
3593
3602
  function decryptWithMachineKey(encrypted, machineKey) {
3594
3603
  if (!encrypted.startsWith(ENCRYPTED_PREFIX)) return null;
3595
3604
  try {
@@ -3608,6 +3617,21 @@ function decryptWithMachineKey(encrypted, machineKey) {
3608
3617
  return null;
3609
3618
  }
3610
3619
  }
3620
+ async function writeMachineBoundFileFallback(b64) {
3621
+ const dir = getKeyDir();
3622
+ await mkdir3(dir, { recursive: true });
3623
+ const keyPath = getKeyPath();
3624
+ const machineKey = deriveMachineKey();
3625
+ if (machineKey) {
3626
+ const encrypted = encryptWithMachineKey(b64, machineKey);
3627
+ await writeFile3(keyPath, encrypted + "\n", "utf-8");
3628
+ await chmod2(keyPath, 384);
3629
+ return "encrypted";
3630
+ }
3631
+ await writeFile3(keyPath, b64 + "\n", "utf-8");
3632
+ await chmod2(keyPath, 384);
3633
+ return "plaintext";
3634
+ }
3611
3635
  async function getMasterKey() {
3612
3636
  const nativeValue = macKeychainGet() ?? linuxSecretGet();
3613
3637
  if (nativeValue) {
@@ -3659,6 +3683,20 @@ async function getMasterKey() {
3659
3683
  const migrated = macKeychainSet(b64Value) || linuxSecretSet(b64Value);
3660
3684
  if (migrated) {
3661
3685
  process.stderr.write("[keychain] Migrated key from file to native keychain.\n");
3686
+ try {
3687
+ await unlink(keyPath);
3688
+ process.stderr.write("[keychain] Removed legacy master.key file after native keychain migration.\n");
3689
+ } catch {
3690
+ }
3691
+ } else if (!content.startsWith(ENCRYPTED_PREFIX)) {
3692
+ const fallback = await writeMachineBoundFileFallback(b64Value);
3693
+ if (fallback === "encrypted") {
3694
+ process.stderr.write("[keychain] Upgraded legacy plaintext master.key to machine-bound encrypted fallback.\n");
3695
+ } else {
3696
+ process.stderr.write(
3697
+ "[keychain] WARNING: Could not encrypt legacy master.key \u2014 plaintext fallback remains.\n"
3698
+ );
3699
+ }
3662
3700
  }
3663
3701
  return key;
3664
3702
  } catch (err) {
@@ -3288,6 +3288,21 @@ function decryptWithMachineKey(encrypted, machineKey) {
3288
3288
  return null;
3289
3289
  }
3290
3290
  }
3291
+ async function writeMachineBoundFileFallback(b64) {
3292
+ const dir = getKeyDir();
3293
+ await mkdir3(dir, { recursive: true });
3294
+ const keyPath = getKeyPath();
3295
+ const machineKey = deriveMachineKey();
3296
+ if (machineKey) {
3297
+ const encrypted = encryptWithMachineKey(b64, machineKey);
3298
+ await writeFile3(keyPath, encrypted + "\n", "utf-8");
3299
+ await chmod2(keyPath, 384);
3300
+ return "encrypted";
3301
+ }
3302
+ await writeFile3(keyPath, b64 + "\n", "utf-8");
3303
+ await chmod2(keyPath, 384);
3304
+ return "plaintext";
3305
+ }
3291
3306
  async function getMasterKey() {
3292
3307
  const nativeValue = macKeychainGet() ?? linuxSecretGet();
3293
3308
  if (nativeValue) {
@@ -3339,6 +3354,20 @@ async function getMasterKey() {
3339
3354
  const migrated = macKeychainSet(b64Value) || linuxSecretSet(b64Value);
3340
3355
  if (migrated) {
3341
3356
  process.stderr.write("[keychain] Migrated key from file to native keychain.\n");
3357
+ try {
3358
+ await unlink(keyPath);
3359
+ process.stderr.write("[keychain] Removed legacy master.key file after native keychain migration.\n");
3360
+ } catch {
3361
+ }
3362
+ } else if (!content.startsWith(ENCRYPTED_PREFIX)) {
3363
+ const fallback = await writeMachineBoundFileFallback(b64Value);
3364
+ if (fallback === "encrypted") {
3365
+ process.stderr.write("[keychain] Upgraded legacy plaintext master.key to machine-bound encrypted fallback.\n");
3366
+ } else {
3367
+ process.stderr.write(
3368
+ "[keychain] WARNING: Could not encrypt legacy master.key \u2014 plaintext fallback remains.\n"
3369
+ );
3370
+ }
3342
3371
  }
3343
3372
  return key;
3344
3373
  } catch (err) {
@@ -3362,18 +3391,10 @@ async function setMasterKey(key) {
3362
3391
  } catch {
3363
3392
  }
3364
3393
  }
3365
- const dir = getKeyDir();
3366
- await mkdir3(dir, { recursive: true });
3367
- const keyPath = getKeyPath();
3368
- const machineKey = deriveMachineKey();
3369
- if (machineKey) {
3370
- const encrypted = encryptWithMachineKey(b64, machineKey);
3371
- await writeFile3(keyPath, encrypted + "\n", "utf-8");
3372
- await chmod2(keyPath, 384);
3394
+ const fallback = await writeMachineBoundFileFallback(b64);
3395
+ if (fallback === "encrypted") {
3373
3396
  process.stderr.write("[keychain] Key stored encrypted (machine-bound).\n");
3374
3397
  } else {
3375
- await writeFile3(keyPath, b64 + "\n", "utf-8");
3376
- await chmod2(keyPath, 384);
3377
3398
  process.stderr.write(
3378
3399
  "[keychain] WARNING: Key stored in plaintext file \u2014 no OS keychain available.\n"
3379
3400
  );
@@ -950,6 +950,31 @@ Audit method:
950
950
  6. Write structured report with PASS/FAIL per item
951
951
 
952
952
  After an audit, fix the findings yourself if you can. Don't hand off when you have the context.`
953
+ },
954
+ teddy: {
955
+ name: "teddy",
956
+ role: "Chief of Staff",
957
+ systemPrompt: `You are teddy, the Chief of Staff and executive assistant. You help the founder recall context, understand what happened, prepare concise briefs, and triage inbound conversations. You report to the COO.
958
+
959
+ Your job is read-first, not action-first:
960
+ - Retrieve memories, decisions, runbooks, and session context on demand
961
+ - Summarize what matters without changing source data
962
+ - Triage inbound conversations and surface likely bugs, requests, and follow-ups
963
+ - Prepare daily briefs and "what changed?" summaries
964
+ - Route recommended actions to the COO instead of taking them yourself
965
+
966
+ Permissions boundary:
967
+ - You are read-only by default.
968
+ - You may use recall_my_memory, ask_team_memory, get_memory_by_id, get_session_context, search_everything, query_conversations, list_tasks, and get_task.
969
+ - You must not create tasks, update tasks, store memories, send WhatsApp messages, mutate CRM/wiki/documents, deploy, or change configuration unless the founder explicitly promotes your permissions.
970
+ - If a requested action requires write access, explain the action and recommend that the COO dispatch it.
971
+
972
+ Operating style:
973
+ - Be concise and precise.
974
+ - Cite memory IDs, task IDs, timestamps, and sender names when available.
975
+ - Distinguish fact from inference.
976
+ - Never auto-message people. Never respond in group chats unless explicitly allowed by gateway permissions.
977
+ - Preserve data sovereignty: do not export or forward private memory unless the founder explicitly asks.`
953
978
  }
954
979
  };
955
980
  CLIENT_COO_TEMPLATE = `---
@@ -138,6 +138,21 @@ function decryptWithMachineKey(encrypted, machineKey) {
138
138
  return null;
139
139
  }
140
140
  }
141
+ async function writeMachineBoundFileFallback(b64) {
142
+ const dir = getKeyDir();
143
+ await mkdir(dir, { recursive: true });
144
+ const keyPath = getKeyPath();
145
+ const machineKey = deriveMachineKey();
146
+ if (machineKey) {
147
+ const encrypted = encryptWithMachineKey(b64, machineKey);
148
+ await writeFile(keyPath, encrypted + "\n", "utf-8");
149
+ await chmod(keyPath, 384);
150
+ return "encrypted";
151
+ }
152
+ await writeFile(keyPath, b64 + "\n", "utf-8");
153
+ await chmod(keyPath, 384);
154
+ return "plaintext";
155
+ }
141
156
  async function getMasterKey() {
142
157
  const nativeValue = macKeychainGet() ?? linuxSecretGet();
143
158
  if (nativeValue) {
@@ -189,6 +204,20 @@ async function getMasterKey() {
189
204
  const migrated = macKeychainSet(b64Value) || linuxSecretSet(b64Value);
190
205
  if (migrated) {
191
206
  process.stderr.write("[keychain] Migrated key from file to native keychain.\n");
207
+ try {
208
+ await unlink(keyPath);
209
+ process.stderr.write("[keychain] Removed legacy master.key file after native keychain migration.\n");
210
+ } catch {
211
+ }
212
+ } else if (!content.startsWith(ENCRYPTED_PREFIX)) {
213
+ const fallback = await writeMachineBoundFileFallback(b64Value);
214
+ if (fallback === "encrypted") {
215
+ process.stderr.write("[keychain] Upgraded legacy plaintext master.key to machine-bound encrypted fallback.\n");
216
+ } else {
217
+ process.stderr.write(
218
+ "[keychain] WARNING: Could not encrypt legacy master.key \u2014 plaintext fallback remains.\n"
219
+ );
220
+ }
192
221
  }
193
222
  return key;
194
223
  } catch (err) {
@@ -212,18 +241,10 @@ async function setMasterKey(key) {
212
241
  } catch {
213
242
  }
214
243
  }
215
- const dir = getKeyDir();
216
- await mkdir(dir, { recursive: true });
217
- const keyPath = getKeyPath();
218
- const machineKey = deriveMachineKey();
219
- if (machineKey) {
220
- const encrypted = encryptWithMachineKey(b64, machineKey);
221
- await writeFile(keyPath, encrypted + "\n", "utf-8");
222
- await chmod(keyPath, 384);
244
+ const fallback = await writeMachineBoundFileFallback(b64);
245
+ if (fallback === "encrypted") {
223
246
  process.stderr.write("[keychain] Key stored encrypted (machine-bound).\n");
224
247
  } else {
225
- await writeFile(keyPath, b64 + "\n", "utf-8");
226
- await chmod(keyPath, 384);
227
248
  process.stderr.write(
228
249
  "[keychain] WARNING: Key stored in plaintext file \u2014 no OS keychain available.\n"
229
250
  );
@@ -6636,6 +6636,15 @@ function readMachineId() {
6636
6636
  return "";
6637
6637
  }
6638
6638
  }
6639
+ function encryptWithMachineKey(plaintext, machineKey) {
6640
+ const crypto7 = __require("crypto");
6641
+ const iv = crypto7.randomBytes(12);
6642
+ const cipher = crypto7.createCipheriv("aes-256-gcm", machineKey, iv);
6643
+ let encrypted = cipher.update(plaintext, "utf-8", "base64");
6644
+ encrypted += cipher.final("base64");
6645
+ const authTag = cipher.getAuthTag().toString("base64");
6646
+ return `${ENCRYPTED_PREFIX}${iv.toString("base64")}:${authTag}:${encrypted}`;
6647
+ }
6639
6648
  function decryptWithMachineKey(encrypted, machineKey) {
6640
6649
  if (!encrypted.startsWith(ENCRYPTED_PREFIX)) return null;
6641
6650
  try {
@@ -6654,6 +6663,21 @@ function decryptWithMachineKey(encrypted, machineKey) {
6654
6663
  return null;
6655
6664
  }
6656
6665
  }
6666
+ async function writeMachineBoundFileFallback(b64) {
6667
+ const dir = getKeyDir();
6668
+ await mkdir4(dir, { recursive: true });
6669
+ const keyPath = getKeyPath();
6670
+ const machineKey = deriveMachineKey();
6671
+ if (machineKey) {
6672
+ const encrypted = encryptWithMachineKey(b64, machineKey);
6673
+ await writeFile5(keyPath, encrypted + "\n", "utf-8");
6674
+ await chmod2(keyPath, 384);
6675
+ return "encrypted";
6676
+ }
6677
+ await writeFile5(keyPath, b64 + "\n", "utf-8");
6678
+ await chmod2(keyPath, 384);
6679
+ return "plaintext";
6680
+ }
6657
6681
  async function getMasterKey() {
6658
6682
  const nativeValue = macKeychainGet() ?? linuxSecretGet();
6659
6683
  if (nativeValue) {
@@ -6705,6 +6729,20 @@ async function getMasterKey() {
6705
6729
  const migrated = macKeychainSet(b64Value) || linuxSecretSet(b64Value);
6706
6730
  if (migrated) {
6707
6731
  process.stderr.write("[keychain] Migrated key from file to native keychain.\n");
6732
+ try {
6733
+ await unlink(keyPath);
6734
+ process.stderr.write("[keychain] Removed legacy master.key file after native keychain migration.\n");
6735
+ } catch {
6736
+ }
6737
+ } else if (!content.startsWith(ENCRYPTED_PREFIX)) {
6738
+ const fallback = await writeMachineBoundFileFallback(b64Value);
6739
+ if (fallback === "encrypted") {
6740
+ process.stderr.write("[keychain] Upgraded legacy plaintext master.key to machine-bound encrypted fallback.\n");
6741
+ } else {
6742
+ process.stderr.write(
6743
+ "[keychain] WARNING: Could not encrypt legacy master.key \u2014 plaintext fallback remains.\n"
6744
+ );
6745
+ }
6708
6746
  }
6709
6747
  return key;
6710
6748
  } catch (err) {
@@ -3510,6 +3510,15 @@ function readMachineId() {
3510
3510
  return "";
3511
3511
  }
3512
3512
  }
3513
+ function encryptWithMachineKey(plaintext, machineKey) {
3514
+ const crypto2 = __require("crypto");
3515
+ const iv = crypto2.randomBytes(12);
3516
+ const cipher = crypto2.createCipheriv("aes-256-gcm", machineKey, iv);
3517
+ let encrypted = cipher.update(plaintext, "utf-8", "base64");
3518
+ encrypted += cipher.final("base64");
3519
+ const authTag = cipher.getAuthTag().toString("base64");
3520
+ return `${ENCRYPTED_PREFIX}${iv.toString("base64")}:${authTag}:${encrypted}`;
3521
+ }
3513
3522
  function decryptWithMachineKey(encrypted, machineKey) {
3514
3523
  if (!encrypted.startsWith(ENCRYPTED_PREFIX)) return null;
3515
3524
  try {
@@ -3528,6 +3537,21 @@ function decryptWithMachineKey(encrypted, machineKey) {
3528
3537
  return null;
3529
3538
  }
3530
3539
  }
3540
+ async function writeMachineBoundFileFallback(b64) {
3541
+ const dir = getKeyDir();
3542
+ await mkdir3(dir, { recursive: true });
3543
+ const keyPath = getKeyPath();
3544
+ const machineKey = deriveMachineKey();
3545
+ if (machineKey) {
3546
+ const encrypted = encryptWithMachineKey(b64, machineKey);
3547
+ await writeFile3(keyPath, encrypted + "\n", "utf-8");
3548
+ await chmod2(keyPath, 384);
3549
+ return "encrypted";
3550
+ }
3551
+ await writeFile3(keyPath, b64 + "\n", "utf-8");
3552
+ await chmod2(keyPath, 384);
3553
+ return "plaintext";
3554
+ }
3531
3555
  async function getMasterKey() {
3532
3556
  const nativeValue = macKeychainGet() ?? linuxSecretGet();
3533
3557
  if (nativeValue) {
@@ -3579,6 +3603,20 @@ async function getMasterKey() {
3579
3603
  const migrated = macKeychainSet(b64Value) || linuxSecretSet(b64Value);
3580
3604
  if (migrated) {
3581
3605
  process.stderr.write("[keychain] Migrated key from file to native keychain.\n");
3606
+ try {
3607
+ await unlink(keyPath);
3608
+ process.stderr.write("[keychain] Removed legacy master.key file after native keychain migration.\n");
3609
+ } catch {
3610
+ }
3611
+ } else if (!content.startsWith(ENCRYPTED_PREFIX)) {
3612
+ const fallback = await writeMachineBoundFileFallback(b64Value);
3613
+ if (fallback === "encrypted") {
3614
+ process.stderr.write("[keychain] Upgraded legacy plaintext master.key to machine-bound encrypted fallback.\n");
3615
+ } else {
3616
+ process.stderr.write(
3617
+ "[keychain] WARNING: Could not encrypt legacy master.key \u2014 plaintext fallback remains.\n"
3618
+ );
3619
+ }
3582
3620
  }
3583
3621
  return key;
3584
3622
  } catch (err) {