@askexenow/exe-os 0.9.8 → 0.9.9

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 (101) hide show
  1. package/dist/bin/backfill-conversations.js +222 -49
  2. package/dist/bin/backfill-responses.js +221 -48
  3. package/dist/bin/backfill-vectors.js +225 -52
  4. package/dist/bin/cleanup-stale-review-tasks.js +150 -28
  5. package/dist/bin/cli.js +1295 -856
  6. package/dist/bin/exe-agent-config.js +36 -8
  7. package/dist/bin/exe-agent.js +14 -4
  8. package/dist/bin/exe-assign.js +221 -48
  9. package/dist/bin/exe-boot.js +778 -427
  10. package/dist/bin/exe-call.js +41 -13
  11. package/dist/bin/exe-cloud.js +163 -58
  12. package/dist/bin/exe-dispatch.js +276 -139
  13. package/dist/bin/exe-doctor.js +145 -27
  14. package/dist/bin/exe-export-behaviors.js +141 -23
  15. package/dist/bin/exe-forget.js +137 -19
  16. package/dist/bin/exe-gateway.js +677 -388
  17. package/dist/bin/exe-heartbeat.js +227 -108
  18. package/dist/bin/exe-kill.js +138 -20
  19. package/dist/bin/exe-launch-agent.js +172 -39
  20. package/dist/bin/exe-link.js +291 -100
  21. package/dist/bin/exe-new-employee.js +214 -106
  22. package/dist/bin/exe-pending-messages.js +395 -33
  23. package/dist/bin/exe-pending-notifications.js +684 -99
  24. package/dist/bin/exe-pending-reviews.js +420 -74
  25. package/dist/bin/exe-rename.js +147 -49
  26. package/dist/bin/exe-review.js +138 -20
  27. package/dist/bin/exe-search.js +240 -69
  28. package/dist/bin/exe-session-cleanup.js +440 -250
  29. package/dist/bin/exe-settings.js +61 -17
  30. package/dist/bin/exe-start-codex.js +158 -39
  31. package/dist/bin/exe-start-opencode.js +157 -38
  32. package/dist/bin/exe-status.js +151 -29
  33. package/dist/bin/exe-team.js +138 -20
  34. package/dist/bin/git-sweep.js +404 -212
  35. package/dist/bin/graph-backfill.js +137 -19
  36. package/dist/bin/graph-export.js +140 -22
  37. package/dist/bin/install.js +90 -61
  38. package/dist/bin/scan-tasks.js +412 -220
  39. package/dist/bin/setup.js +564 -293
  40. package/dist/bin/shard-migrate.js +139 -21
  41. package/dist/bin/update.js +138 -49
  42. package/dist/bin/wiki-sync.js +137 -19
  43. package/dist/gateway/index.js +533 -320
  44. package/dist/hooks/bug-report-worker.js +344 -193
  45. package/dist/hooks/codex-stop-task-finalizer.js +4678 -0
  46. package/dist/hooks/commit-complete.js +402 -210
  47. package/dist/hooks/error-recall.js +245 -74
  48. package/dist/hooks/exe-heartbeat-hook.js +16 -6
  49. package/dist/hooks/ingest-worker.js +3423 -3157
  50. package/dist/hooks/ingest.js +832 -97
  51. package/dist/hooks/instructions-loaded.js +227 -54
  52. package/dist/hooks/notification.js +216 -43
  53. package/dist/hooks/post-compact.js +239 -62
  54. package/dist/hooks/pre-compact.js +408 -216
  55. package/dist/hooks/pre-tool-use.js +268 -90
  56. package/dist/hooks/prompt-ingest-worker.js +352 -102
  57. package/dist/hooks/prompt-submit.js +541 -328
  58. package/dist/hooks/response-ingest-worker.js +372 -122
  59. package/dist/hooks/session-end.js +443 -240
  60. package/dist/hooks/session-start.js +313 -127
  61. package/dist/hooks/stop.js +293 -98
  62. package/dist/hooks/subagent-stop.js +239 -62
  63. package/dist/hooks/summary-worker.js +568 -236
  64. package/dist/index.js +538 -324
  65. package/dist/lib/agent-config.js +28 -6
  66. package/dist/lib/cloud-sync.js +284 -105
  67. package/dist/lib/config.js +30 -10
  68. package/dist/lib/consolidation.js +16 -6
  69. package/dist/lib/database.js +123 -25
  70. package/dist/lib/db-daemon-client.js +73 -19
  71. package/dist/lib/db.js +123 -25
  72. package/dist/lib/device-registry.js +133 -35
  73. package/dist/lib/embedder.js +107 -32
  74. package/dist/lib/employee-templates.js +14 -4
  75. package/dist/lib/employees.js +41 -13
  76. package/dist/lib/exe-daemon-client.js +88 -22
  77. package/dist/lib/exe-daemon.js +935 -587
  78. package/dist/lib/hybrid-search.js +240 -69
  79. package/dist/lib/identity.js +18 -8
  80. package/dist/lib/license.js +133 -48
  81. package/dist/lib/messaging.js +116 -56
  82. package/dist/lib/reminders.js +14 -4
  83. package/dist/lib/schedules.js +137 -19
  84. package/dist/lib/skill-learning.js +33 -6
  85. package/dist/lib/store.js +137 -19
  86. package/dist/lib/task-router.js +14 -4
  87. package/dist/lib/tasks.js +280 -234
  88. package/dist/lib/tmux-routing.js +172 -125
  89. package/dist/lib/token-spend.js +26 -8
  90. package/dist/mcp/server.js +1326 -609
  91. package/dist/mcp/tools/complete-reminder.js +14 -4
  92. package/dist/mcp/tools/create-reminder.js +14 -4
  93. package/dist/mcp/tools/create-task.js +306 -248
  94. package/dist/mcp/tools/deactivate-behavior.js +16 -6
  95. package/dist/mcp/tools/list-reminders.js +14 -4
  96. package/dist/mcp/tools/list-tasks.js +123 -107
  97. package/dist/mcp/tools/send-message.js +75 -29
  98. package/dist/mcp/tools/update-task.js +1848 -199
  99. package/dist/runtime/index.js +441 -248
  100. package/dist/tui/App.js +761 -424
  101. package/package.json +1 -1
@@ -26,9 +26,18 @@ var init_db_retry = __esm({
26
26
  }
27
27
  });
28
28
 
29
+ // src/lib/secure-files.ts
30
+ import { chmodSync, existsSync, mkdirSync } from "fs";
31
+ import { chmod, mkdir } from "fs/promises";
32
+ var init_secure_files = __esm({
33
+ "src/lib/secure-files.ts"() {
34
+ "use strict";
35
+ }
36
+ });
37
+
29
38
  // src/lib/config.ts
30
- import { readFile, writeFile, mkdir, chmod } from "fs/promises";
31
- import { readFileSync, existsSync, renameSync } from "fs";
39
+ import { readFile, writeFile } from "fs/promises";
40
+ import { readFileSync, existsSync as existsSync2, renameSync } from "fs";
32
41
  import path from "path";
33
42
  import os from "os";
34
43
  function resolveDataDir() {
@@ -36,7 +45,7 @@ function resolveDataDir() {
36
45
  if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
37
46
  const newDir = path.join(os.homedir(), ".exe-os");
38
47
  const legacyDir = path.join(os.homedir(), ".exe-mem");
39
- if (!existsSync(newDir) && existsSync(legacyDir)) {
48
+ if (!existsSync2(newDir) && existsSync2(legacyDir)) {
40
49
  try {
41
50
  renameSync(legacyDir, newDir);
42
51
  process.stderr.write(`[exe-os] Migrated data directory: ~/.exe-mem \u2192 ~/.exe-os
@@ -51,6 +60,7 @@ var EXE_AI_DIR, DB_PATH, MODELS_DIR, CONFIG_PATH, LEGACY_LANCE_PATH, CURRENT_CON
51
60
  var init_config = __esm({
52
61
  "src/lib/config.ts"() {
53
62
  "use strict";
63
+ init_secure_files();
54
64
  EXE_AI_DIR = resolveDataDir();
55
65
  DB_PATH = path.join(EXE_AI_DIR, "memories.db");
56
66
  MODELS_DIR = path.join(EXE_AI_DIR, "models");
@@ -119,7 +129,7 @@ var init_config = __esm({
119
129
 
120
130
  // src/lib/employees.ts
121
131
  import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
122
- import { existsSync as existsSync2, symlinkSync, readlinkSync, readFileSync as readFileSync2, renameSync as renameSync2, unlinkSync, writeFileSync } from "fs";
132
+ import { existsSync as existsSync3, symlinkSync, readlinkSync, readFileSync as readFileSync2, renameSync as renameSync2, unlinkSync, writeFileSync } from "fs";
123
133
  import { execSync } from "child_process";
124
134
  import path2 from "path";
125
135
  import os2 from "os";
@@ -136,7 +146,7 @@ function getCoordinatorName(employees = loadEmployeesSync()) {
136
146
  return getCoordinatorEmployee(employees)?.name ?? DEFAULT_COORDINATOR_TEMPLATE_NAME;
137
147
  }
138
148
  function loadEmployeesSync(employeesPath = EMPLOYEES_PATH) {
139
- if (!existsSync2(employeesPath)) return [];
149
+ if (!existsSync3(employeesPath)) return [];
140
150
  try {
141
151
  return JSON.parse(readFileSync2(employeesPath, "utf-8"));
142
152
  } catch {
@@ -460,10 +470,10 @@ var init_runtime_table = __esm({
460
470
  });
461
471
 
462
472
  // src/lib/agent-config.ts
463
- import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, existsSync as existsSync3, mkdirSync } from "fs";
473
+ import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, existsSync as existsSync4 } from "fs";
464
474
  import path5 from "path";
465
475
  function loadAgentConfig() {
466
- if (!existsSync3(AGENT_CONFIG_PATH)) return {};
476
+ if (!existsSync4(AGENT_CONFIG_PATH)) return {};
467
477
  try {
468
478
  return JSON.parse(readFileSync3(AGENT_CONFIG_PATH, "utf-8"));
469
479
  } catch {
@@ -484,6 +494,7 @@ var init_agent_config = __esm({
484
494
  "use strict";
485
495
  init_config();
486
496
  init_runtime_table();
497
+ init_secure_files();
487
498
  AGENT_CONFIG_PATH = path5.join(EXE_AI_DIR, "agent-config.json");
488
499
  DEFAULT_MODELS = {
489
500
  claude: "claude-opus-4",
@@ -494,16 +505,16 @@ var init_agent_config = __esm({
494
505
  });
495
506
 
496
507
  // src/lib/intercom-queue.ts
497
- import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, renameSync as renameSync3, existsSync as existsSync4, mkdirSync as mkdirSync2 } from "fs";
508
+ import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, renameSync as renameSync3, existsSync as existsSync5, mkdirSync as mkdirSync2 } from "fs";
498
509
  import path6 from "path";
499
510
  import os5 from "os";
500
511
  function ensureDir() {
501
512
  const dir = path6.dirname(QUEUE_PATH);
502
- if (!existsSync4(dir)) mkdirSync2(dir, { recursive: true });
513
+ if (!existsSync5(dir)) mkdirSync2(dir, { recursive: true });
503
514
  }
504
515
  function readQueue() {
505
516
  try {
506
- if (!existsSync4(QUEUE_PATH)) return [];
517
+ if (!existsSync5(QUEUE_PATH)) return [];
507
518
  return JSON.parse(readFileSync4(QUEUE_PATH, "utf8"));
508
519
  } catch {
509
520
  return [];
@@ -543,8 +554,11 @@ var init_intercom_queue = __esm({
543
554
  });
544
555
 
545
556
  // src/lib/license.ts
546
- import { readFileSync as readFileSync5, writeFileSync as writeFileSync4, existsSync as existsSync5, mkdirSync as mkdirSync3 } from "fs";
557
+ import { readFileSync as readFileSync5, writeFileSync as writeFileSync4, existsSync as existsSync6, mkdirSync as mkdirSync3 } from "fs";
547
558
  import { randomUUID } from "crypto";
559
+ import { createRequire as createRequire2 } from "module";
560
+ import { pathToFileURL as pathToFileURL2 } from "url";
561
+ import os6 from "os";
548
562
  import path7 from "path";
549
563
  import { jwtVerify, importSPKI } from "jose";
550
564
  var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH;
@@ -559,7 +573,7 @@ var init_license = __esm({
559
573
  });
560
574
 
561
575
  // src/lib/plan-limits.ts
562
- import { readFileSync as readFileSync6, existsSync as existsSync6 } from "fs";
576
+ import { readFileSync as readFileSync6, existsSync as existsSync7 } from "fs";
563
577
  import path8 from "path";
564
578
  var CACHE_PATH2;
565
579
  var init_plan_limits = __esm({
@@ -575,9 +589,9 @@ var init_plan_limits = __esm({
575
589
 
576
590
  // src/lib/tmux-routing.ts
577
591
  import { execFileSync as execFileSync2, execSync as execSync4 } from "child_process";
578
- import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, mkdirSync as mkdirSync4, existsSync as existsSync7, appendFileSync, readdirSync } from "fs";
592
+ import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, mkdirSync as mkdirSync4, existsSync as existsSync8, appendFileSync, readdirSync } from "fs";
579
593
  import path9 from "path";
580
- import os6 from "os";
594
+ import os7 from "os";
581
595
  import { fileURLToPath } from "url";
582
596
  function getMySession() {
583
597
  return getTransport().getMySession();
@@ -650,7 +664,7 @@ function isEmployeeAlive(sessionName) {
650
664
  }
651
665
  function readDebounceState() {
652
666
  try {
653
- if (!existsSync7(DEBOUNCE_FILE)) return {};
667
+ if (!existsSync8(DEBOUNCE_FILE)) return {};
654
668
  const raw = JSON.parse(readFileSync7(DEBOUNCE_FILE, "utf8"));
655
669
  const state = {};
656
670
  for (const [key, val] of Object.entries(raw)) {
@@ -667,7 +681,7 @@ function readDebounceState() {
667
681
  }
668
682
  function writeDebounceState(state) {
669
683
  try {
670
- if (!existsSync7(SESSION_CACHE)) mkdirSync4(SESSION_CACHE, { recursive: true });
684
+ if (!existsSync8(SESSION_CACHE)) mkdirSync4(SESSION_CACHE, { recursive: true });
671
685
  writeFileSync5(DEBOUNCE_FILE, JSON.stringify(state));
672
686
  } catch {
673
687
  }
@@ -763,7 +777,7 @@ function sendIntercom(targetSession) {
763
777
  const rawAgent = targetSession.split("-")[0] ?? targetSession;
764
778
  const agent = baseAgentName(rawAgent);
765
779
  const markerPath = path9.join(SESSION_CACHE, `current-task-${agent}.json`);
766
- if (existsSync7(markerPath)) {
780
+ if (existsSync8(markerPath)) {
767
781
  logIntercom(`SKIP \u2192 ${targetSession} (has in_progress task marker \u2014 will auto-chain)`);
768
782
  return "debounced";
769
783
  }
@@ -773,7 +787,7 @@ function sendIntercom(targetSession) {
773
787
  const rawAgent = targetSession.split("-")[0] ?? targetSession;
774
788
  const agent = baseAgentName(rawAgent);
775
789
  const taskDir = path9.join(process.cwd(), "exe", agent);
776
- if (existsSync7(taskDir)) {
790
+ if (existsSync8(taskDir)) {
777
791
  const files = readdirSync(taskDir).filter(
778
792
  (f) => f.endsWith(".md") && f !== "DONE.txt"
779
793
  );
@@ -826,24 +840,49 @@ var init_tmux_routing = __esm({
826
840
  init_intercom_queue();
827
841
  init_plan_limits();
828
842
  init_employees();
829
- SPAWN_LOCK_DIR = path9.join(os6.homedir(), ".exe-os", "spawn-locks");
830
- SESSION_CACHE = path9.join(os6.homedir(), ".exe-os", "session-cache");
843
+ SPAWN_LOCK_DIR = path9.join(os7.homedir(), ".exe-os", "spawn-locks");
844
+ SESSION_CACHE = path9.join(os7.homedir(), ".exe-os", "session-cache");
831
845
  VALID_SESSION_NAME = /^[a-z]+\d*-[a-zA-Z0-9_]+$/;
832
846
  INTERCOM_DEBOUNCE_MS = 3e4;
833
847
  CODEX_DEBOUNCE_MS = 12e4;
834
- INTERCOM_LOG2 = path9.join(os6.homedir(), ".exe-os", "intercom.log");
848
+ INTERCOM_LOG2 = path9.join(os7.homedir(), ".exe-os", "intercom.log");
835
849
  DEBOUNCE_FILE = path9.join(SESSION_CACHE, "intercom-debounce.json");
836
850
  DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
837
851
  BUSY_PATTERN = /[✻✽✶✳·].*…|Running…|• Working|• Ran |• Explored|• Called|esc to interrupt/;
838
852
  }
839
853
  });
840
854
 
855
+ // src/lib/task-scope.ts
856
+ function getCurrentSessionScope() {
857
+ try {
858
+ return resolveExeSession();
859
+ } catch {
860
+ return null;
861
+ }
862
+ }
863
+ function strictSessionScopeFilter(sessionScope, tableAlias) {
864
+ const scope = sessionScope !== void 0 ? sessionScope : getCurrentSessionScope();
865
+ if (!scope) return { sql: "", args: [] };
866
+ const col = tableAlias ? `${tableAlias}.session_scope` : "session_scope";
867
+ return {
868
+ sql: ` AND ${col} = ?`,
869
+ args: [scope]
870
+ };
871
+ }
872
+ var init_task_scope = __esm({
873
+ "src/lib/task-scope.ts"() {
874
+ "use strict";
875
+ init_tmux_routing();
876
+ }
877
+ });
878
+
841
879
  // src/mcp/tools/send-message.ts
842
880
  import { z } from "zod";
843
881
 
844
882
  // src/lib/messaging.ts
845
883
  init_database();
846
884
  init_tmux_routing();
885
+ init_task_scope();
847
886
  import crypto from "crypto";
848
887
  function generateUlid() {
849
888
  const timestamp = Date.now().toString(36).padStart(10, "0");
@@ -858,6 +897,7 @@ function rowToMessage(row) {
858
897
  targetAgent: row.target_agent,
859
898
  targetProject: row.target_project ?? null,
860
899
  targetDevice: row.target_device,
900
+ sessionScope: row.session_scope ?? null,
861
901
  content: row.content,
862
902
  priority: row.priority ?? "normal",
863
903
  status: row.status ?? "pending",
@@ -876,15 +916,17 @@ async function sendMessage(input) {
876
916
  const id = generateUlid();
877
917
  const now = (/* @__PURE__ */ new Date()).toISOString();
878
918
  const targetDevice = input.targetDevice ?? "local";
919
+ const sessionScope = input.sessionScope === void 0 ? resolveExeSession() : input.sessionScope;
879
920
  await client.execute({
880
- sql: `INSERT INTO messages (id, from_agent, from_device, target_agent, target_project, target_device, content, priority, status, created_at)
881
- VALUES (?, ?, 'local', ?, ?, ?, ?, ?, 'pending', ?)`,
921
+ sql: `INSERT INTO messages (id, from_agent, from_device, target_agent, target_project, target_device, session_scope, content, priority, status, created_at)
922
+ VALUES (?, ?, 'local', ?, ?, ?, ?, ?, ?, 'pending', ?)`,
882
923
  args: [
883
924
  id,
884
925
  input.fromAgent,
885
926
  input.targetAgent,
886
927
  input.targetProject ?? null,
887
928
  targetDevice,
929
+ sessionScope,
888
930
  input.content,
889
931
  input.priority ?? "normal",
890
932
  now
@@ -898,9 +940,10 @@ async function sendMessage(input) {
898
940
  }
899
941
  } catch {
900
942
  }
943
+ const sentScope = strictSessionScopeFilter(sessionScope);
901
944
  const result = await client.execute({
902
- sql: "SELECT * FROM messages WHERE id = ?",
903
- args: [id]
945
+ sql: `SELECT * FROM messages WHERE id = ?${sentScope.sql}`,
946
+ args: [id, ...sentScope.args]
904
947
  });
905
948
  return rowToMessage(result.rows[0]);
906
949
  }
@@ -922,6 +965,7 @@ async function deliverCrossMachineMessage(messageId, targetDevice) {
922
965
  fromAgent: msg.fromAgent,
923
966
  targetAgent: msg.targetAgent,
924
967
  targetProject: msg.targetProject,
968
+ sessionScope: msg.sessionScope,
925
969
  content: msg.content,
926
970
  priority: msg.priority,
927
971
  createdAt: msg.createdAt
@@ -965,7 +1009,7 @@ async function deliverLocalMessage(messageId) {
965
1009
  } catch {
966
1010
  const newRetryCount = msg.retryCount + 1;
967
1011
  if (newRetryCount >= MAX_RETRIES) {
968
- await markFailed(messageId, "session unavailable after 10 retries");
1012
+ await markFailed(messageId, "session unavailable after 10 retries", msg.sessionScope);
969
1013
  } else {
970
1014
  await client.execute({
971
1015
  sql: "UPDATE messages SET retry_count = ? WHERE id = ?",
@@ -975,11 +1019,13 @@ async function deliverLocalMessage(messageId) {
975
1019
  return false;
976
1020
  }
977
1021
  }
978
- async function markFailed(messageId, reason) {
1022
+ async function markFailed(messageId, reason, sessionScope) {
979
1023
  const client = getClient();
1024
+ const scope = strictSessionScopeFilter(sessionScope);
980
1025
  await client.execute({
981
- sql: "UPDATE messages SET status = 'failed', failed_at = ?, failure_reason = ? WHERE id = ?",
982
- args: [(/* @__PURE__ */ new Date()).toISOString(), reason, messageId]
1026
+ sql: `UPDATE messages SET status = 'failed', failed_at = ?, failure_reason = ?
1027
+ WHERE id = ?${scope.sql}`,
1028
+ args: [(/* @__PURE__ */ new Date()).toISOString(), reason, messageId, ...scope.args]
983
1029
  });
984
1030
  }
985
1031