@askexenow/exe-os 0.8.83 → 0.8.86

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/dist/bin/backfill-conversations.js +746 -595
  2. package/dist/bin/backfill-responses.js +745 -594
  3. package/dist/bin/backfill-vectors.js +312 -226
  4. package/dist/bin/cleanup-stale-review-tasks.js +154 -21
  5. package/dist/bin/cli.js +14678 -12676
  6. package/dist/bin/exe-agent-config.js +242 -0
  7. package/dist/bin/exe-agent.js +100 -91
  8. package/dist/bin/exe-assign.js +1003 -854
  9. package/dist/bin/exe-boot.js +1420 -485
  10. package/dist/bin/exe-call.js +10 -0
  11. package/dist/bin/exe-cloud.js +29 -6
  12. package/dist/bin/exe-dispatch.js +572 -271
  13. package/dist/bin/exe-doctor.js +403 -6
  14. package/dist/bin/exe-export-behaviors.js +175 -72
  15. package/dist/bin/exe-forget.js +102 -3
  16. package/dist/bin/exe-gateway.js +796 -292
  17. package/dist/bin/exe-healthcheck.js +134 -1
  18. package/dist/bin/exe-heartbeat.js +172 -36
  19. package/dist/bin/exe-kill.js +175 -72
  20. package/dist/bin/exe-launch-agent.js +189 -76
  21. package/dist/bin/exe-link.js +927 -82
  22. package/dist/bin/exe-new-employee.js +60 -8
  23. package/dist/bin/exe-pending-messages.js +151 -19
  24. package/dist/bin/exe-pending-notifications.js +97 -2
  25. package/dist/bin/exe-pending-reviews.js +155 -22
  26. package/dist/bin/exe-rename.js +564 -23
  27. package/dist/bin/exe-review.js +231 -73
  28. package/dist/bin/exe-search.js +995 -228
  29. package/dist/bin/exe-session-cleanup.js +4930 -1664
  30. package/dist/bin/exe-settings.js +20 -5
  31. package/dist/bin/exe-start-codex.js +2598 -0
  32. package/dist/bin/exe-start.sh +15 -3
  33. package/dist/bin/exe-status.js +154 -21
  34. package/dist/bin/exe-team.js +97 -2
  35. package/dist/bin/git-sweep.js +1180 -363
  36. package/dist/bin/graph-backfill.js +175 -72
  37. package/dist/bin/graph-export.js +175 -72
  38. package/dist/bin/install.js +60 -7
  39. package/dist/bin/list-providers.js +1 -0
  40. package/dist/bin/scan-tasks.js +1185 -367
  41. package/dist/bin/setup.js +914 -270
  42. package/dist/bin/shard-migrate.js +175 -72
  43. package/dist/bin/update.js +1 -0
  44. package/dist/bin/wiki-sync.js +175 -72
  45. package/dist/gateway/index.js +792 -285
  46. package/dist/hooks/bug-report-worker.js +445 -135
  47. package/dist/hooks/commit-complete.js +1178 -361
  48. package/dist/hooks/error-recall.js +994 -228
  49. package/dist/hooks/ingest-worker.js +1799 -1234
  50. package/dist/hooks/ingest.js +3 -0
  51. package/dist/hooks/instructions-loaded.js +707 -97
  52. package/dist/hooks/notification.js +699 -89
  53. package/dist/hooks/post-compact.js +757 -109
  54. package/dist/hooks/pre-compact.js +1061 -244
  55. package/dist/hooks/pre-tool-use.js +787 -130
  56. package/dist/hooks/prompt-ingest-worker.js +242 -101
  57. package/dist/hooks/prompt-submit.js +1121 -299
  58. package/dist/hooks/response-ingest-worker.js +242 -101
  59. package/dist/hooks/session-end.js +4063 -397
  60. package/dist/hooks/session-start.js +1071 -254
  61. package/dist/hooks/stop.js +768 -120
  62. package/dist/hooks/subagent-stop.js +757 -109
  63. package/dist/hooks/summary-worker.js +1706 -1011
  64. package/dist/index.js +1821 -1098
  65. package/dist/lib/agent-config.js +167 -0
  66. package/dist/lib/cloud-sync.js +932 -88
  67. package/dist/lib/consolidation.js +2 -1
  68. package/dist/lib/database.js +642 -87
  69. package/dist/lib/db-daemon-client.js +503 -0
  70. package/dist/lib/device-registry.js +547 -7
  71. package/dist/lib/embedder.js +14 -28
  72. package/dist/lib/employee-templates.js +84 -74
  73. package/dist/lib/employees.js +9 -0
  74. package/dist/lib/exe-daemon-client.js +16 -29
  75. package/dist/lib/exe-daemon.js +2733 -1575
  76. package/dist/lib/hybrid-search.js +995 -228
  77. package/dist/lib/identity.js +87 -67
  78. package/dist/lib/keychain.js +9 -1
  79. package/dist/lib/messaging.js +103 -40
  80. package/dist/lib/reminders.js +91 -74
  81. package/dist/lib/runtime-table.js +16 -0
  82. package/dist/lib/schedules.js +96 -2
  83. package/dist/lib/session-wrappers.js +22 -0
  84. package/dist/lib/skill-learning.js +103 -85
  85. package/dist/lib/store.js +234 -73
  86. package/dist/lib/tasks.js +348 -134
  87. package/dist/lib/tmux-routing.js +422 -208
  88. package/dist/lib/token-spend.js +273 -0
  89. package/dist/lib/ws-client.js +11 -0
  90. package/dist/mcp/server.js +5742 -696
  91. package/dist/mcp/tools/complete-reminder.js +94 -77
  92. package/dist/mcp/tools/create-reminder.js +94 -77
  93. package/dist/mcp/tools/create-task.js +375 -152
  94. package/dist/mcp/tools/deactivate-behavior.js +95 -77
  95. package/dist/mcp/tools/list-reminders.js +94 -77
  96. package/dist/mcp/tools/list-tasks.js +99 -31
  97. package/dist/mcp/tools/send-message.js +108 -45
  98. package/dist/mcp/tools/update-task.js +162 -77
  99. package/dist/runtime/index.js +1075 -258
  100. package/dist/tui/App.js +1333 -506
  101. package/package.json +6 -1
  102. package/src/commands/exe/agent-config.md +27 -0
  103. package/src/commands/exe/cc-doctor.md +10 -0
@@ -163,15 +163,22 @@ function getClient() {
163
163
  if (!_resilientClient) {
164
164
  throw new Error("Database client not initialized. Call initDatabase() first.");
165
165
  }
166
+ if (process.env.EXE_IS_DAEMON === "1") {
167
+ return _resilientClient;
168
+ }
169
+ if (_daemonClient && _daemonClient._isDaemonActive()) {
170
+ return _daemonClient;
171
+ }
166
172
  return _resilientClient;
167
173
  }
168
- var _resilientClient;
174
+ var _resilientClient, _daemonClient;
169
175
  var init_database = __esm({
170
176
  "src/lib/database.ts"() {
171
177
  "use strict";
172
178
  init_db_retry();
173
179
  init_employees();
174
180
  _resilientClient = null;
181
+ _daemonClient = null;
175
182
  }
176
183
  });
177
184
 
@@ -357,18 +364,54 @@ var init_provider_table = __esm({
357
364
  }
358
365
  });
359
366
 
360
- // src/lib/intercom-queue.ts
361
- import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, renameSync as renameSync3, existsSync as existsSync3, mkdirSync } from "fs";
367
+ // src/lib/runtime-table.ts
368
+ var RUNTIME_TABLE;
369
+ var init_runtime_table = __esm({
370
+ "src/lib/runtime-table.ts"() {
371
+ "use strict";
372
+ RUNTIME_TABLE = {
373
+ codex: {
374
+ binary: "codex",
375
+ launchMode: "exec",
376
+ autoApproveFlag: "--full-auto",
377
+ inlineFlag: "--no-alt-screen",
378
+ apiKeyEnv: "OPENAI_API_KEY",
379
+ defaultModel: "gpt-5.4"
380
+ }
381
+ };
382
+ }
383
+ });
384
+
385
+ // src/lib/agent-config.ts
386
+ import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, existsSync as existsSync3, mkdirSync } from "fs";
362
387
  import path4 from "path";
388
+ var AGENT_CONFIG_PATH, DEFAULT_MODELS;
389
+ var init_agent_config = __esm({
390
+ "src/lib/agent-config.ts"() {
391
+ "use strict";
392
+ init_config();
393
+ init_runtime_table();
394
+ AGENT_CONFIG_PATH = path4.join(EXE_AI_DIR, "agent-config.json");
395
+ DEFAULT_MODELS = {
396
+ claude: "claude-opus-4",
397
+ codex: RUNTIME_TABLE.codex?.defaultModel ?? "gpt-5.4",
398
+ opencode: "minimax-m2.7"
399
+ };
400
+ }
401
+ });
402
+
403
+ // src/lib/intercom-queue.ts
404
+ import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, renameSync as renameSync3, existsSync as existsSync4, mkdirSync as mkdirSync2 } from "fs";
405
+ import path5 from "path";
363
406
  import os4 from "os";
364
407
  function ensureDir() {
365
- const dir = path4.dirname(QUEUE_PATH);
366
- if (!existsSync3(dir)) mkdirSync(dir, { recursive: true });
408
+ const dir = path5.dirname(QUEUE_PATH);
409
+ if (!existsSync4(dir)) mkdirSync2(dir, { recursive: true });
367
410
  }
368
411
  function readQueue() {
369
412
  try {
370
- if (!existsSync3(QUEUE_PATH)) return [];
371
- return JSON.parse(readFileSync3(QUEUE_PATH, "utf8"));
413
+ if (!existsSync4(QUEUE_PATH)) return [];
414
+ return JSON.parse(readFileSync4(QUEUE_PATH, "utf8"));
372
415
  } catch {
373
416
  return [];
374
417
  }
@@ -376,7 +419,7 @@ function readQueue() {
376
419
  function writeQueue(queue) {
377
420
  ensureDir();
378
421
  const tmp = `${QUEUE_PATH}.tmp`;
379
- writeFileSync2(tmp, JSON.stringify(queue, null, 2));
422
+ writeFileSync3(tmp, JSON.stringify(queue, null, 2));
380
423
  renameSync3(tmp, QUEUE_PATH);
381
424
  }
382
425
  function queueIntercom(targetSession, reason) {
@@ -400,31 +443,31 @@ var QUEUE_PATH, TTL_MS, INTERCOM_LOG;
400
443
  var init_intercom_queue = __esm({
401
444
  "src/lib/intercom-queue.ts"() {
402
445
  "use strict";
403
- QUEUE_PATH = path4.join(os4.homedir(), ".exe-os", "intercom-queue.json");
446
+ QUEUE_PATH = path5.join(os4.homedir(), ".exe-os", "intercom-queue.json");
404
447
  TTL_MS = 60 * 60 * 1e3;
405
- INTERCOM_LOG = path4.join(os4.homedir(), ".exe-os", "intercom.log");
448
+ INTERCOM_LOG = path5.join(os4.homedir(), ".exe-os", "intercom.log");
406
449
  }
407
450
  });
408
451
 
409
452
  // src/lib/license.ts
410
- import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, existsSync as existsSync4, mkdirSync as mkdirSync2 } from "fs";
453
+ import { readFileSync as readFileSync5, writeFileSync as writeFileSync4, existsSync as existsSync5, mkdirSync as mkdirSync3 } from "fs";
411
454
  import { randomUUID } from "crypto";
412
- import path5 from "path";
455
+ import path6 from "path";
413
456
  import { jwtVerify, importSPKI } from "jose";
414
457
  var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH;
415
458
  var init_license = __esm({
416
459
  "src/lib/license.ts"() {
417
460
  "use strict";
418
461
  init_config();
419
- LICENSE_PATH = path5.join(EXE_AI_DIR, "license.key");
420
- CACHE_PATH = path5.join(EXE_AI_DIR, "license-cache.json");
421
- DEVICE_ID_PATH = path5.join(EXE_AI_DIR, "device-id");
462
+ LICENSE_PATH = path6.join(EXE_AI_DIR, "license.key");
463
+ CACHE_PATH = path6.join(EXE_AI_DIR, "license-cache.json");
464
+ DEVICE_ID_PATH = path6.join(EXE_AI_DIR, "device-id");
422
465
  }
423
466
  });
424
467
 
425
468
  // src/lib/plan-limits.ts
426
- import { readFileSync as readFileSync5, existsSync as existsSync5 } from "fs";
427
- import path6 from "path";
469
+ import { readFileSync as readFileSync6, existsSync as existsSync6 } from "fs";
470
+ import path7 from "path";
428
471
  var CACHE_PATH2;
429
472
  var init_plan_limits = __esm({
430
473
  "src/lib/plan-limits.ts"() {
@@ -433,13 +476,13 @@ var init_plan_limits = __esm({
433
476
  init_employees();
434
477
  init_license();
435
478
  init_config();
436
- CACHE_PATH2 = path6.join(EXE_AI_DIR, "license-cache.json");
479
+ CACHE_PATH2 = path7.join(EXE_AI_DIR, "license-cache.json");
437
480
  }
438
481
  });
439
482
 
440
483
  // src/lib/tmux-routing.ts
441
- import { readFileSync as readFileSync6, writeFileSync as writeFileSync4, mkdirSync as mkdirSync3, existsSync as existsSync6, appendFileSync } from "fs";
442
- import path7 from "path";
484
+ import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, mkdirSync as mkdirSync4, existsSync as existsSync7, appendFileSync } from "fs";
485
+ import path8 from "path";
443
486
  import os5 from "os";
444
487
  import { fileURLToPath } from "url";
445
488
  function getMySession() {
@@ -480,7 +523,7 @@ function extractRootExe(name) {
480
523
  }
481
524
  function getParentExe(sessionKey) {
482
525
  try {
483
- const data = JSON.parse(readFileSync6(path7.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
526
+ const data = JSON.parse(readFileSync7(path8.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
484
527
  return data.parentExe || null;
485
528
  } catch {
486
529
  return null;
@@ -504,32 +547,50 @@ function isEmployeeAlive(sessionName) {
504
547
  }
505
548
  function readDebounceState() {
506
549
  try {
507
- if (!existsSync6(DEBOUNCE_FILE)) return {};
508
- return JSON.parse(readFileSync6(DEBOUNCE_FILE, "utf8"));
550
+ if (!existsSync7(DEBOUNCE_FILE)) return {};
551
+ const raw = JSON.parse(readFileSync7(DEBOUNCE_FILE, "utf8"));
552
+ const state = {};
553
+ for (const [key, val] of Object.entries(raw)) {
554
+ if (typeof val === "number") {
555
+ state[key] = { lastSent: val, pending: 0 };
556
+ } else if (val && typeof val === "object" && "lastSent" in val) {
557
+ state[key] = val;
558
+ }
559
+ }
560
+ return state;
509
561
  } catch {
510
562
  return {};
511
563
  }
512
564
  }
513
565
  function writeDebounceState(state) {
514
566
  try {
515
- if (!existsSync6(SESSION_CACHE)) mkdirSync3(SESSION_CACHE, { recursive: true });
516
- writeFileSync4(DEBOUNCE_FILE, JSON.stringify(state));
567
+ if (!existsSync7(SESSION_CACHE)) mkdirSync4(SESSION_CACHE, { recursive: true });
568
+ writeFileSync5(DEBOUNCE_FILE, JSON.stringify(state));
517
569
  } catch {
518
570
  }
519
571
  }
520
572
  function isDebounced(targetSession) {
521
573
  const state = readDebounceState();
522
- const lastSent = state[targetSession] ?? 0;
523
- return Date.now() - lastSent < INTERCOM_DEBOUNCE_MS;
574
+ const entry = state[targetSession];
575
+ const lastSent = entry?.lastSent ?? 0;
576
+ if (Date.now() - lastSent < INTERCOM_DEBOUNCE_MS) {
577
+ if (!state[targetSession]) state[targetSession] = { lastSent, pending: 0 };
578
+ state[targetSession].pending++;
579
+ writeDebounceState(state);
580
+ return true;
581
+ }
582
+ return false;
524
583
  }
525
584
  function recordDebounce(targetSession) {
526
585
  const state = readDebounceState();
527
- state[targetSession] = Date.now();
586
+ const batched = state[targetSession]?.pending ?? 0;
587
+ state[targetSession] = { lastSent: Date.now(), pending: 0 };
528
588
  const cutoff = Date.now() - DEBOUNCE_CLEANUP_AGE_MS;
529
589
  for (const key of Object.keys(state)) {
530
- if ((state[key] ?? 0) < cutoff) delete state[key];
590
+ if ((state[key]?.lastSent ?? 0) < cutoff) delete state[key];
531
591
  }
532
592
  writeDebounceState(state);
593
+ return batched;
533
594
  }
534
595
  function logIntercom(msg) {
535
596
  const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] ${msg}
@@ -570,7 +631,7 @@ function sendIntercom(targetSession) {
570
631
  return "skipped_exe";
571
632
  }
572
633
  if (isDebounced(targetSession)) {
573
- logIntercom(`DEBOUNCE \u2192 ${targetSession} (cross-process file debounce)`);
634
+ logIntercom(`DEBOUNCE \u2192 ${targetSession} (nudge batched, task safe in DB)`);
574
635
  return "debounced";
575
636
  }
576
637
  try {
@@ -582,14 +643,14 @@ function sendIntercom(targetSession) {
582
643
  const sessionState = getSessionState(targetSession);
583
644
  if (sessionState === "no_claude") {
584
645
  queueIntercom(targetSession, "claude not running in session");
585
- recordDebounce(targetSession);
586
- logIntercom(`QUEUED \u2192 ${targetSession} (no claude process \u2014 raw shell detected)`);
646
+ const batched2 = recordDebounce(targetSession);
647
+ logIntercom(`QUEUED \u2192 ${targetSession} (no claude process)${batched2 > 0 ? ` [${batched2} batched]` : ""}`);
587
648
  return "queued";
588
649
  }
589
650
  if (sessionState === "thinking" || sessionState === "tool") {
590
651
  queueIntercom(targetSession, "session busy at send time");
591
- recordDebounce(targetSession);
592
- logIntercom(`QUEUED \u2192 ${targetSession} (session busy, will retry from queue)`);
652
+ const batched2 = recordDebounce(targetSession);
653
+ logIntercom(`QUEUED \u2192 ${targetSession} (session busy)${batched2 > 0 ? ` [${batched2} batched]` : ""}`);
593
654
  return "queued";
594
655
  }
595
656
  if (transport.isPaneInCopyMode(targetSession)) {
@@ -597,8 +658,8 @@ function sendIntercom(targetSession) {
597
658
  transport.sendKeys(targetSession, "q");
598
659
  }
599
660
  transport.sendKeys(targetSession, "/exe-intercom");
600
- recordDebounce(targetSession);
601
- logIntercom(`DELIVERED \u2192 ${targetSession} (fire-and-forget)`);
661
+ const batched = recordDebounce(targetSession);
662
+ logIntercom(`DELIVERED \u2192 ${targetSession}${batched > 0 ? ` [${batched} nudges batched during debounce]` : ""} (fire-and-forget)`);
602
663
  return "delivered";
603
664
  } catch {
604
665
  logIntercom(`FAIL \u2192 ${targetSession}`);
@@ -615,15 +676,17 @@ var init_tmux_routing = __esm({
615
676
  init_cc_agent_support();
616
677
  init_mcp_prefix();
617
678
  init_provider_table();
679
+ init_agent_config();
680
+ init_runtime_table();
618
681
  init_intercom_queue();
619
682
  init_plan_limits();
620
683
  init_employees();
621
- SPAWN_LOCK_DIR = path7.join(os5.homedir(), ".exe-os", "spawn-locks");
622
- SESSION_CACHE = path7.join(os5.homedir(), ".exe-os", "session-cache");
684
+ SPAWN_LOCK_DIR = path8.join(os5.homedir(), ".exe-os", "spawn-locks");
685
+ SESSION_CACHE = path8.join(os5.homedir(), ".exe-os", "session-cache");
623
686
  VALID_SESSION_NAME = /^[a-z]+\d*-[a-zA-Z0-9_]+$/;
624
687
  INTERCOM_DEBOUNCE_MS = 3e4;
625
- INTERCOM_LOG2 = path7.join(os5.homedir(), ".exe-os", "intercom.log");
626
- DEBOUNCE_FILE = path7.join(SESSION_CACHE, "intercom-debounce.json");
688
+ INTERCOM_LOG2 = path8.join(os5.homedir(), ".exe-os", "intercom.log");
689
+ DEBOUNCE_FILE = path8.join(SESSION_CACHE, "intercom-debounce.json");
627
690
  DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
628
691
  BUSY_PATTERN = /[✻✽✶✳·].*…|Running…/;
629
692
  }
@@ -776,16 +839,16 @@ async function markFailed(messageId, reason) {
776
839
 
777
840
  // src/adapters/claude/active-agent.ts
778
841
  init_config();
779
- import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, mkdirSync as mkdirSync4, unlinkSync as unlinkSync2, readdirSync } from "fs";
842
+ import { readFileSync as readFileSync8, writeFileSync as writeFileSync6, mkdirSync as mkdirSync5, unlinkSync as unlinkSync2, readdirSync } from "fs";
780
843
  import { execSync as execSync4 } from "child_process";
781
- import path8 from "path";
844
+ import path9 from "path";
782
845
 
783
846
  // src/adapters/claude/session-key.ts
784
847
  init_session_key();
785
848
 
786
849
  // src/adapters/claude/active-agent.ts
787
850
  init_employees();
788
- var CACHE_DIR = path8.join(EXE_AI_DIR, "session-cache");
851
+ var CACHE_DIR = path9.join(EXE_AI_DIR, "session-cache");
789
852
  var STALE_MS = 24 * 60 * 60 * 1e3;
790
853
  function isNameWithOptionalInstance(candidate, baseName) {
791
854
  if (candidate === baseName) return true;
@@ -830,12 +893,12 @@ function resolveActiveAgentFromTmuxSession(sessionName) {
830
893
  return null;
831
894
  }
832
895
  function getMarkerPath() {
833
- return path8.join(CACHE_DIR, `active-agent-${getSessionKey()}.json`);
896
+ return path9.join(CACHE_DIR, `active-agent-${getSessionKey()}.json`);
834
897
  }
835
898
  function getActiveAgent() {
836
899
  try {
837
900
  const markerPath = getMarkerPath();
838
- const raw = readFileSync7(markerPath, "utf8");
901
+ const raw = readFileSync8(markerPath, "utf8");
839
902
  const data = JSON.parse(raw);
840
903
  if (data.agentId) {
841
904
  if (data.startedAt) {