@askexenow/exe-os 0.9.7 → 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 +953 -105
  2. package/dist/bin/backfill-responses.js +952 -104
  3. package/dist/bin/backfill-vectors.js +956 -108
  4. package/dist/bin/cleanup-stale-review-tasks.js +802 -58
  5. package/dist/bin/cli.js +2292 -1070
  6. package/dist/bin/exe-agent-config.js +157 -101
  7. package/dist/bin/exe-agent.js +55 -29
  8. package/dist/bin/exe-assign.js +940 -92
  9. package/dist/bin/exe-boot.js +1424 -442
  10. package/dist/bin/exe-call.js +240 -141
  11. package/dist/bin/exe-cloud.js +198 -70
  12. package/dist/bin/exe-dispatch.js +951 -192
  13. package/dist/bin/exe-doctor.js +791 -51
  14. package/dist/bin/exe-export-behaviors.js +790 -42
  15. package/dist/bin/exe-forget.js +771 -31
  16. package/dist/bin/exe-gateway.js +1592 -521
  17. package/dist/bin/exe-heartbeat.js +850 -109
  18. package/dist/bin/exe-kill.js +783 -35
  19. package/dist/bin/exe-launch-agent.js +1030 -107
  20. package/dist/bin/exe-link.js +916 -110
  21. package/dist/bin/exe-new-employee.js +526 -217
  22. package/dist/bin/exe-pending-messages.js +1046 -62
  23. package/dist/bin/exe-pending-notifications.js +1318 -111
  24. package/dist/bin/exe-pending-reviews.js +1040 -72
  25. package/dist/bin/exe-rename.js +772 -59
  26. package/dist/bin/exe-review.js +772 -32
  27. package/dist/bin/exe-search.js +982 -128
  28. package/dist/bin/exe-session-cleanup.js +1180 -306
  29. package/dist/bin/exe-settings.js +185 -105
  30. package/dist/bin/exe-start-codex.js +886 -132
  31. package/dist/bin/exe-start-opencode.js +873 -119
  32. package/dist/bin/exe-status.js +803 -59
  33. package/dist/bin/exe-team.js +772 -32
  34. package/dist/bin/git-sweep.js +1046 -223
  35. package/dist/bin/graph-backfill.js +779 -31
  36. package/dist/bin/graph-export.js +785 -37
  37. package/dist/bin/install.js +632 -200
  38. package/dist/bin/scan-tasks.js +1055 -232
  39. package/dist/bin/setup.js +1419 -320
  40. package/dist/bin/shard-migrate.js +783 -35
  41. package/dist/bin/update.js +138 -49
  42. package/dist/bin/wiki-sync.js +782 -34
  43. package/dist/gateway/index.js +1444 -449
  44. package/dist/hooks/bug-report-worker.js +1141 -269
  45. package/dist/hooks/codex-stop-task-finalizer.js +4678 -0
  46. package/dist/hooks/commit-complete.js +1044 -221
  47. package/dist/hooks/error-recall.js +989 -135
  48. package/dist/hooks/exe-heartbeat-hook.js +99 -75
  49. package/dist/hooks/ingest-worker.js +4176 -3226
  50. package/dist/hooks/ingest.js +920 -168
  51. package/dist/hooks/instructions-loaded.js +874 -70
  52. package/dist/hooks/notification.js +860 -56
  53. package/dist/hooks/post-compact.js +881 -73
  54. package/dist/hooks/pre-compact.js +1050 -227
  55. package/dist/hooks/pre-tool-use.js +1084 -159
  56. package/dist/hooks/prompt-ingest-worker.js +1089 -164
  57. package/dist/hooks/prompt-submit.js +1469 -515
  58. package/dist/hooks/response-ingest-worker.js +1104 -179
  59. package/dist/hooks/session-end.js +1085 -251
  60. package/dist/hooks/session-start.js +1241 -231
  61. package/dist/hooks/stop.js +935 -109
  62. package/dist/hooks/subagent-stop.js +881 -73
  63. package/dist/hooks/summary-worker.js +1323 -307
  64. package/dist/index.js +1449 -452
  65. package/dist/lib/agent-config.js +28 -6
  66. package/dist/lib/cloud-sync.js +909 -115
  67. package/dist/lib/config.js +30 -10
  68. package/dist/lib/consolidation.js +42 -9
  69. package/dist/lib/database.js +739 -33
  70. package/dist/lib/db-daemon-client.js +73 -19
  71. package/dist/lib/db.js +2359 -0
  72. package/dist/lib/device-registry.js +760 -47
  73. package/dist/lib/embedder.js +201 -73
  74. package/dist/lib/employee-templates.js +30 -4
  75. package/dist/lib/employees.js +290 -86
  76. package/dist/lib/exe-daemon-client.js +187 -83
  77. package/dist/lib/exe-daemon.js +1696 -616
  78. package/dist/lib/hybrid-search.js +982 -128
  79. package/dist/lib/identity.js +43 -13
  80. package/dist/lib/license.js +133 -48
  81. package/dist/lib/messaging.js +167 -80
  82. package/dist/lib/reminders.js +35 -5
  83. package/dist/lib/schedules.js +772 -32
  84. package/dist/lib/skill-learning.js +54 -7
  85. package/dist/lib/store.js +779 -31
  86. package/dist/lib/task-router.js +94 -73
  87. package/dist/lib/tasks.js +298 -225
  88. package/dist/lib/tmux-routing.js +246 -172
  89. package/dist/lib/token-spend.js +52 -14
  90. package/dist/mcp/server.js +2893 -850
  91. package/dist/mcp/tools/complete-reminder.js +35 -5
  92. package/dist/mcp/tools/create-reminder.js +35 -5
  93. package/dist/mcp/tools/create-task.js +507 -323
  94. package/dist/mcp/tools/deactivate-behavior.js +40 -10
  95. package/dist/mcp/tools/list-reminders.js +35 -5
  96. package/dist/mcp/tools/list-tasks.js +277 -104
  97. package/dist/mcp/tools/send-message.js +129 -56
  98. package/dist/mcp/tools/update-task.js +1864 -188
  99. package/dist/runtime/index.js +1083 -259
  100. package/dist/tui/App.js +1501 -434
  101. package/package.json +3 -2
@@ -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 {
@@ -154,7 +164,7 @@ function baseAgentName(name, employees) {
154
164
  if (getEmployee(roster, base)) return base;
155
165
  return name;
156
166
  }
157
- var EMPLOYEES_PATH, DEFAULT_COORDINATOR_TEMPLATE_NAME, COORDINATOR_ROLE;
167
+ var EMPLOYEES_PATH, DEFAULT_COORDINATOR_TEMPLATE_NAME, COORDINATOR_ROLE, IDENTITY_DIR;
158
168
  var init_employees = __esm({
159
169
  "src/lib/employees.ts"() {
160
170
  "use strict";
@@ -162,15 +172,40 @@ var init_employees = __esm({
162
172
  EMPLOYEES_PATH = path2.join(EXE_AI_DIR, "exe-employees.json");
163
173
  DEFAULT_COORDINATOR_TEMPLATE_NAME = "exe";
164
174
  COORDINATOR_ROLE = "COO";
175
+ IDENTITY_DIR = path2.join(EXE_AI_DIR, "identity");
176
+ }
177
+ });
178
+
179
+ // src/lib/database-adapter.ts
180
+ import os3 from "os";
181
+ import path3 from "path";
182
+ import { createRequire } from "module";
183
+ import { pathToFileURL } from "url";
184
+ var BOOLEAN_COLUMNS_BY_TABLE, BOOLEAN_COLUMN_NAMES;
185
+ var init_database_adapter = __esm({
186
+ "src/lib/database-adapter.ts"() {
187
+ "use strict";
188
+ BOOLEAN_COLUMNS_BY_TABLE = {
189
+ memories: /* @__PURE__ */ new Set(["has_error", "draft"]),
190
+ behaviors: /* @__PURE__ */ new Set(["active"]),
191
+ notifications: /* @__PURE__ */ new Set(["read"]),
192
+ users: /* @__PURE__ */ new Set(["has_personal_memory"])
193
+ };
194
+ BOOLEAN_COLUMN_NAMES = new Set(
195
+ Object.values(BOOLEAN_COLUMNS_BY_TABLE).flatMap((cols) => [...cols])
196
+ );
165
197
  }
166
198
  });
167
199
 
168
200
  // src/lib/database.ts
169
201
  import { createClient } from "@libsql/client";
170
202
  function getClient() {
171
- if (!_resilientClient) {
203
+ if (!_adapterClient) {
172
204
  throw new Error("Database client not initialized. Call initDatabase() first.");
173
205
  }
206
+ if (process.env.DATABASE_URL) {
207
+ return _adapterClient;
208
+ }
174
209
  if (process.env.EXE_IS_DAEMON === "1") {
175
210
  return _resilientClient;
176
211
  }
@@ -179,25 +214,27 @@ function getClient() {
179
214
  }
180
215
  return _resilientClient;
181
216
  }
182
- var _resilientClient, _daemonClient;
217
+ var _resilientClient, _daemonClient, _adapterClient;
183
218
  var init_database = __esm({
184
219
  "src/lib/database.ts"() {
185
220
  "use strict";
186
221
  init_db_retry();
187
222
  init_employees();
223
+ init_database_adapter();
188
224
  _resilientClient = null;
189
225
  _daemonClient = null;
226
+ _adapterClient = null;
190
227
  }
191
228
  });
192
229
 
193
230
  // src/lib/session-registry.ts
194
- import path3 from "path";
195
- import os3 from "os";
231
+ import path4 from "path";
232
+ import os4 from "os";
196
233
  var REGISTRY_PATH;
197
234
  var init_session_registry = __esm({
198
235
  "src/lib/session-registry.ts"() {
199
236
  "use strict";
200
- REGISTRY_PATH = path3.join(os3.homedir(), ".exe-os", "session-registry.json");
237
+ REGISTRY_PATH = path4.join(os4.homedir(), ".exe-os", "session-registry.json");
201
238
  }
202
239
  });
203
240
 
@@ -433,10 +470,10 @@ var init_runtime_table = __esm({
433
470
  });
434
471
 
435
472
  // src/lib/agent-config.ts
436
- import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, existsSync as existsSync3, mkdirSync } from "fs";
437
- import path4 from "path";
473
+ import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, existsSync as existsSync4 } from "fs";
474
+ import path5 from "path";
438
475
  function loadAgentConfig() {
439
- if (!existsSync3(AGENT_CONFIG_PATH)) return {};
476
+ if (!existsSync4(AGENT_CONFIG_PATH)) return {};
440
477
  try {
441
478
  return JSON.parse(readFileSync3(AGENT_CONFIG_PATH, "utf-8"));
442
479
  } catch {
@@ -457,7 +494,8 @@ var init_agent_config = __esm({
457
494
  "use strict";
458
495
  init_config();
459
496
  init_runtime_table();
460
- AGENT_CONFIG_PATH = path4.join(EXE_AI_DIR, "agent-config.json");
497
+ init_secure_files();
498
+ AGENT_CONFIG_PATH = path5.join(EXE_AI_DIR, "agent-config.json");
461
499
  DEFAULT_MODELS = {
462
500
  claude: "claude-opus-4",
463
501
  codex: RUNTIME_TABLE.codex?.defaultModel ?? "gpt-5.4",
@@ -467,16 +505,16 @@ var init_agent_config = __esm({
467
505
  });
468
506
 
469
507
  // src/lib/intercom-queue.ts
470
- import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, renameSync as renameSync3, existsSync as existsSync4, mkdirSync as mkdirSync2 } from "fs";
471
- import path5 from "path";
472
- import os4 from "os";
508
+ import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, renameSync as renameSync3, existsSync as existsSync5, mkdirSync as mkdirSync2 } from "fs";
509
+ import path6 from "path";
510
+ import os5 from "os";
473
511
  function ensureDir() {
474
- const dir = path5.dirname(QUEUE_PATH);
475
- if (!existsSync4(dir)) mkdirSync2(dir, { recursive: true });
512
+ const dir = path6.dirname(QUEUE_PATH);
513
+ if (!existsSync5(dir)) mkdirSync2(dir, { recursive: true });
476
514
  }
477
515
  function readQueue() {
478
516
  try {
479
- if (!existsSync4(QUEUE_PATH)) return [];
517
+ if (!existsSync5(QUEUE_PATH)) return [];
480
518
  return JSON.parse(readFileSync4(QUEUE_PATH, "utf8"));
481
519
  } catch {
482
520
  return [];
@@ -509,31 +547,34 @@ var QUEUE_PATH, TTL_MS, INTERCOM_LOG;
509
547
  var init_intercom_queue = __esm({
510
548
  "src/lib/intercom-queue.ts"() {
511
549
  "use strict";
512
- QUEUE_PATH = path5.join(os4.homedir(), ".exe-os", "intercom-queue.json");
550
+ QUEUE_PATH = path6.join(os5.homedir(), ".exe-os", "intercom-queue.json");
513
551
  TTL_MS = 60 * 60 * 1e3;
514
- INTERCOM_LOG = path5.join(os4.homedir(), ".exe-os", "intercom.log");
552
+ INTERCOM_LOG = path6.join(os5.homedir(), ".exe-os", "intercom.log");
515
553
  }
516
554
  });
517
555
 
518
556
  // src/lib/license.ts
519
- 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";
520
558
  import { randomUUID } from "crypto";
521
- import path6 from "path";
559
+ import { createRequire as createRequire2 } from "module";
560
+ import { pathToFileURL as pathToFileURL2 } from "url";
561
+ import os6 from "os";
562
+ import path7 from "path";
522
563
  import { jwtVerify, importSPKI } from "jose";
523
564
  var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH;
524
565
  var init_license = __esm({
525
566
  "src/lib/license.ts"() {
526
567
  "use strict";
527
568
  init_config();
528
- LICENSE_PATH = path6.join(EXE_AI_DIR, "license.key");
529
- CACHE_PATH = path6.join(EXE_AI_DIR, "license-cache.json");
530
- DEVICE_ID_PATH = path6.join(EXE_AI_DIR, "device-id");
569
+ LICENSE_PATH = path7.join(EXE_AI_DIR, "license.key");
570
+ CACHE_PATH = path7.join(EXE_AI_DIR, "license-cache.json");
571
+ DEVICE_ID_PATH = path7.join(EXE_AI_DIR, "device-id");
531
572
  }
532
573
  });
533
574
 
534
575
  // src/lib/plan-limits.ts
535
- import { readFileSync as readFileSync6, existsSync as existsSync6 } from "fs";
536
- import path7 from "path";
576
+ import { readFileSync as readFileSync6, existsSync as existsSync7 } from "fs";
577
+ import path8 from "path";
537
578
  var CACHE_PATH2;
538
579
  var init_plan_limits = __esm({
539
580
  "src/lib/plan-limits.ts"() {
@@ -542,15 +583,15 @@ var init_plan_limits = __esm({
542
583
  init_employees();
543
584
  init_license();
544
585
  init_config();
545
- CACHE_PATH2 = path7.join(EXE_AI_DIR, "license-cache.json");
586
+ CACHE_PATH2 = path8.join(EXE_AI_DIR, "license-cache.json");
546
587
  }
547
588
  });
548
589
 
549
590
  // src/lib/tmux-routing.ts
550
591
  import { execFileSync as execFileSync2, execSync as execSync4 } from "child_process";
551
- import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, mkdirSync as mkdirSync4, existsSync as existsSync7, appendFileSync, readdirSync } from "fs";
552
- import path8 from "path";
553
- import os5 from "os";
592
+ import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, mkdirSync as mkdirSync4, existsSync as existsSync8, appendFileSync, readdirSync } from "fs";
593
+ import path9 from "path";
594
+ import os7 from "os";
554
595
  import { fileURLToPath } from "url";
555
596
  function getMySession() {
556
597
  return getTransport().getMySession();
@@ -590,7 +631,7 @@ function extractRootExe(name) {
590
631
  }
591
632
  function getParentExe(sessionKey) {
592
633
  try {
593
- const data = JSON.parse(readFileSync7(path8.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
634
+ const data = JSON.parse(readFileSync7(path9.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
594
635
  return data.parentExe || null;
595
636
  } catch {
596
637
  return null;
@@ -623,7 +664,7 @@ function isEmployeeAlive(sessionName) {
623
664
  }
624
665
  function readDebounceState() {
625
666
  try {
626
- if (!existsSync7(DEBOUNCE_FILE)) return {};
667
+ if (!existsSync8(DEBOUNCE_FILE)) return {};
627
668
  const raw = JSON.parse(readFileSync7(DEBOUNCE_FILE, "utf8"));
628
669
  const state = {};
629
670
  for (const [key, val] of Object.entries(raw)) {
@@ -640,7 +681,7 @@ function readDebounceState() {
640
681
  }
641
682
  function writeDebounceState(state) {
642
683
  try {
643
- if (!existsSync7(SESSION_CACHE)) mkdirSync4(SESSION_CACHE, { recursive: true });
684
+ if (!existsSync8(SESSION_CACHE)) mkdirSync4(SESSION_CACHE, { recursive: true });
644
685
  writeFileSync5(DEBOUNCE_FILE, JSON.stringify(state));
645
686
  } catch {
646
687
  }
@@ -735,8 +776,8 @@ function sendIntercom(targetSession) {
735
776
  try {
736
777
  const rawAgent = targetSession.split("-")[0] ?? targetSession;
737
778
  const agent = baseAgentName(rawAgent);
738
- const markerPath = path8.join(SESSION_CACHE, `current-task-${agent}.json`);
739
- if (existsSync7(markerPath)) {
779
+ const markerPath = path9.join(SESSION_CACHE, `current-task-${agent}.json`);
780
+ if (existsSync8(markerPath)) {
740
781
  logIntercom(`SKIP \u2192 ${targetSession} (has in_progress task marker \u2014 will auto-chain)`);
741
782
  return "debounced";
742
783
  }
@@ -745,8 +786,8 @@ function sendIntercom(targetSession) {
745
786
  try {
746
787
  const rawAgent = targetSession.split("-")[0] ?? targetSession;
747
788
  const agent = baseAgentName(rawAgent);
748
- const taskDir = path8.join(process.cwd(), "exe", agent);
749
- if (existsSync7(taskDir)) {
789
+ const taskDir = path9.join(process.cwd(), "exe", agent);
790
+ if (existsSync8(taskDir)) {
750
791
  const files = readdirSync(taskDir).filter(
751
792
  (f) => f.endsWith(".md") && f !== "DONE.txt"
752
793
  );
@@ -799,21 +840,46 @@ var init_tmux_routing = __esm({
799
840
  init_intercom_queue();
800
841
  init_plan_limits();
801
842
  init_employees();
802
- SPAWN_LOCK_DIR = path8.join(os5.homedir(), ".exe-os", "spawn-locks");
803
- SESSION_CACHE = path8.join(os5.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");
804
845
  VALID_SESSION_NAME = /^[a-z]+\d*-[a-zA-Z0-9_]+$/;
805
846
  INTERCOM_DEBOUNCE_MS = 3e4;
806
847
  CODEX_DEBOUNCE_MS = 12e4;
807
- INTERCOM_LOG2 = path8.join(os5.homedir(), ".exe-os", "intercom.log");
808
- DEBOUNCE_FILE = path8.join(SESSION_CACHE, "intercom-debounce.json");
848
+ INTERCOM_LOG2 = path9.join(os7.homedir(), ".exe-os", "intercom.log");
849
+ DEBOUNCE_FILE = path9.join(SESSION_CACHE, "intercom-debounce.json");
809
850
  DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
810
851
  BUSY_PATTERN = /[✻✽✶✳·].*…|Running…|• Working|• Ran |• Explored|• Called|esc to interrupt/;
811
852
  }
812
853
  });
813
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
+
814
879
  // src/lib/messaging.ts
815
880
  init_database();
816
881
  init_tmux_routing();
882
+ init_task_scope();
817
883
  import crypto from "crypto";
818
884
  function generateUlid() {
819
885
  const timestamp = Date.now().toString(36).padStart(10, "0");
@@ -828,6 +894,7 @@ function rowToMessage(row) {
828
894
  targetAgent: row.target_agent,
829
895
  targetProject: row.target_project ?? null,
830
896
  targetDevice: row.target_device,
897
+ sessionScope: row.session_scope ?? null,
831
898
  content: row.content,
832
899
  priority: row.priority ?? "normal",
833
900
  status: row.status ?? "pending",
@@ -846,15 +913,17 @@ async function sendMessage(input) {
846
913
  const id = generateUlid();
847
914
  const now = (/* @__PURE__ */ new Date()).toISOString();
848
915
  const targetDevice = input.targetDevice ?? "local";
916
+ const sessionScope = input.sessionScope === void 0 ? resolveExeSession() : input.sessionScope;
849
917
  await client.execute({
850
- sql: `INSERT INTO messages (id, from_agent, from_device, target_agent, target_project, target_device, content, priority, status, created_at)
851
- VALUES (?, ?, 'local', ?, ?, ?, ?, ?, 'pending', ?)`,
918
+ sql: `INSERT INTO messages (id, from_agent, from_device, target_agent, target_project, target_device, session_scope, content, priority, status, created_at)
919
+ VALUES (?, ?, 'local', ?, ?, ?, ?, ?, ?, 'pending', ?)`,
852
920
  args: [
853
921
  id,
854
922
  input.fromAgent,
855
923
  input.targetAgent,
856
924
  input.targetProject ?? null,
857
925
  targetDevice,
926
+ sessionScope,
858
927
  input.content,
859
928
  input.priority ?? "normal",
860
929
  now
@@ -868,9 +937,10 @@ async function sendMessage(input) {
868
937
  }
869
938
  } catch {
870
939
  }
940
+ const sentScope = strictSessionScopeFilter(sessionScope);
871
941
  const result = await client.execute({
872
- sql: "SELECT * FROM messages WHERE id = ?",
873
- args: [id]
942
+ sql: `SELECT * FROM messages WHERE id = ?${sentScope.sql}`,
943
+ args: [id, ...sentScope.args]
874
944
  });
875
945
  return rowToMessage(result.rows[0]);
876
946
  }
@@ -895,6 +965,7 @@ async function deliverCrossMachineMessage(messageId, targetDevice) {
895
965
  fromAgent: msg.fromAgent,
896
966
  targetAgent: msg.targetAgent,
897
967
  targetProject: msg.targetProject,
968
+ sessionScope: msg.sessionScope,
898
969
  content: msg.content,
899
970
  priority: msg.priority,
900
971
  createdAt: msg.createdAt
@@ -938,7 +1009,7 @@ async function deliverLocalMessage(messageId) {
938
1009
  } catch {
939
1010
  const newRetryCount = msg.retryCount + 1;
940
1011
  if (newRetryCount >= MAX_RETRIES) {
941
- await markFailed(messageId, "session unavailable after 10 retries");
1012
+ await markFailed(messageId, "session unavailable after 10 retries", msg.sessionScope);
942
1013
  } else {
943
1014
  await client.execute({
944
1015
  sql: "UPDATE messages SET retry_count = ? WHERE id = ?",
@@ -948,85 +1019,101 @@ async function deliverLocalMessage(messageId) {
948
1019
  return false;
949
1020
  }
950
1021
  }
951
- async function getPendingMessages(targetAgent) {
1022
+ async function getPendingMessages(targetAgent, sessionScope) {
952
1023
  const client = getClient();
1024
+ const scope = strictSessionScopeFilter(sessionScope);
953
1025
  const result = await client.execute({
954
1026
  sql: `SELECT * FROM messages
955
- WHERE target_agent = ? AND status IN ('pending', 'delivered')
1027
+ WHERE target_agent = ? AND status IN ('pending', 'delivered')${scope.sql}
956
1028
  ORDER BY id`,
957
- args: [targetAgent]
1029
+ args: [targetAgent, ...scope.args]
958
1030
  });
959
1031
  return result.rows.map((row) => rowToMessage(row));
960
1032
  }
961
- async function markRead(messageId) {
1033
+ async function markRead(messageId, sessionScope) {
962
1034
  const client = getClient();
1035
+ const scope = strictSessionScopeFilter(sessionScope);
963
1036
  await client.execute({
964
- sql: "UPDATE messages SET status = 'read' WHERE id = ? AND status IN ('pending', 'delivered')",
965
- args: [messageId]
1037
+ sql: `UPDATE messages SET status = 'read'
1038
+ WHERE id = ? AND status IN ('pending', 'delivered')${scope.sql}`,
1039
+ args: [messageId, ...scope.args]
966
1040
  });
967
1041
  }
968
- async function markAcknowledged(messageId) {
1042
+ async function markAcknowledged(messageId, sessionScope) {
969
1043
  const client = getClient();
1044
+ const scope = strictSessionScopeFilter(sessionScope);
970
1045
  await client.execute({
971
- sql: "UPDATE messages SET status = 'acknowledged', processed_at = ? WHERE id = ? AND status = 'read'",
972
- args: [(/* @__PURE__ */ new Date()).toISOString(), messageId]
1046
+ sql: `UPDATE messages SET status = 'acknowledged', processed_at = ?
1047
+ WHERE id = ? AND status = 'read'${scope.sql}`,
1048
+ args: [(/* @__PURE__ */ new Date()).toISOString(), messageId, ...scope.args]
973
1049
  });
974
1050
  }
975
- async function markProcessed(messageId) {
1051
+ async function markProcessed(messageId, sessionScope) {
976
1052
  const client = getClient();
1053
+ const scope = strictSessionScopeFilter(sessionScope);
977
1054
  await client.execute({
978
- sql: "UPDATE messages SET status = 'processed', processed_at = ? WHERE id = ?",
979
- args: [(/* @__PURE__ */ new Date()).toISOString(), messageId]
1055
+ sql: `UPDATE messages SET status = 'processed', processed_at = ?
1056
+ WHERE id = ?${scope.sql}`,
1057
+ args: [(/* @__PURE__ */ new Date()).toISOString(), messageId, ...scope.args]
980
1058
  });
981
1059
  }
982
- async function getMessageStatus(messageId) {
1060
+ async function getMessageStatus(messageId, sessionScope) {
983
1061
  const client = getClient();
1062
+ const scope = strictSessionScopeFilter(sessionScope);
984
1063
  const result = await client.execute({
985
- sql: "SELECT status FROM messages WHERE id = ?",
986
- args: [messageId]
1064
+ sql: `SELECT status FROM messages WHERE id = ?${scope.sql}`,
1065
+ args: [messageId, ...scope.args]
987
1066
  });
988
1067
  return result.rows[0]?.status ?? null;
989
1068
  }
990
- async function getUnacknowledgedMessages(targetAgent) {
1069
+ async function getUnacknowledgedMessages(targetAgent, sessionScope) {
991
1070
  const client = getClient();
1071
+ const scope = strictSessionScopeFilter(sessionScope);
992
1072
  const result = await client.execute({
993
1073
  sql: `SELECT * FROM messages
994
- WHERE target_agent = ? AND status IN ('pending', 'delivered', 'read')
1074
+ WHERE target_agent = ? AND status IN ('pending', 'delivered', 'read')${scope.sql}
995
1075
  ORDER BY id`,
996
- args: [targetAgent]
1076
+ args: [targetAgent, ...scope.args]
997
1077
  });
998
1078
  return result.rows.map((row) => rowToMessage(row));
999
1079
  }
1000
- async function getReadMessages(targetAgent) {
1080
+ async function getReadMessages(targetAgent, sessionScope) {
1001
1081
  const client = getClient();
1082
+ const scope = strictSessionScopeFilter(sessionScope);
1002
1083
  const result = await client.execute({
1003
- sql: "SELECT * FROM messages WHERE target_agent = ? AND status = 'read' ORDER BY id",
1004
- args: [targetAgent]
1084
+ sql: `SELECT * FROM messages
1085
+ WHERE target_agent = ? AND status = 'read'${scope.sql}
1086
+ ORDER BY id`,
1087
+ args: [targetAgent, ...scope.args]
1005
1088
  });
1006
1089
  return result.rows.map((row) => rowToMessage(row));
1007
1090
  }
1008
- async function markFailed(messageId, reason) {
1091
+ async function markFailed(messageId, reason, sessionScope) {
1009
1092
  const client = getClient();
1093
+ const scope = strictSessionScopeFilter(sessionScope);
1010
1094
  await client.execute({
1011
- sql: "UPDATE messages SET status = 'failed', failed_at = ?, failure_reason = ? WHERE id = ?",
1012
- args: [(/* @__PURE__ */ new Date()).toISOString(), reason, messageId]
1095
+ sql: `UPDATE messages SET status = 'failed', failed_at = ?, failure_reason = ?
1096
+ WHERE id = ?${scope.sql}`,
1097
+ args: [(/* @__PURE__ */ new Date()).toISOString(), reason, messageId, ...scope.args]
1013
1098
  });
1014
1099
  }
1015
- async function getFailedMessages() {
1100
+ async function getFailedMessages(sessionScope) {
1016
1101
  const client = getClient();
1102
+ const scope = strictSessionScopeFilter(sessionScope);
1017
1103
  const result = await client.execute({
1018
- sql: "SELECT * FROM messages WHERE status = 'failed' ORDER BY created_at DESC",
1019
- args: []
1104
+ sql: `SELECT * FROM messages WHERE status = 'failed'${scope.sql} ORDER BY created_at DESC`,
1105
+ args: [...scope.args]
1020
1106
  });
1021
1107
  return result.rows.map((row) => rowToMessage(row));
1022
1108
  }
1023
- async function retryPendingMessages() {
1109
+ async function retryPendingMessages(sessionScope) {
1024
1110
  const client = getClient();
1111
+ const scope = strictSessionScopeFilter(sessionScope);
1025
1112
  const result = await client.execute({
1026
1113
  sql: `SELECT * FROM messages
1027
- WHERE status = 'pending' AND retry_count < ?
1114
+ WHERE status = 'pending' AND retry_count < ?${scope.sql}
1028
1115
  ORDER BY id`,
1029
- args: [MAX_RETRIES]
1116
+ args: [MAX_RETRIES, ...scope.args]
1030
1117
  });
1031
1118
  let delivered = 0;
1032
1119
  for (const row of result.rows) {
@@ -3,9 +3,18 @@ var __esm = (fn, res) => function __init() {
3
3
  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
4
4
  };
5
5
 
6
+ // src/lib/secure-files.ts
7
+ import { chmodSync, existsSync, mkdirSync } from "fs";
8
+ import { chmod, mkdir } from "fs/promises";
9
+ var init_secure_files = __esm({
10
+ "src/lib/secure-files.ts"() {
11
+ "use strict";
12
+ }
13
+ });
14
+
6
15
  // src/lib/config.ts
7
- import { readFile, writeFile, mkdir, chmod } from "fs/promises";
8
- import { readFileSync, existsSync, renameSync } from "fs";
16
+ import { readFile, writeFile } from "fs/promises";
17
+ import { readFileSync, existsSync as existsSync2, renameSync } from "fs";
9
18
  import path from "path";
10
19
  import os from "os";
11
20
  function resolveDataDir() {
@@ -13,7 +22,7 @@ function resolveDataDir() {
13
22
  if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
14
23
  const newDir = path.join(os.homedir(), ".exe-os");
15
24
  const legacyDir = path.join(os.homedir(), ".exe-mem");
16
- if (!existsSync(newDir) && existsSync(legacyDir)) {
25
+ if (!existsSync2(newDir) && existsSync2(legacyDir)) {
17
26
  try {
18
27
  renameSync(legacyDir, newDir);
19
28
  process.stderr.write(`[exe-os] Migrated data directory: ~/.exe-mem \u2192 ~/.exe-os
@@ -28,6 +37,7 @@ var EXE_AI_DIR, DB_PATH, MODELS_DIR, CONFIG_PATH, LEGACY_LANCE_PATH, CURRENT_CON
28
37
  var init_config = __esm({
29
38
  "src/lib/config.ts"() {
30
39
  "use strict";
40
+ init_secure_files();
31
41
  EXE_AI_DIR = resolveDataDir();
32
42
  DB_PATH = path.join(EXE_AI_DIR, "memories.db");
33
43
  MODELS_DIR = path.join(EXE_AI_DIR, "models");
@@ -103,19 +113,39 @@ import { createClient } from "@libsql/client";
103
113
  // src/lib/employees.ts
104
114
  init_config();
105
115
  import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
106
- import { existsSync as existsSync2, symlinkSync, readlinkSync, readFileSync as readFileSync2, renameSync as renameSync2, unlinkSync, writeFileSync } from "fs";
116
+ import { existsSync as existsSync3, symlinkSync, readlinkSync, readFileSync as readFileSync2, renameSync as renameSync2, unlinkSync, writeFileSync } from "fs";
107
117
  import { execSync } from "child_process";
108
118
  import path2 from "path";
109
119
  import os2 from "os";
110
120
  var EMPLOYEES_PATH = path2.join(EXE_AI_DIR, "exe-employees.json");
121
+ var IDENTITY_DIR = path2.join(EXE_AI_DIR, "identity");
122
+
123
+ // src/lib/database-adapter.ts
124
+ import os3 from "os";
125
+ import path3 from "path";
126
+ import { createRequire } from "module";
127
+ import { pathToFileURL } from "url";
128
+ var BOOLEAN_COLUMNS_BY_TABLE = {
129
+ memories: /* @__PURE__ */ new Set(["has_error", "draft"]),
130
+ behaviors: /* @__PURE__ */ new Set(["active"]),
131
+ notifications: /* @__PURE__ */ new Set(["read"]),
132
+ users: /* @__PURE__ */ new Set(["has_personal_memory"])
133
+ };
134
+ var BOOLEAN_COLUMN_NAMES = new Set(
135
+ Object.values(BOOLEAN_COLUMNS_BY_TABLE).flatMap((cols) => [...cols])
136
+ );
111
137
 
112
138
  // src/lib/database.ts
113
139
  var _resilientClient = null;
114
140
  var _daemonClient = null;
141
+ var _adapterClient = null;
115
142
  function getClient() {
116
- if (!_resilientClient) {
143
+ if (!_adapterClient) {
117
144
  throw new Error("Database client not initialized. Call initDatabase() first.");
118
145
  }
146
+ if (process.env.DATABASE_URL) {
147
+ return _adapterClient;
148
+ }
119
149
  if (process.env.EXE_IS_DAEMON === "1") {
120
150
  return _resilientClient;
121
151
  }