@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
@@ -90,6 +90,44 @@ var init_db_retry = __esm({
90
90
  }
91
91
  });
92
92
 
93
+ // src/lib/secure-files.ts
94
+ import { chmodSync, existsSync, mkdirSync } from "fs";
95
+ import { chmod, mkdir } from "fs/promises";
96
+ async function ensurePrivateDir(dirPath) {
97
+ await mkdir(dirPath, { recursive: true, mode: PRIVATE_DIR_MODE });
98
+ try {
99
+ await chmod(dirPath, PRIVATE_DIR_MODE);
100
+ } catch {
101
+ }
102
+ }
103
+ function ensurePrivateDirSync(dirPath) {
104
+ mkdirSync(dirPath, { recursive: true, mode: PRIVATE_DIR_MODE });
105
+ try {
106
+ chmodSync(dirPath, PRIVATE_DIR_MODE);
107
+ } catch {
108
+ }
109
+ }
110
+ async function enforcePrivateFile(filePath) {
111
+ try {
112
+ await chmod(filePath, PRIVATE_FILE_MODE);
113
+ } catch {
114
+ }
115
+ }
116
+ function enforcePrivateFileSync(filePath) {
117
+ try {
118
+ if (existsSync(filePath)) chmodSync(filePath, PRIVATE_FILE_MODE);
119
+ } catch {
120
+ }
121
+ }
122
+ var PRIVATE_DIR_MODE, PRIVATE_FILE_MODE;
123
+ var init_secure_files = __esm({
124
+ "src/lib/secure-files.ts"() {
125
+ "use strict";
126
+ PRIVATE_DIR_MODE = 448;
127
+ PRIVATE_FILE_MODE = 384;
128
+ }
129
+ });
130
+
93
131
  // src/lib/config.ts
94
132
  var config_exports = {};
95
133
  __export(config_exports, {
@@ -106,8 +144,8 @@ __export(config_exports, {
106
144
  migrateConfig: () => migrateConfig,
107
145
  saveConfig: () => saveConfig
108
146
  });
109
- import { readFile, writeFile, mkdir, chmod } from "fs/promises";
110
- import { readFileSync, existsSync, renameSync } from "fs";
147
+ import { readFile, writeFile } from "fs/promises";
148
+ import { readFileSync, existsSync as existsSync2, renameSync } from "fs";
111
149
  import path from "path";
112
150
  import os from "os";
113
151
  function resolveDataDir() {
@@ -115,7 +153,7 @@ function resolveDataDir() {
115
153
  if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
116
154
  const newDir = path.join(os.homedir(), ".exe-os");
117
155
  const legacyDir = path.join(os.homedir(), ".exe-mem");
118
- if (!existsSync(newDir) && existsSync(legacyDir)) {
156
+ if (!existsSync2(newDir) && existsSync2(legacyDir)) {
119
157
  try {
120
158
  renameSync(legacyDir, newDir);
121
159
  process.stderr.write(`[exe-os] Migrated data directory: ~/.exe-mem \u2192 ~/.exe-os
@@ -178,9 +216,9 @@ function normalizeAutoUpdate(raw) {
178
216
  }
179
217
  async function loadConfig() {
180
218
  const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
181
- await mkdir(dir, { recursive: true });
219
+ await ensurePrivateDir(dir);
182
220
  const configPath = path.join(dir, "config.json");
183
- if (!existsSync(configPath)) {
221
+ if (!existsSync2(configPath)) {
184
222
  return { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db") };
185
223
  }
186
224
  const raw = await readFile(configPath, "utf-8");
@@ -193,6 +231,7 @@ async function loadConfig() {
193
231
  `);
194
232
  try {
195
233
  await writeFile(configPath, JSON.stringify(migratedCfg, null, 2) + "\n");
234
+ await enforcePrivateFile(configPath);
196
235
  } catch {
197
236
  }
198
237
  }
@@ -211,7 +250,7 @@ async function loadConfig() {
211
250
  function loadConfigSync() {
212
251
  const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
213
252
  const configPath = path.join(dir, "config.json");
214
- if (!existsSync(configPath)) {
253
+ if (!existsSync2(configPath)) {
215
254
  return { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db") };
216
255
  }
217
256
  try {
@@ -229,12 +268,10 @@ function loadConfigSync() {
229
268
  }
230
269
  async function saveConfig(config) {
231
270
  const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
232
- await mkdir(dir, { recursive: true });
271
+ await ensurePrivateDir(dir);
233
272
  const configPath = path.join(dir, "config.json");
234
273
  await writeFile(configPath, JSON.stringify(config, null, 2) + "\n");
235
- if (config.cloud?.apiKey) {
236
- await chmod(configPath, 384);
237
- }
274
+ await enforcePrivateFile(configPath);
238
275
  }
239
276
  async function loadConfigFrom(configPath) {
240
277
  const raw = await readFile(configPath, "utf-8");
@@ -254,6 +291,7 @@ var EXE_AI_DIR, DB_PATH, MODELS_DIR, CONFIG_PATH, LEGACY_LANCE_PATH, CURRENT_CON
254
291
  var init_config = __esm({
255
292
  "src/lib/config.ts"() {
256
293
  "use strict";
294
+ init_secure_files();
257
295
  EXE_AI_DIR = resolveDataDir();
258
296
  DB_PATH = path.join(EXE_AI_DIR, "memories.db");
259
297
  MODELS_DIR = path.join(EXE_AI_DIR, "models");
@@ -332,7 +370,7 @@ var init_config = __esm({
332
370
 
333
371
  // src/lib/employees.ts
334
372
  import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
335
- import { existsSync as existsSync2, symlinkSync, readlinkSync, readFileSync as readFileSync2, renameSync as renameSync2, unlinkSync, writeFileSync } from "fs";
373
+ import { existsSync as existsSync3, symlinkSync, readlinkSync, readFileSync as readFileSync2, renameSync as renameSync2, unlinkSync, writeFileSync } from "fs";
336
374
  import { execSync } from "child_process";
337
375
  import path2 from "path";
338
376
  import os2 from "os";
@@ -353,7 +391,7 @@ function isCoordinatorName(agentName2, employees = loadEmployeesSync()) {
353
391
  return agentName2.toLowerCase() === getCoordinatorName(employees).toLowerCase();
354
392
  }
355
393
  async function loadEmployees(employeesPath = EMPLOYEES_PATH) {
356
- if (!existsSync2(employeesPath)) {
394
+ if (!existsSync3(employeesPath)) {
357
395
  return [];
358
396
  }
359
397
  const raw = await readFile2(employeesPath, "utf-8");
@@ -364,7 +402,7 @@ async function loadEmployees(employeesPath = EMPLOYEES_PATH) {
364
402
  }
365
403
  }
366
404
  function loadEmployeesSync(employeesPath = EMPLOYEES_PATH) {
367
- if (!existsSync2(employeesPath)) return [];
405
+ if (!existsSync3(employeesPath)) return [];
368
406
  try {
369
407
  return JSON.parse(readFileSync2(employeesPath, "utf-8"));
370
408
  } catch {
@@ -985,13 +1023,50 @@ var init_database_adapter = __esm({
985
1023
  }
986
1024
  });
987
1025
 
1026
+ // src/lib/daemon-auth.ts
1027
+ import crypto from "crypto";
1028
+ import path4 from "path";
1029
+ import { existsSync as existsSync4, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
1030
+ function normalizeToken(token) {
1031
+ if (!token) return null;
1032
+ const trimmed = token.trim();
1033
+ return trimmed.length > 0 ? trimmed : null;
1034
+ }
1035
+ function readDaemonToken() {
1036
+ try {
1037
+ if (!existsSync4(DAEMON_TOKEN_PATH)) return null;
1038
+ return normalizeToken(readFileSync3(DAEMON_TOKEN_PATH, "utf8"));
1039
+ } catch {
1040
+ return null;
1041
+ }
1042
+ }
1043
+ function ensureDaemonToken(seed) {
1044
+ const existing = readDaemonToken();
1045
+ if (existing) return existing;
1046
+ const token = normalizeToken(seed) ?? crypto.randomBytes(32).toString("hex");
1047
+ ensurePrivateDirSync(EXE_AI_DIR);
1048
+ writeFileSync2(DAEMON_TOKEN_PATH, `${token}
1049
+ `, "utf8");
1050
+ enforcePrivateFileSync(DAEMON_TOKEN_PATH);
1051
+ return token;
1052
+ }
1053
+ var DAEMON_TOKEN_PATH;
1054
+ var init_daemon_auth = __esm({
1055
+ "src/lib/daemon-auth.ts"() {
1056
+ "use strict";
1057
+ init_config();
1058
+ init_secure_files();
1059
+ DAEMON_TOKEN_PATH = path4.join(EXE_AI_DIR, "exed.token");
1060
+ }
1061
+ });
1062
+
988
1063
  // src/lib/exe-daemon-client.ts
989
1064
  import net from "net";
990
1065
  import os4 from "os";
991
1066
  import { spawn } from "child_process";
992
1067
  import { randomUUID } from "crypto";
993
- import { existsSync as existsSync3, unlinkSync as unlinkSync2, readFileSync as readFileSync3, openSync, closeSync, statSync } from "fs";
994
- import path4 from "path";
1068
+ import { existsSync as existsSync5, unlinkSync as unlinkSync2, readFileSync as readFileSync4, openSync, closeSync, statSync } from "fs";
1069
+ import path5 from "path";
995
1070
  import { fileURLToPath } from "url";
996
1071
  function handleData(chunk) {
997
1072
  _buffer += chunk.toString();
@@ -1019,9 +1094,9 @@ function handleData(chunk) {
1019
1094
  }
1020
1095
  }
1021
1096
  function cleanupStaleFiles() {
1022
- if (existsSync3(PID_PATH)) {
1097
+ if (existsSync5(PID_PATH)) {
1023
1098
  try {
1024
- const pid = parseInt(readFileSync3(PID_PATH, "utf8").trim(), 10);
1099
+ const pid = parseInt(readFileSync4(PID_PATH, "utf8").trim(), 10);
1025
1100
  if (pid > 0) {
1026
1101
  try {
1027
1102
  process.kill(pid, 0);
@@ -1042,11 +1117,11 @@ function cleanupStaleFiles() {
1042
1117
  }
1043
1118
  }
1044
1119
  function findPackageRoot() {
1045
- let dir = path4.dirname(fileURLToPath(import.meta.url));
1046
- const { root } = path4.parse(dir);
1120
+ let dir = path5.dirname(fileURLToPath(import.meta.url));
1121
+ const { root } = path5.parse(dir);
1047
1122
  while (dir !== root) {
1048
- if (existsSync3(path4.join(dir, "package.json"))) return dir;
1049
- dir = path4.dirname(dir);
1123
+ if (existsSync5(path5.join(dir, "package.json"))) return dir;
1124
+ dir = path5.dirname(dir);
1050
1125
  }
1051
1126
  return null;
1052
1127
  }
@@ -1072,16 +1147,17 @@ function spawnDaemon() {
1072
1147
  process.stderr.write("[exed-client] WARN: cannot find package root\n");
1073
1148
  return;
1074
1149
  }
1075
- const daemonPath = path4.join(pkgRoot, "dist", "lib", "exe-daemon.js");
1076
- if (!existsSync3(daemonPath)) {
1150
+ const daemonPath = path5.join(pkgRoot, "dist", "lib", "exe-daemon.js");
1151
+ if (!existsSync5(daemonPath)) {
1077
1152
  process.stderr.write(`[exed-client] WARN: daemon script not found at ${daemonPath}
1078
1153
  `);
1079
1154
  return;
1080
1155
  }
1081
1156
  const resolvedPath = daemonPath;
1157
+ const daemonToken = ensureDaemonToken(process.env[DAEMON_TOKEN_ENV] ?? null);
1082
1158
  process.stderr.write(`[exed-client] Spawning daemon: ${resolvedPath}
1083
1159
  `);
1084
- const logPath = path4.join(path4.dirname(SOCKET_PATH), "exed.log");
1160
+ const logPath = path5.join(path5.dirname(SOCKET_PATH), "exed.log");
1085
1161
  let stderrFd = "ignore";
1086
1162
  try {
1087
1163
  stderrFd = openSync(logPath, "a");
@@ -1099,7 +1175,8 @@ function spawnDaemon() {
1099
1175
  TMUX_PANE: void 0,
1100
1176
  // Prevents resolveExeSession() from scoping to one session
1101
1177
  EXE_DAEMON_SOCK: SOCKET_PATH,
1102
- EXE_DAEMON_PID: PID_PATH
1178
+ EXE_DAEMON_PID: PID_PATH,
1179
+ [DAEMON_TOKEN_ENV]: daemonToken
1103
1180
  }
1104
1181
  });
1105
1182
  child.unref();
@@ -1209,13 +1286,14 @@ function sendDaemonRequest(payload, timeoutMs = REQUEST_TIMEOUT_MS) {
1209
1286
  return;
1210
1287
  }
1211
1288
  const id = randomUUID();
1289
+ const token = process.env[DAEMON_TOKEN_ENV] ?? readDaemonToken();
1212
1290
  const timer = setTimeout(() => {
1213
1291
  _pending.delete(id);
1214
1292
  resolve({ error: "Request timeout" });
1215
1293
  }, timeoutMs);
1216
1294
  _pending.set(id, { resolve, timer });
1217
1295
  try {
1218
- _socket.write(JSON.stringify({ id, ...payload }) + "\n");
1296
+ _socket.write(JSON.stringify({ id, token, ...payload }) + "\n");
1219
1297
  } catch {
1220
1298
  clearTimeout(timer);
1221
1299
  _pending.delete(id);
@@ -1244,9 +1322,9 @@ function killAndRespawnDaemon() {
1244
1322
  }
1245
1323
  try {
1246
1324
  process.stderr.write("[exed-client] Killing daemon for restart...\n");
1247
- if (existsSync3(PID_PATH)) {
1325
+ if (existsSync5(PID_PATH)) {
1248
1326
  try {
1249
- const pid = parseInt(readFileSync3(PID_PATH, "utf8").trim(), 10);
1327
+ const pid = parseInt(readFileSync4(PID_PATH, "utf8").trim(), 10);
1250
1328
  if (pid > 0) {
1251
1329
  try {
1252
1330
  process.kill(pid, "SIGKILL");
@@ -1366,17 +1444,19 @@ function disconnectClient() {
1366
1444
  function isClientConnected() {
1367
1445
  return _connected;
1368
1446
  }
1369
- var SOCKET_PATH, PID_PATH, SPAWN_LOCK_PATH, SPAWN_LOCK_STALE_MS, CONNECT_TIMEOUT_MS, REQUEST_TIMEOUT_MS, _socket, _connected, _buffer, _requestCount, _consecutiveFailures, HEALTH_CHECK_INTERVAL, MAX_RETRIES_BEFORE_RESTART, RETRY_DELAYS_MS, MIN_DAEMON_AGE_MS, _pending, MAX_BUFFER;
1447
+ var SOCKET_PATH, PID_PATH, SPAWN_LOCK_PATH, SPAWN_LOCK_STALE_MS, CONNECT_TIMEOUT_MS, REQUEST_TIMEOUT_MS, DAEMON_TOKEN_ENV, _socket, _connected, _buffer, _requestCount, _consecutiveFailures, HEALTH_CHECK_INTERVAL, MAX_RETRIES_BEFORE_RESTART, RETRY_DELAYS_MS, MIN_DAEMON_AGE_MS, _pending, MAX_BUFFER;
1370
1448
  var init_exe_daemon_client = __esm({
1371
1449
  "src/lib/exe-daemon-client.ts"() {
1372
1450
  "use strict";
1373
1451
  init_config();
1374
- SOCKET_PATH = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ?? path4.join(EXE_AI_DIR, "exed.sock");
1375
- PID_PATH = process.env.EXE_DAEMON_PID ?? process.env.EXE_EMBED_PID ?? path4.join(EXE_AI_DIR, "exed.pid");
1376
- SPAWN_LOCK_PATH = path4.join(EXE_AI_DIR, "exed-spawn.lock");
1452
+ init_daemon_auth();
1453
+ SOCKET_PATH = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ?? path5.join(EXE_AI_DIR, "exed.sock");
1454
+ PID_PATH = process.env.EXE_DAEMON_PID ?? process.env.EXE_EMBED_PID ?? path5.join(EXE_AI_DIR, "exed.pid");
1455
+ SPAWN_LOCK_PATH = path5.join(EXE_AI_DIR, "exed-spawn.lock");
1377
1456
  SPAWN_LOCK_STALE_MS = 3e4;
1378
1457
  CONNECT_TIMEOUT_MS = 15e3;
1379
1458
  REQUEST_TIMEOUT_MS = 3e4;
1459
+ DAEMON_TOKEN_ENV = "EXE_DAEMON_TOKEN";
1380
1460
  _socket = null;
1381
1461
  _connected = false;
1382
1462
  _buffer = "";
@@ -1961,6 +2041,7 @@ async function ensureSchema() {
1961
2041
  project TEXT NOT NULL,
1962
2042
  summary TEXT NOT NULL,
1963
2043
  task_file TEXT,
2044
+ session_scope TEXT,
1964
2045
  read INTEGER NOT NULL DEFAULT 0,
1965
2046
  created_at TEXT NOT NULL
1966
2047
  );
@@ -1969,7 +2050,7 @@ async function ensureSchema() {
1969
2050
  ON notifications(read);
1970
2051
 
1971
2052
  CREATE INDEX IF NOT EXISTS idx_notifications_agent
1972
- ON notifications(agent_id);
2053
+ ON notifications(agent_id, session_scope);
1973
2054
 
1974
2055
  CREATE INDEX IF NOT EXISTS idx_notifications_task_file
1975
2056
  ON notifications(task_file);
@@ -2007,6 +2088,7 @@ async function ensureSchema() {
2007
2088
  target_agent TEXT NOT NULL,
2008
2089
  target_project TEXT,
2009
2090
  target_device TEXT NOT NULL DEFAULT 'local',
2091
+ session_scope TEXT,
2010
2092
  content TEXT NOT NULL,
2011
2093
  priority TEXT DEFAULT 'normal',
2012
2094
  status TEXT DEFAULT 'pending',
@@ -2020,10 +2102,31 @@ async function ensureSchema() {
2020
2102
  );
2021
2103
 
2022
2104
  CREATE INDEX IF NOT EXISTS idx_messages_target
2023
- ON messages(target_agent, status);
2105
+ ON messages(target_agent, session_scope, status);
2024
2106
 
2025
2107
  CREATE INDEX IF NOT EXISTS idx_messages_conversation_order
2026
- ON messages(target_agent, from_agent, server_seq);
2108
+ ON messages(target_agent, session_scope, from_agent, server_seq);
2109
+ `);
2110
+ try {
2111
+ await client.execute({
2112
+ sql: `ALTER TABLE notifications ADD COLUMN session_scope TEXT`,
2113
+ args: []
2114
+ });
2115
+ } catch {
2116
+ }
2117
+ try {
2118
+ await client.execute({
2119
+ sql: `ALTER TABLE messages ADD COLUMN session_scope TEXT`,
2120
+ args: []
2121
+ });
2122
+ } catch {
2123
+ }
2124
+ await client.executeMultiple(`
2125
+ CREATE INDEX IF NOT EXISTS idx_notifications_agent_scope_read
2126
+ ON notifications(agent_id, session_scope, read, created_at);
2127
+
2128
+ CREATE INDEX IF NOT EXISTS idx_messages_target_scope_status
2129
+ ON messages(target_agent, session_scope, status, created_at);
2027
2130
  `);
2028
2131
  try {
2029
2132
  await client.execute({
@@ -2607,6 +2710,13 @@ async function ensureSchema() {
2607
2710
  } catch {
2608
2711
  }
2609
2712
  }
2713
+ try {
2714
+ await client.execute({
2715
+ sql: `UPDATE tasks SET status = 'closed' WHERE status = 'done' AND result IS NOT NULL`,
2716
+ args: []
2717
+ });
2718
+ } catch {
2719
+ }
2610
2720
  }
2611
2721
  async function disposeDatabase() {
2612
2722
  if (_walCheckpointTimer) {
@@ -2646,14 +2756,14 @@ var init_database = __esm({
2646
2756
 
2647
2757
  // src/lib/keychain.ts
2648
2758
  import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
2649
- import { existsSync as existsSync4 } from "fs";
2650
- import path5 from "path";
2759
+ import { existsSync as existsSync6 } from "fs";
2760
+ import path6 from "path";
2651
2761
  import os5 from "os";
2652
2762
  function getKeyDir() {
2653
- return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path5.join(os5.homedir(), ".exe-os");
2763
+ return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path6.join(os5.homedir(), ".exe-os");
2654
2764
  }
2655
2765
  function getKeyPath() {
2656
- return path5.join(getKeyDir(), "master.key");
2766
+ return path6.join(getKeyDir(), "master.key");
2657
2767
  }
2658
2768
  async function tryKeytar() {
2659
2769
  try {
@@ -2674,7 +2784,7 @@ async function getMasterKey() {
2674
2784
  }
2675
2785
  }
2676
2786
  const keyPath = getKeyPath();
2677
- if (!existsSync4(keyPath)) {
2787
+ if (!existsSync6(keyPath)) {
2678
2788
  process.stderr.write(
2679
2789
  `[keychain] Key not found at ${keyPath} (HOME=${os5.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
2680
2790
  `
@@ -2761,6 +2871,7 @@ var shard_manager_exports = {};
2761
2871
  __export(shard_manager_exports, {
2762
2872
  disposeShards: () => disposeShards,
2763
2873
  ensureShardSchema: () => ensureShardSchema,
2874
+ getOpenShardCount: () => getOpenShardCount,
2764
2875
  getReadyShardClient: () => getReadyShardClient,
2765
2876
  getShardClient: () => getShardClient,
2766
2877
  getShardsDir: () => getShardsDir,
@@ -2769,15 +2880,18 @@ __export(shard_manager_exports, {
2769
2880
  listShards: () => listShards,
2770
2881
  shardExists: () => shardExists
2771
2882
  });
2772
- import path6 from "path";
2773
- import { existsSync as existsSync5, mkdirSync, readdirSync } from "fs";
2883
+ import path7 from "path";
2884
+ import { existsSync as existsSync7, mkdirSync as mkdirSync2, readdirSync } from "fs";
2774
2885
  import { createClient as createClient2 } from "@libsql/client";
2775
2886
  function initShardManager(encryptionKey) {
2776
2887
  _encryptionKey = encryptionKey;
2777
- if (!existsSync5(SHARDS_DIR)) {
2778
- mkdirSync(SHARDS_DIR, { recursive: true });
2888
+ if (!existsSync7(SHARDS_DIR)) {
2889
+ mkdirSync2(SHARDS_DIR, { recursive: true });
2779
2890
  }
2780
2891
  _shardingEnabled = true;
2892
+ if (_evictionTimer) clearInterval(_evictionTimer);
2893
+ _evictionTimer = setInterval(evictIdleShards, EVICTION_INTERVAL_MS);
2894
+ _evictionTimer.unref();
2781
2895
  }
2782
2896
  function isShardingEnabled() {
2783
2897
  return _shardingEnabled;
@@ -2794,21 +2908,28 @@ function getShardClient(projectName) {
2794
2908
  throw new Error(`Invalid project name for shard: "${projectName}"`);
2795
2909
  }
2796
2910
  const cached = _shards.get(safeName);
2797
- if (cached) return cached;
2798
- const dbPath = path6.join(SHARDS_DIR, `${safeName}.db`);
2911
+ if (cached) {
2912
+ _shardLastAccess.set(safeName, Date.now());
2913
+ return cached;
2914
+ }
2915
+ while (_shards.size >= MAX_OPEN_SHARDS) {
2916
+ evictLRU();
2917
+ }
2918
+ const dbPath = path7.join(SHARDS_DIR, `${safeName}.db`);
2799
2919
  const client = createClient2({
2800
2920
  url: `file:${dbPath}`,
2801
2921
  encryptionKey: _encryptionKey
2802
2922
  });
2803
2923
  _shards.set(safeName, client);
2924
+ _shardLastAccess.set(safeName, Date.now());
2804
2925
  return client;
2805
2926
  }
2806
2927
  function shardExists(projectName) {
2807
2928
  const safeName = projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
2808
- return existsSync5(path6.join(SHARDS_DIR, `${safeName}.db`));
2929
+ return existsSync7(path7.join(SHARDS_DIR, `${safeName}.db`));
2809
2930
  }
2810
2931
  function listShards() {
2811
- if (!existsSync5(SHARDS_DIR)) return [];
2932
+ if (!existsSync7(SHARDS_DIR)) return [];
2812
2933
  return readdirSync(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
2813
2934
  }
2814
2935
  async function ensureShardSchema(client) {
@@ -2860,6 +2981,8 @@ async function ensureShardSchema(client) {
2860
2981
  for (const col of [
2861
2982
  "ALTER TABLE memories ADD COLUMN task_id TEXT",
2862
2983
  "ALTER TABLE memories ADD COLUMN consolidated INTEGER NOT NULL DEFAULT 0",
2984
+ "ALTER TABLE memories ADD COLUMN author_device_id TEXT",
2985
+ "ALTER TABLE memories ADD COLUMN scope TEXT NOT NULL DEFAULT 'business'",
2863
2986
  "ALTER TABLE memories ADD COLUMN importance INTEGER DEFAULT 5",
2864
2987
  "ALTER TABLE memories ADD COLUMN status TEXT DEFAULT 'active'",
2865
2988
  "ALTER TABLE memories ADD COLUMN wiki_synced INTEGER DEFAULT 0",
@@ -2997,21 +3120,69 @@ async function getReadyShardClient(projectName) {
2997
3120
  await ensureShardSchema(client);
2998
3121
  return client;
2999
3122
  }
3123
+ function evictLRU() {
3124
+ let oldest = null;
3125
+ let oldestTime = Infinity;
3126
+ for (const [name, time] of _shardLastAccess) {
3127
+ if (time < oldestTime) {
3128
+ oldestTime = time;
3129
+ oldest = name;
3130
+ }
3131
+ }
3132
+ if (oldest) {
3133
+ const client = _shards.get(oldest);
3134
+ if (client) {
3135
+ client.close();
3136
+ }
3137
+ _shards.delete(oldest);
3138
+ _shardLastAccess.delete(oldest);
3139
+ }
3140
+ }
3141
+ function evictIdleShards() {
3142
+ const now = Date.now();
3143
+ const toEvict = [];
3144
+ for (const [name, lastAccess] of _shardLastAccess) {
3145
+ if (now - lastAccess > SHARD_IDLE_MS) {
3146
+ toEvict.push(name);
3147
+ }
3148
+ }
3149
+ for (const name of toEvict) {
3150
+ const client = _shards.get(name);
3151
+ if (client) {
3152
+ client.close();
3153
+ }
3154
+ _shards.delete(name);
3155
+ _shardLastAccess.delete(name);
3156
+ }
3157
+ }
3158
+ function getOpenShardCount() {
3159
+ return _shards.size;
3160
+ }
3000
3161
  function disposeShards() {
3162
+ if (_evictionTimer) {
3163
+ clearInterval(_evictionTimer);
3164
+ _evictionTimer = null;
3165
+ }
3001
3166
  for (const [, client] of _shards) {
3002
3167
  client.close();
3003
3168
  }
3004
3169
  _shards.clear();
3170
+ _shardLastAccess.clear();
3005
3171
  _shardingEnabled = false;
3006
3172
  _encryptionKey = null;
3007
3173
  }
3008
- var SHARDS_DIR, _shards, _encryptionKey, _shardingEnabled;
3174
+ var SHARDS_DIR, SHARD_IDLE_MS, MAX_OPEN_SHARDS, EVICTION_INTERVAL_MS, _shards, _shardLastAccess, _evictionTimer, _encryptionKey, _shardingEnabled;
3009
3175
  var init_shard_manager = __esm({
3010
3176
  "src/lib/shard-manager.ts"() {
3011
3177
  "use strict";
3012
3178
  init_config();
3013
- SHARDS_DIR = path6.join(EXE_AI_DIR, "shards");
3179
+ SHARDS_DIR = path7.join(EXE_AI_DIR, "shards");
3180
+ SHARD_IDLE_MS = 5 * 60 * 1e3;
3181
+ MAX_OPEN_SHARDS = 10;
3182
+ EVICTION_INTERVAL_MS = 60 * 1e3;
3014
3183
  _shards = /* @__PURE__ */ new Map();
3184
+ _shardLastAccess = /* @__PURE__ */ new Map();
3185
+ _evictionTimer = null;
3015
3186
  _encryptionKey = null;
3016
3187
  _shardingEnabled = false;
3017
3188
  }
@@ -3775,13 +3946,13 @@ var init_store = __esm({
3775
3946
  });
3776
3947
 
3777
3948
  // src/lib/session-registry.ts
3778
- import { readFileSync as readFileSync4, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2, existsSync as existsSync6 } from "fs";
3779
- import path7 from "path";
3949
+ import { readFileSync as readFileSync5, writeFileSync as writeFileSync3, mkdirSync as mkdirSync3, existsSync as existsSync8 } from "fs";
3950
+ import path8 from "path";
3780
3951
  import os6 from "os";
3781
3952
  function registerSession(entry) {
3782
- const dir = path7.dirname(REGISTRY_PATH);
3783
- if (!existsSync6(dir)) {
3784
- mkdirSync2(dir, { recursive: true });
3953
+ const dir = path8.dirname(REGISTRY_PATH);
3954
+ if (!existsSync8(dir)) {
3955
+ mkdirSync3(dir, { recursive: true });
3785
3956
  }
3786
3957
  const sessions = listSessions();
3787
3958
  const idx = sessions.findIndex((s) => s.windowName === entry.windowName);
@@ -3790,11 +3961,11 @@ function registerSession(entry) {
3790
3961
  } else {
3791
3962
  sessions.push(entry);
3792
3963
  }
3793
- writeFileSync2(REGISTRY_PATH, JSON.stringify(sessions, null, 2));
3964
+ writeFileSync3(REGISTRY_PATH, JSON.stringify(sessions, null, 2));
3794
3965
  }
3795
3966
  function listSessions() {
3796
3967
  try {
3797
- const raw = readFileSync4(REGISTRY_PATH, "utf8");
3968
+ const raw = readFileSync5(REGISTRY_PATH, "utf8");
3798
3969
  return JSON.parse(raw);
3799
3970
  } catch {
3800
3971
  return [];
@@ -3804,7 +3975,7 @@ var REGISTRY_PATH;
3804
3975
  var init_session_registry = __esm({
3805
3976
  "src/lib/session-registry.ts"() {
3806
3977
  "use strict";
3807
- REGISTRY_PATH = path7.join(os6.homedir(), ".exe-os", "session-registry.json");
3978
+ REGISTRY_PATH = path8.join(os6.homedir(), ".exe-os", "session-registry.json");
3808
3979
  }
3809
3980
  });
3810
3981
 
@@ -4084,12 +4255,12 @@ var init_runtime_table = __esm({
4084
4255
  });
4085
4256
 
4086
4257
  // src/lib/agent-config.ts
4087
- import { readFileSync as readFileSync5, writeFileSync as writeFileSync3, existsSync as existsSync7, mkdirSync as mkdirSync3 } from "fs";
4088
- import path8 from "path";
4258
+ import { readFileSync as readFileSync6, writeFileSync as writeFileSync4, existsSync as existsSync9 } from "fs";
4259
+ import path9 from "path";
4089
4260
  function loadAgentConfig() {
4090
- if (!existsSync7(AGENT_CONFIG_PATH)) return {};
4261
+ if (!existsSync9(AGENT_CONFIG_PATH)) return {};
4091
4262
  try {
4092
- return JSON.parse(readFileSync5(AGENT_CONFIG_PATH, "utf-8"));
4263
+ return JSON.parse(readFileSync6(AGENT_CONFIG_PATH, "utf-8"));
4093
4264
  } catch {
4094
4265
  return {};
4095
4266
  }
@@ -4108,7 +4279,8 @@ var init_agent_config = __esm({
4108
4279
  "use strict";
4109
4280
  init_config();
4110
4281
  init_runtime_table();
4111
- AGENT_CONFIG_PATH = path8.join(EXE_AI_DIR, "agent-config.json");
4282
+ init_secure_files();
4283
+ AGENT_CONFIG_PATH = path9.join(EXE_AI_DIR, "agent-config.json");
4112
4284
  DEFAULT_MODELS = {
4113
4285
  claude: "claude-opus-4",
4114
4286
  codex: RUNTIME_TABLE.codex?.defaultModel ?? "gpt-5.4",
@@ -4126,17 +4298,17 @@ __export(intercom_queue_exports, {
4126
4298
  queueIntercom: () => queueIntercom,
4127
4299
  readQueue: () => readQueue
4128
4300
  });
4129
- import { readFileSync as readFileSync6, writeFileSync as writeFileSync4, renameSync as renameSync3, existsSync as existsSync8, mkdirSync as mkdirSync4 } from "fs";
4130
- import path9 from "path";
4301
+ import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, renameSync as renameSync3, existsSync as existsSync10, mkdirSync as mkdirSync4 } from "fs";
4302
+ import path10 from "path";
4131
4303
  import os7 from "os";
4132
4304
  function ensureDir() {
4133
- const dir = path9.dirname(QUEUE_PATH);
4134
- if (!existsSync8(dir)) mkdirSync4(dir, { recursive: true });
4305
+ const dir = path10.dirname(QUEUE_PATH);
4306
+ if (!existsSync10(dir)) mkdirSync4(dir, { recursive: true });
4135
4307
  }
4136
4308
  function readQueue() {
4137
4309
  try {
4138
- if (!existsSync8(QUEUE_PATH)) return [];
4139
- return JSON.parse(readFileSync6(QUEUE_PATH, "utf8"));
4310
+ if (!existsSync10(QUEUE_PATH)) return [];
4311
+ return JSON.parse(readFileSync7(QUEUE_PATH, "utf8"));
4140
4312
  } catch {
4141
4313
  return [];
4142
4314
  }
@@ -4144,7 +4316,7 @@ function readQueue() {
4144
4316
  function writeQueue(queue) {
4145
4317
  ensureDir();
4146
4318
  const tmp = `${QUEUE_PATH}.tmp`;
4147
- writeFileSync4(tmp, JSON.stringify(queue, null, 2));
4319
+ writeFileSync5(tmp, JSON.stringify(queue, null, 2));
4148
4320
  renameSync3(tmp, QUEUE_PATH);
4149
4321
  }
4150
4322
  function queueIntercom(targetSession, reason) {
@@ -4236,26 +4408,29 @@ var QUEUE_PATH, MAX_RETRIES2, TTL_MS, INTERCOM_LOG;
4236
4408
  var init_intercom_queue = __esm({
4237
4409
  "src/lib/intercom-queue.ts"() {
4238
4410
  "use strict";
4239
- QUEUE_PATH = path9.join(os7.homedir(), ".exe-os", "intercom-queue.json");
4411
+ QUEUE_PATH = path10.join(os7.homedir(), ".exe-os", "intercom-queue.json");
4240
4412
  MAX_RETRIES2 = 5;
4241
4413
  TTL_MS = 60 * 60 * 1e3;
4242
- INTERCOM_LOG = path9.join(os7.homedir(), ".exe-os", "intercom.log");
4414
+ INTERCOM_LOG = path10.join(os7.homedir(), ".exe-os", "intercom.log");
4243
4415
  }
4244
4416
  });
4245
4417
 
4246
4418
  // src/lib/license.ts
4247
- import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, existsSync as existsSync9, mkdirSync as mkdirSync5 } from "fs";
4419
+ import { readFileSync as readFileSync8, writeFileSync as writeFileSync6, existsSync as existsSync11, mkdirSync as mkdirSync5 } from "fs";
4248
4420
  import { randomUUID as randomUUID3 } from "crypto";
4249
- import path10 from "path";
4421
+ import { createRequire as createRequire2 } from "module";
4422
+ import { pathToFileURL as pathToFileURL2 } from "url";
4423
+ import os8 from "os";
4424
+ import path11 from "path";
4250
4425
  import { jwtVerify, importSPKI } from "jose";
4251
4426
  var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH, PLAN_LIMITS;
4252
4427
  var init_license = __esm({
4253
4428
  "src/lib/license.ts"() {
4254
4429
  "use strict";
4255
4430
  init_config();
4256
- LICENSE_PATH = path10.join(EXE_AI_DIR, "license.key");
4257
- CACHE_PATH = path10.join(EXE_AI_DIR, "license-cache.json");
4258
- DEVICE_ID_PATH = path10.join(EXE_AI_DIR, "device-id");
4431
+ LICENSE_PATH = path11.join(EXE_AI_DIR, "license.key");
4432
+ CACHE_PATH = path11.join(EXE_AI_DIR, "license-cache.json");
4433
+ DEVICE_ID_PATH = path11.join(EXE_AI_DIR, "device-id");
4259
4434
  PLAN_LIMITS = {
4260
4435
  free: { devices: 1, employees: 1, memories: 5e3 },
4261
4436
  pro: { devices: 3, employees: 5, memories: 1e5 },
@@ -4267,12 +4442,12 @@ var init_license = __esm({
4267
4442
  });
4268
4443
 
4269
4444
  // src/lib/plan-limits.ts
4270
- import { readFileSync as readFileSync8, existsSync as existsSync10 } from "fs";
4271
- import path11 from "path";
4445
+ import { readFileSync as readFileSync9, existsSync as existsSync12 } from "fs";
4446
+ import path12 from "path";
4272
4447
  function getLicenseSync() {
4273
4448
  try {
4274
- if (!existsSync10(CACHE_PATH2)) return freeLicense();
4275
- const raw = JSON.parse(readFileSync8(CACHE_PATH2, "utf8"));
4449
+ if (!existsSync12(CACHE_PATH2)) return freeLicense();
4450
+ const raw = JSON.parse(readFileSync9(CACHE_PATH2, "utf8"));
4276
4451
  if (!raw.token || typeof raw.token !== "string") return freeLicense();
4277
4452
  const parts = raw.token.split(".");
4278
4453
  if (parts.length !== 3) return freeLicense();
@@ -4310,8 +4485,8 @@ function assertEmployeeLimitSync(rosterPath) {
4310
4485
  const filePath = rosterPath ?? EMPLOYEES_PATH;
4311
4486
  let count = 0;
4312
4487
  try {
4313
- if (existsSync10(filePath)) {
4314
- const raw = readFileSync8(filePath, "utf8");
4488
+ if (existsSync12(filePath)) {
4489
+ const raw = readFileSync9(filePath, "utf8");
4315
4490
  const employees = JSON.parse(raw);
4316
4491
  count = Array.isArray(employees) ? employees.length : 0;
4317
4492
  }
@@ -4340,29 +4515,30 @@ var init_plan_limits = __esm({
4340
4515
  this.name = "PlanLimitError";
4341
4516
  }
4342
4517
  };
4343
- CACHE_PATH2 = path11.join(EXE_AI_DIR, "license-cache.json");
4518
+ CACHE_PATH2 = path12.join(EXE_AI_DIR, "license-cache.json");
4344
4519
  }
4345
4520
  });
4346
4521
 
4347
4522
  // src/lib/notifications.ts
4348
- import crypto from "crypto";
4349
- import path12 from "path";
4350
- import os8 from "os";
4523
+ import crypto2 from "crypto";
4524
+ import path13 from "path";
4525
+ import os9 from "os";
4351
4526
  import {
4352
- readFileSync as readFileSync9,
4527
+ readFileSync as readFileSync10,
4353
4528
  readdirSync as readdirSync2,
4354
4529
  unlinkSync as unlinkSync3,
4355
- existsSync as existsSync11,
4530
+ existsSync as existsSync13,
4356
4531
  rmdirSync
4357
4532
  } from "fs";
4358
4533
  async function writeNotification(notification) {
4359
4534
  try {
4360
4535
  const client = getClient();
4361
- const id = crypto.randomUUID();
4536
+ const id = crypto2.randomUUID();
4362
4537
  const now = (/* @__PURE__ */ new Date()).toISOString();
4538
+ const sessionScope = notification.sessionScope === void 0 ? getCurrentSessionScope() : notification.sessionScope;
4363
4539
  await client.execute({
4364
- sql: `INSERT INTO notifications (id, agent_id, agent_role, event, project, summary, task_file, read, created_at)
4365
- VALUES (?, ?, ?, ?, ?, ?, ?, 0, ?)`,
4540
+ sql: `INSERT INTO notifications (id, agent_id, agent_role, event, project, summary, task_file, session_scope, read, created_at)
4541
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, 0, ?)`,
4366
4542
  args: [
4367
4543
  id,
4368
4544
  notification.agentId,
@@ -4371,6 +4547,7 @@ async function writeNotification(notification) {
4371
4547
  notification.project,
4372
4548
  notification.summary,
4373
4549
  notification.taskFile ?? null,
4550
+ sessionScope,
4374
4551
  now
4375
4552
  ]
4376
4553
  });
@@ -4379,12 +4556,14 @@ async function writeNotification(notification) {
4379
4556
  `);
4380
4557
  }
4381
4558
  }
4382
- async function markAsReadByTaskFile(taskFile) {
4559
+ async function markAsReadByTaskFile(taskFile, sessionScope) {
4383
4560
  try {
4384
4561
  const client = getClient();
4562
+ const scope = strictSessionScopeFilter(sessionScope);
4385
4563
  await client.execute({
4386
- sql: "UPDATE notifications SET read = 1 WHERE task_file = ? AND read = 0",
4387
- args: [taskFile]
4564
+ sql: `UPDATE notifications SET read = 1
4565
+ WHERE task_file = ? AND read = 0${scope.sql}`,
4566
+ args: [taskFile, ...scope.args]
4388
4567
  });
4389
4568
  } catch {
4390
4569
  }
@@ -4393,11 +4572,12 @@ var init_notifications = __esm({
4393
4572
  "src/lib/notifications.ts"() {
4394
4573
  "use strict";
4395
4574
  init_database();
4575
+ init_task_scope();
4396
4576
  }
4397
4577
  });
4398
4578
 
4399
4579
  // src/lib/session-kill-telemetry.ts
4400
- import crypto2 from "crypto";
4580
+ import crypto3 from "crypto";
4401
4581
  async function recordSessionKill(input) {
4402
4582
  try {
4403
4583
  const client = getClient();
@@ -4407,7 +4587,7 @@ async function recordSessionKill(input) {
4407
4587
  ticks_idle, estimated_tokens_saved)
4408
4588
  VALUES (?, ?, ?, ?, ?, ?, ?)`,
4409
4589
  args: [
4410
- crypto2.randomUUID(),
4590
+ crypto3.randomUUID(),
4411
4591
  input.sessionName,
4412
4592
  input.agentId,
4413
4593
  (/* @__PURE__ */ new Date()).toISOString(),
@@ -4447,12 +4627,12 @@ __export(tasks_crud_exports, {
4447
4627
  updateTaskStatus: () => updateTaskStatus,
4448
4628
  writeCheckpoint: () => writeCheckpoint
4449
4629
  });
4450
- import crypto3 from "crypto";
4451
- import path13 from "path";
4452
- import os9 from "os";
4630
+ import crypto4 from "crypto";
4631
+ import path14 from "path";
4632
+ import os10 from "os";
4453
4633
  import { execSync as execSync4 } from "child_process";
4454
4634
  import { mkdir as mkdir4, writeFile as writeFile4, appendFile } from "fs/promises";
4455
- import { existsSync as existsSync12, readFileSync as readFileSync10 } from "fs";
4635
+ import { existsSync as existsSync14, readFileSync as readFileSync11 } from "fs";
4456
4636
  async function writeCheckpoint(input) {
4457
4637
  const client = getClient();
4458
4638
  const row = await resolveTask(client, input.taskId);
@@ -4568,7 +4748,7 @@ async function resolveTask(client, identifier, scopeSession) {
4568
4748
  }
4569
4749
  async function createTaskCore(input) {
4570
4750
  const client = getClient();
4571
- const id = crypto3.randomUUID();
4751
+ const id = crypto4.randomUUID();
4572
4752
  const now = (/* @__PURE__ */ new Date()).toISOString();
4573
4753
  const slug = slugify(input.title);
4574
4754
  let earlySessionScope = null;
@@ -4627,8 +4807,8 @@ ${laneWarning}` : laneWarning;
4627
4807
  }
4628
4808
  if (input.baseDir) {
4629
4809
  try {
4630
- await mkdir4(path13.join(input.baseDir, "exe", "output"), { recursive: true });
4631
- await mkdir4(path13.join(input.baseDir, "exe", "research"), { recursive: true });
4810
+ await mkdir4(path14.join(input.baseDir, "exe", "output"), { recursive: true });
4811
+ await mkdir4(path14.join(input.baseDir, "exe", "research"), { recursive: true });
4632
4812
  await ensureArchitectureDoc(input.baseDir, input.projectName);
4633
4813
  await ensureGitignoreExe(input.baseDir);
4634
4814
  } catch {
@@ -4664,13 +4844,19 @@ ${laneWarning}` : laneWarning;
4664
4844
  });
4665
4845
  if (input.baseDir) {
4666
4846
  try {
4667
- const EXE_OS_DIR = path13.join(os9.homedir(), ".exe-os");
4668
- const mdPath = path13.join(EXE_OS_DIR, taskFile);
4669
- const mdDir = path13.dirname(mdPath);
4670
- if (!existsSync12(mdDir)) await mkdir4(mdDir, { recursive: true });
4847
+ const EXE_OS_DIR = path14.join(os10.homedir(), ".exe-os");
4848
+ const mdPath = path14.join(EXE_OS_DIR, taskFile);
4849
+ const mdDir = path14.dirname(mdPath);
4850
+ if (!existsSync14(mdDir)) await mkdir4(mdDir, { recursive: true });
4671
4851
  const reviewer = input.reviewer ?? input.assignedBy;
4672
4852
  const mdContent = `# ${input.title}
4673
4853
 
4854
+ ## MANDATORY: When done
4855
+
4856
+ You MUST call update_task with status "done" and a result summary when finished.
4857
+ If you skip this, your reviewer will not know you're done and your work won't be reviewed.
4858
+ Do NOT let a failed commit or any error prevent you from calling update_task(done).
4859
+
4674
4860
  **ID:** ${id}
4675
4861
  **Status:** ${initialStatus}
4676
4862
  **Priority:** ${input.priority}
@@ -4684,12 +4870,6 @@ ${laneWarning}` : laneWarning;
4684
4870
  ## Context
4685
4871
 
4686
4872
  ${input.context}
4687
-
4688
- ## MANDATORY: When done
4689
-
4690
- You MUST call update_task with status "done" and a result summary when finished.
4691
- If you skip this, your reviewer will not know you're done and your work won't be reviewed.
4692
- Do NOT let a failed commit or any error prevent you from calling update_task(done).
4693
4873
  `;
4694
4874
  await writeFile4(mdPath, mdContent, "utf-8");
4695
4875
  } catch (err) {
@@ -4938,7 +5118,7 @@ ${input.result}` : `\u26A0\uFE0F ${warning}`;
4938
5118
  await client.execute("PRAGMA wal_checkpoint(PASSIVE)");
4939
5119
  } catch {
4940
5120
  }
4941
- if (input.status === "done" || input.status === "cancelled") {
5121
+ if (input.status === "done" || input.status === "cancelled" || input.status === "closed") {
4942
5122
  try {
4943
5123
  const { clearQueueForAgent: clearQueueForAgent2 } = await Promise.resolve().then(() => (init_intercom_queue(), intercom_queue_exports));
4944
5124
  clearQueueForAgent2(String(row.assigned_to));
@@ -4967,9 +5147,9 @@ async function deleteTaskCore(taskId, _baseDir) {
4967
5147
  return { taskFile, assignedTo, assignedBy, taskSlug };
4968
5148
  }
4969
5149
  async function ensureArchitectureDoc(baseDir, projectName) {
4970
- const archPath = path13.join(baseDir, "exe", "ARCHITECTURE.md");
5150
+ const archPath = path14.join(baseDir, "exe", "ARCHITECTURE.md");
4971
5151
  try {
4972
- if (existsSync12(archPath)) return;
5152
+ if (existsSync14(archPath)) return;
4973
5153
  const template = [
4974
5154
  `# ${projectName} \u2014 System Architecture`,
4975
5155
  "",
@@ -5002,10 +5182,10 @@ async function ensureArchitectureDoc(baseDir, projectName) {
5002
5182
  }
5003
5183
  }
5004
5184
  async function ensureGitignoreExe(baseDir) {
5005
- const gitignorePath = path13.join(baseDir, ".gitignore");
5185
+ const gitignorePath = path14.join(baseDir, ".gitignore");
5006
5186
  try {
5007
- if (existsSync12(gitignorePath)) {
5008
- const content = readFileSync10(gitignorePath, "utf-8");
5187
+ if (existsSync14(gitignorePath)) {
5188
+ const content = readFileSync11(gitignorePath, "utf-8");
5009
5189
  if (/^\/?exe\/?$/m.test(content)) return;
5010
5190
  await appendFile(gitignorePath, "\n# Employee task assignments (private)\n/exe/\n");
5011
5191
  } else {
@@ -5048,8 +5228,8 @@ __export(tasks_review_exports, {
5048
5228
  isStale: () => isStale,
5049
5229
  listPendingReviews: () => listPendingReviews
5050
5230
  });
5051
- import path14 from "path";
5052
- import { existsSync as existsSync13, readdirSync as readdirSync3, unlinkSync as unlinkSync4 } from "fs";
5231
+ import path15 from "path";
5232
+ import { existsSync as existsSync15, readdirSync as readdirSync3, unlinkSync as unlinkSync4 } from "fs";
5053
5233
  function formatAge(isoTimestamp) {
5054
5234
  if (!isoTimestamp) return "";
5055
5235
  const ms = Date.now() - new Date(isoTimestamp).getTime();
@@ -5067,54 +5247,38 @@ function isStale(isoTimestamp) {
5067
5247
  }
5068
5248
  async function countPendingReviews(sessionScope) {
5069
5249
  const client = getClient();
5070
- if (sessionScope) {
5071
- const result2 = await client.execute({
5072
- sql: "SELECT COUNT(*) as cnt FROM tasks WHERE status = 'needs_review' AND session_scope = ?",
5073
- args: [sessionScope]
5074
- });
5075
- return Number(result2.rows[0]?.cnt) || 0;
5076
- }
5250
+ const scope = strictSessionScopeFilter(
5251
+ sessionScope === void 0 ? getCurrentSessionScope() : sessionScope
5252
+ );
5077
5253
  const result = await client.execute({
5078
- sql: "SELECT COUNT(*) as cnt FROM tasks WHERE status = 'needs_review'",
5079
- args: []
5254
+ sql: `SELECT COUNT(*) as cnt FROM tasks
5255
+ WHERE status = 'needs_review'${scope.sql}`,
5256
+ args: [...scope.args]
5080
5257
  });
5081
5258
  return Number(result.rows[0]?.cnt) || 0;
5082
5259
  }
5083
5260
  async function countNewPendingReviewsSince(sinceIso, sessionScope) {
5084
5261
  const client = getClient();
5085
- if (sessionScope) {
5086
- const result2 = await client.execute({
5087
- sql: `SELECT COUNT(*) as cnt FROM tasks
5088
- WHERE status = 'needs_review' AND updated_at > ?
5089
- AND session_scope = ?`,
5090
- args: [sinceIso, sessionScope]
5091
- });
5092
- return Number(result2.rows[0]?.cnt) || 0;
5093
- }
5262
+ const scope = strictSessionScopeFilter(
5263
+ sessionScope === void 0 ? getCurrentSessionScope() : sessionScope
5264
+ );
5094
5265
  const result = await client.execute({
5095
5266
  sql: `SELECT COUNT(*) as cnt FROM tasks
5096
- WHERE status = 'needs_review' AND updated_at > ?`,
5097
- args: [sinceIso]
5267
+ WHERE status = 'needs_review' AND updated_at > ?${scope.sql}`,
5268
+ args: [sinceIso, ...scope.args]
5098
5269
  });
5099
5270
  return Number(result.rows[0]?.cnt) || 0;
5100
5271
  }
5101
5272
  async function listPendingReviews(limit, sessionScope) {
5102
5273
  const client = getClient();
5103
- if (sessionScope) {
5104
- const result2 = await client.execute({
5105
- sql: `SELECT title, assigned_to, project_name, updated_at FROM tasks
5106
- WHERE status = 'needs_review'
5107
- AND session_scope = ?
5108
- ORDER BY updated_at ASC LIMIT ?`,
5109
- args: [sessionScope, limit]
5110
- });
5111
- return result2.rows;
5112
- }
5274
+ const scope = strictSessionScopeFilter(
5275
+ sessionScope === void 0 ? getCurrentSessionScope() : sessionScope
5276
+ );
5113
5277
  const result = await client.execute({
5114
5278
  sql: `SELECT title, assigned_to, project_name, updated_at FROM tasks
5115
- WHERE status = 'needs_review'
5279
+ WHERE status = 'needs_review'${scope.sql}
5116
5280
  ORDER BY updated_at ASC LIMIT ?`,
5117
- args: [limit]
5281
+ args: [...scope.args, limit]
5118
5282
  });
5119
5283
  return result.rows;
5120
5284
  }
@@ -5126,7 +5290,7 @@ async function cleanupOrphanedReviews() {
5126
5290
  WHERE status IN ('open', 'needs_review', 'in_progress')
5127
5291
  AND assigned_by = 'system'
5128
5292
  AND title LIKE 'Review:%'
5129
- AND parent_task_id IN (SELECT id FROM tasks WHERE status IN ('done', 'cancelled'))`,
5293
+ AND parent_task_id IN (SELECT id FROM tasks WHERE status IN ('done', 'cancelled', 'closed'))`,
5130
5294
  args: [now]
5131
5295
  });
5132
5296
  const r1b = await client.execute({
@@ -5334,11 +5498,11 @@ async function cleanupReviewFile(row, taskFile, _baseDir) {
5334
5498
  );
5335
5499
  }
5336
5500
  try {
5337
- const cacheDir = path14.join(EXE_AI_DIR, "session-cache");
5338
- if (existsSync13(cacheDir)) {
5501
+ const cacheDir = path15.join(EXE_AI_DIR, "session-cache");
5502
+ if (existsSync15(cacheDir)) {
5339
5503
  for (const f of readdirSync3(cacheDir)) {
5340
5504
  if (f.startsWith("review-notified-")) {
5341
- unlinkSync4(path14.join(cacheDir, f));
5505
+ unlinkSync4(path15.join(cacheDir, f));
5342
5506
  }
5343
5507
  }
5344
5508
  }
@@ -5355,11 +5519,12 @@ var init_tasks_review = __esm({
5355
5519
  init_tmux_routing();
5356
5520
  init_session_key();
5357
5521
  init_state_bus();
5522
+ init_task_scope();
5358
5523
  }
5359
5524
  });
5360
5525
 
5361
5526
  // src/lib/tasks-chain.ts
5362
- import path15 from "path";
5527
+ import path16 from "path";
5363
5528
  import { readFile as readFile4, writeFile as writeFile5 } from "fs/promises";
5364
5529
  async function cascadeUnblock(taskId, baseDir, now) {
5365
5530
  const client = getClient();
@@ -5376,7 +5541,7 @@ async function cascadeUnblock(taskId, baseDir, now) {
5376
5541
  });
5377
5542
  for (const ur of unblockedRows.rows) {
5378
5543
  try {
5379
- const ubFile = path15.join(baseDir, String(ur.task_file));
5544
+ const ubFile = path16.join(baseDir, String(ur.task_file));
5380
5545
  let ubContent = await readFile4(ubFile, "utf-8");
5381
5546
  ubContent = ubContent.replace(/\*\*Status:\*\* blocked/, "**Status:** open");
5382
5547
  ubContent = ubContent.replace(/\n\*\*Blocked by:\*\*.*\n/, "\n");
@@ -5411,7 +5576,7 @@ async function checkSubtaskCompletion(parentTaskId, projectName) {
5411
5576
  const scScope = sessionScopeFilter();
5412
5577
  const remaining = await client.execute({
5413
5578
  sql: `SELECT COUNT(*) as cnt FROM tasks
5414
- WHERE parent_task_id = ? AND status NOT IN ('done', 'cancelled')${scScope.sql}`,
5579
+ WHERE parent_task_id = ? AND status NOT IN ('done', 'cancelled', 'closed')${scScope.sql}`,
5415
5580
  args: [parentTaskId, ...scScope.args]
5416
5581
  });
5417
5582
  const cnt = Number(remaining.rows[0]?.cnt ?? 1);
@@ -5445,7 +5610,7 @@ var init_tasks_chain = __esm({
5445
5610
 
5446
5611
  // src/lib/project-name.ts
5447
5612
  import { execSync as execSync5 } from "child_process";
5448
- import path16 from "path";
5613
+ import path17 from "path";
5449
5614
  function getProjectName(cwd) {
5450
5615
  const dir = cwd ?? process.cwd();
5451
5616
  if (_cached2 && _cachedCwd === dir) return _cached2;
@@ -5458,7 +5623,7 @@ function getProjectName(cwd) {
5458
5623
  timeout: 2e3,
5459
5624
  stdio: ["pipe", "pipe", "pipe"]
5460
5625
  }).trim();
5461
- repoRoot = path16.dirname(gitCommonDir);
5626
+ repoRoot = path17.dirname(gitCommonDir);
5462
5627
  } catch {
5463
5628
  repoRoot = execSync5("git rev-parse --show-toplevel", {
5464
5629
  cwd: dir,
@@ -5467,11 +5632,11 @@ function getProjectName(cwd) {
5467
5632
  stdio: ["pipe", "pipe", "pipe"]
5468
5633
  }).trim();
5469
5634
  }
5470
- _cached2 = path16.basename(repoRoot);
5635
+ _cached2 = path17.basename(repoRoot);
5471
5636
  _cachedCwd = dir;
5472
5637
  return _cached2;
5473
5638
  } catch {
5474
- _cached2 = path16.basename(dir);
5639
+ _cached2 = path17.basename(dir);
5475
5640
  _cachedCwd = dir;
5476
5641
  return _cached2;
5477
5642
  }
@@ -5614,10 +5779,10 @@ var init_tasks_notify = __esm({
5614
5779
  });
5615
5780
 
5616
5781
  // src/lib/behaviors.ts
5617
- import crypto4 from "crypto";
5782
+ import crypto5 from "crypto";
5618
5783
  async function storeBehavior(opts) {
5619
5784
  const client = getClient();
5620
- const id = crypto4.randomUUID();
5785
+ const id = crypto5.randomUUID();
5621
5786
  const now = (/* @__PURE__ */ new Date()).toISOString();
5622
5787
  await client.execute({
5623
5788
  sql: `INSERT INTO behaviors (id, agent_id, project_name, domain, priority, content, active, created_at, updated_at)
@@ -5646,7 +5811,7 @@ __export(skill_learning_exports, {
5646
5811
  storeTrajectory: () => storeTrajectory,
5647
5812
  sweepTrajectories: () => sweepTrajectories
5648
5813
  });
5649
- import crypto5 from "crypto";
5814
+ import crypto6 from "crypto";
5650
5815
  async function extractTrajectory(taskId, agentId) {
5651
5816
  const client = getClient();
5652
5817
  const result = await client.execute({
@@ -5675,11 +5840,11 @@ async function extractTrajectory(taskId, agentId) {
5675
5840
  return signature;
5676
5841
  }
5677
5842
  function hashSignature(signature) {
5678
- return crypto5.createHash("sha256").update(signature.join("|")).digest("hex").slice(0, 16);
5843
+ return crypto6.createHash("sha256").update(signature.join("|")).digest("hex").slice(0, 16);
5679
5844
  }
5680
5845
  async function storeTrajectory(opts) {
5681
5846
  const client = getClient();
5682
- const id = crypto5.randomUUID();
5847
+ const id = crypto6.randomUUID();
5683
5848
  const now = (/* @__PURE__ */ new Date()).toISOString();
5684
5849
  const signatureHash = hashSignature(opts.signature);
5685
5850
  await client.execute({
@@ -5944,8 +6109,8 @@ __export(tasks_exports, {
5944
6109
  updateTaskStatus: () => updateTaskStatus,
5945
6110
  writeCheckpoint: () => writeCheckpoint
5946
6111
  });
5947
- import path17 from "path";
5948
- import { writeFileSync as writeFileSync6, mkdirSync as mkdirSync6, unlinkSync as unlinkSync5 } from "fs";
6112
+ import path18 from "path";
6113
+ import { writeFileSync as writeFileSync7, mkdirSync as mkdirSync6, unlinkSync as unlinkSync5 } from "fs";
5949
6114
  async function createTask(input) {
5950
6115
  const result = await createTaskCore(input);
5951
6116
  if (!input.skipDispatch && result.status !== "blocked" && !process.env.VITEST) {
@@ -5964,12 +6129,12 @@ async function updateTask(input) {
5964
6129
  const { row, taskFile, now, taskId } = await updateTaskStatus(input);
5965
6130
  try {
5966
6131
  const agent = String(row.assigned_to);
5967
- const cacheDir = path17.join(EXE_AI_DIR, "session-cache");
5968
- const cachePath = path17.join(cacheDir, `current-task-${agent}.json`);
6132
+ const cacheDir = path18.join(EXE_AI_DIR, "session-cache");
6133
+ const cachePath = path18.join(cacheDir, `current-task-${agent}.json`);
5969
6134
  if (input.status === "in_progress") {
5970
6135
  mkdirSync6(cacheDir, { recursive: true });
5971
- writeFileSync6(cachePath, JSON.stringify({ taskId, title: String(row.title) }));
5972
- } else if (input.status === "done" || input.status === "blocked" || input.status === "cancelled") {
6136
+ writeFileSync7(cachePath, JSON.stringify({ taskId, title: String(row.title) }));
6137
+ } else if (input.status === "done" || input.status === "blocked" || input.status === "cancelled" || input.status === "closed") {
5973
6138
  try {
5974
6139
  unlinkSync5(cachePath);
5975
6140
  } catch {
@@ -5977,10 +6142,10 @@ async function updateTask(input) {
5977
6142
  }
5978
6143
  } catch {
5979
6144
  }
5980
- if (input.status === "done") {
6145
+ if (input.status === "done" || input.status === "closed") {
5981
6146
  await cleanupReviewFile(row, taskFile, input.baseDir);
5982
6147
  }
5983
- if (input.status === "done" || input.status === "cancelled") {
6148
+ if (input.status === "done" || input.status === "cancelled" || input.status === "closed") {
5984
6149
  try {
5985
6150
  const client = getClient();
5986
6151
  const taskTitle = String(row.title);
@@ -5996,7 +6161,7 @@ async function updateTask(input) {
5996
6161
  if (!isCoordinatorName(assignedAgent)) {
5997
6162
  try {
5998
6163
  const draftClient = getClient();
5999
- if (input.status === "done") {
6164
+ if (input.status === "done" || input.status === "closed") {
6000
6165
  await draftClient.execute({
6001
6166
  sql: `UPDATE memories SET draft = 0 WHERE agent_id = ? AND draft = 1`,
6002
6167
  args: [assignedAgent]
@@ -6013,7 +6178,7 @@ async function updateTask(input) {
6013
6178
  try {
6014
6179
  const client = getClient();
6015
6180
  const cascaded = await client.execute({
6016
- sql: `UPDATE tasks SET status = 'done', updated_at = ?
6181
+ sql: `UPDATE tasks SET status = 'closed', updated_at = ?
6017
6182
  WHERE parent_task_id = ? AND status = 'needs_review'`,
6018
6183
  args: [now, taskId]
6019
6184
  });
@@ -6026,14 +6191,14 @@ async function updateTask(input) {
6026
6191
  } catch {
6027
6192
  }
6028
6193
  }
6029
- const isTerminal = input.status === "done" || input.status === "needs_review";
6194
+ const isTerminal = input.status === "done" || input.status === "needs_review" || input.status === "closed";
6030
6195
  if (isTerminal) {
6031
6196
  const isCoordinator = isCoordinatorName(String(row.assigned_to));
6032
6197
  if (!isCoordinator) {
6033
6198
  notifyTaskDone();
6034
6199
  }
6035
6200
  await markTaskNotificationsRead(taskFile);
6036
- if (input.status === "done") {
6201
+ if (input.status === "done" || input.status === "closed") {
6037
6202
  try {
6038
6203
  await cascadeUnblock(taskId, input.baseDir, now);
6039
6204
  } catch {
@@ -6053,7 +6218,7 @@ async function updateTask(input) {
6053
6218
  }
6054
6219
  }
6055
6220
  }
6056
- if (input.status === "done" && !isCoordinatorName(String(row.assigned_to)) && !process.env.VITEST) {
6221
+ if ((input.status === "done" || input.status === "closed") && !isCoordinatorName(String(row.assigned_to)) && !process.env.VITEST) {
6057
6222
  Promise.resolve().then(() => (init_skill_learning(), skill_learning_exports)).then(
6058
6223
  ({ captureAndLearn: captureAndLearn2 }) => captureAndLearn2({
6059
6224
  taskId,
@@ -6425,6 +6590,7 @@ __export(tmux_routing_exports, {
6425
6590
  isEmployeeAlive: () => isEmployeeAlive,
6426
6591
  isExeSession: () => isExeSession,
6427
6592
  isSessionBusy: () => isSessionBusy,
6593
+ notifyCoordinatorTaskCompletion: () => notifyCoordinatorTaskCompletion,
6428
6594
  notifyParentExe: () => notifyParentExe,
6429
6595
  parseParentExe: () => parseParentExe,
6430
6596
  registerParentExe: () => registerParentExe,
@@ -6435,13 +6601,13 @@ __export(tmux_routing_exports, {
6435
6601
  verifyPaneAtCapacity: () => verifyPaneAtCapacity
6436
6602
  });
6437
6603
  import { execFileSync as execFileSync2, execSync as execSync6 } from "child_process";
6438
- import { readFileSync as readFileSync11, writeFileSync as writeFileSync7, mkdirSync as mkdirSync7, existsSync as existsSync14, appendFileSync, readdirSync as readdirSync4 } from "fs";
6439
- import path18 from "path";
6440
- import os10 from "os";
6604
+ import { readFileSync as readFileSync12, writeFileSync as writeFileSync8, mkdirSync as mkdirSync7, existsSync as existsSync16, appendFileSync, readdirSync as readdirSync4 } from "fs";
6605
+ import path19 from "path";
6606
+ import os11 from "os";
6441
6607
  import { fileURLToPath as fileURLToPath2 } from "url";
6442
6608
  import { unlinkSync as unlinkSync6 } from "fs";
6443
6609
  function spawnLockPath(sessionName) {
6444
- return path18.join(SPAWN_LOCK_DIR, `${sessionName}.lock`);
6610
+ return path19.join(SPAWN_LOCK_DIR, `${sessionName}.lock`);
6445
6611
  }
6446
6612
  function isProcessAlive(pid) {
6447
6613
  try {
@@ -6452,13 +6618,13 @@ function isProcessAlive(pid) {
6452
6618
  }
6453
6619
  }
6454
6620
  function acquireSpawnLock2(sessionName) {
6455
- if (!existsSync14(SPAWN_LOCK_DIR)) {
6621
+ if (!existsSync16(SPAWN_LOCK_DIR)) {
6456
6622
  mkdirSync7(SPAWN_LOCK_DIR, { recursive: true });
6457
6623
  }
6458
6624
  const lockFile = spawnLockPath(sessionName);
6459
- if (existsSync14(lockFile)) {
6625
+ if (existsSync16(lockFile)) {
6460
6626
  try {
6461
- const lock = JSON.parse(readFileSync11(lockFile, "utf8"));
6627
+ const lock = JSON.parse(readFileSync12(lockFile, "utf8"));
6462
6628
  const age = Date.now() - lock.timestamp;
6463
6629
  if (isProcessAlive(lock.pid) && age < 6e4) {
6464
6630
  return false;
@@ -6466,7 +6632,7 @@ function acquireSpawnLock2(sessionName) {
6466
6632
  } catch {
6467
6633
  }
6468
6634
  }
6469
- writeFileSync7(lockFile, JSON.stringify({ pid: process.pid, timestamp: Date.now() }));
6635
+ writeFileSync8(lockFile, JSON.stringify({ pid: process.pid, timestamp: Date.now() }));
6470
6636
  return true;
6471
6637
  }
6472
6638
  function releaseSpawnLock2(sessionName) {
@@ -6478,13 +6644,13 @@ function releaseSpawnLock2(sessionName) {
6478
6644
  function resolveBehaviorsExporterScript() {
6479
6645
  try {
6480
6646
  const thisFile = fileURLToPath2(import.meta.url);
6481
- const scriptPath = path18.join(
6482
- path18.dirname(thisFile),
6647
+ const scriptPath = path19.join(
6648
+ path19.dirname(thisFile),
6483
6649
  "..",
6484
6650
  "bin",
6485
6651
  "exe-export-behaviors.js"
6486
6652
  );
6487
- return existsSync14(scriptPath) ? scriptPath : null;
6653
+ return existsSync16(scriptPath) ? scriptPath : null;
6488
6654
  } catch {
6489
6655
  return null;
6490
6656
  }
@@ -6550,12 +6716,12 @@ function extractRootExe(name) {
6550
6716
  return parts.length > 0 ? parts[parts.length - 1] : null;
6551
6717
  }
6552
6718
  function registerParentExe(sessionKey, parentExe, dispatchedBy) {
6553
- if (!existsSync14(SESSION_CACHE)) {
6719
+ if (!existsSync16(SESSION_CACHE)) {
6554
6720
  mkdirSync7(SESSION_CACHE, { recursive: true });
6555
6721
  }
6556
6722
  const rootExe = extractRootExe(parentExe) ?? parentExe;
6557
- const filePath = path18.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`);
6558
- writeFileSync7(filePath, JSON.stringify({
6723
+ const filePath = path19.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`);
6724
+ writeFileSync8(filePath, JSON.stringify({
6559
6725
  parentExe: rootExe,
6560
6726
  dispatchedBy: dispatchedBy || rootExe,
6561
6727
  registeredAt: (/* @__PURE__ */ new Date()).toISOString()
@@ -6563,7 +6729,7 @@ function registerParentExe(sessionKey, parentExe, dispatchedBy) {
6563
6729
  }
6564
6730
  function getParentExe(sessionKey) {
6565
6731
  try {
6566
- const data = JSON.parse(readFileSync11(path18.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
6732
+ const data = JSON.parse(readFileSync12(path19.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
6567
6733
  return data.parentExe || null;
6568
6734
  } catch {
6569
6735
  return null;
@@ -6571,8 +6737,8 @@ function getParentExe(sessionKey) {
6571
6737
  }
6572
6738
  function getDispatchedBy(sessionKey) {
6573
6739
  try {
6574
- const data = JSON.parse(readFileSync11(
6575
- path18.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`),
6740
+ const data = JSON.parse(readFileSync12(
6741
+ path19.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`),
6576
6742
  "utf8"
6577
6743
  ));
6578
6744
  return data.dispatchedBy ?? data.parentExe ?? null;
@@ -6642,8 +6808,8 @@ async function verifyPaneAtCapacity(sessionName) {
6642
6808
  }
6643
6809
  function readDebounceState() {
6644
6810
  try {
6645
- if (!existsSync14(DEBOUNCE_FILE)) return {};
6646
- const raw = JSON.parse(readFileSync11(DEBOUNCE_FILE, "utf8"));
6811
+ if (!existsSync16(DEBOUNCE_FILE)) return {};
6812
+ const raw = JSON.parse(readFileSync12(DEBOUNCE_FILE, "utf8"));
6647
6813
  const state = {};
6648
6814
  for (const [key, val] of Object.entries(raw)) {
6649
6815
  if (typeof val === "number") {
@@ -6659,8 +6825,8 @@ function readDebounceState() {
6659
6825
  }
6660
6826
  function writeDebounceState(state) {
6661
6827
  try {
6662
- if (!existsSync14(SESSION_CACHE)) mkdirSync7(SESSION_CACHE, { recursive: true });
6663
- writeFileSync7(DEBOUNCE_FILE, JSON.stringify(state));
6828
+ if (!existsSync16(SESSION_CACHE)) mkdirSync7(SESSION_CACHE, { recursive: true });
6829
+ writeFileSync8(DEBOUNCE_FILE, JSON.stringify(state));
6664
6830
  } catch {
6665
6831
  }
6666
6832
  }
@@ -6758,8 +6924,8 @@ function sendIntercom(targetSession) {
6758
6924
  try {
6759
6925
  const rawAgent = targetSession.split("-")[0] ?? targetSession;
6760
6926
  const agent = baseAgentName(rawAgent);
6761
- const markerPath = path18.join(SESSION_CACHE, `current-task-${agent}.json`);
6762
- if (existsSync14(markerPath)) {
6927
+ const markerPath = path19.join(SESSION_CACHE, `current-task-${agent}.json`);
6928
+ if (existsSync16(markerPath)) {
6763
6929
  logIntercom(`SKIP \u2192 ${targetSession} (has in_progress task marker \u2014 will auto-chain)`);
6764
6930
  return "debounced";
6765
6931
  }
@@ -6768,8 +6934,8 @@ function sendIntercom(targetSession) {
6768
6934
  try {
6769
6935
  const rawAgent = targetSession.split("-")[0] ?? targetSession;
6770
6936
  const agent = baseAgentName(rawAgent);
6771
- const taskDir = path18.join(process.cwd(), "exe", agent);
6772
- if (existsSync14(taskDir)) {
6937
+ const taskDir = path19.join(process.cwd(), "exe", agent);
6938
+ if (existsSync16(taskDir)) {
6773
6939
  const files = readdirSync4(taskDir).filter(
6774
6940
  (f) => f.endsWith(".md") && f !== "DONE.txt"
6775
6941
  );
@@ -6829,6 +6995,21 @@ function notifyParentExe(sessionKey) {
6829
6995
  }
6830
6996
  return true;
6831
6997
  }
6998
+ function notifyCoordinatorTaskCompletion(coordinatorSession, agentName2, taskTitle) {
6999
+ const transport = getTransport();
7000
+ try {
7001
+ const sessions = transport.listSessions();
7002
+ if (!sessions.includes(coordinatorSession)) return false;
7003
+ execSync6(
7004
+ `tmux send-keys -t ${JSON.stringify(coordinatorSession)} '/exe-intercom' Enter`,
7005
+ { timeout: 3e3 }
7006
+ );
7007
+ logIntercom(`COMPLETION \u2192 ${coordinatorSession} (${agentName2} completed "${taskTitle.slice(0, 50)}")`);
7008
+ return true;
7009
+ } catch {
7010
+ return false;
7011
+ }
7012
+ }
6832
7013
  function ensureEmployee(employeeName, exeSession2, projectDir, opts) {
6833
7014
  if (isCoordinatorName(employeeName)) {
6834
7015
  return { status: "failed", sessionName: "", error: "The COO is not a dispatchable employee" };
@@ -6902,26 +7083,26 @@ function spawnEmployee(employeeName, exeSession2, projectDir, opts) {
6902
7083
  const transport = getTransport();
6903
7084
  const sessionName = employeeSessionName(employeeName, exeSession2, opts?.instance);
6904
7085
  const instanceLabel2 = opts?.instance != null && opts.instance > 0 ? `${employeeName}${opts.instance}` : employeeName;
6905
- const logDir = path18.join(os10.homedir(), ".exe-os", "session-logs");
6906
- const logFile = path18.join(logDir, `${instanceLabel2}-${Date.now()}.log`);
6907
- if (!existsSync14(logDir)) {
7086
+ const logDir = path19.join(os11.homedir(), ".exe-os", "session-logs");
7087
+ const logFile = path19.join(logDir, `${instanceLabel2}-${Date.now()}.log`);
7088
+ if (!existsSync16(logDir)) {
6908
7089
  mkdirSync7(logDir, { recursive: true });
6909
7090
  }
6910
7091
  transport.kill(sessionName);
6911
7092
  let cleanupSuffix = "";
6912
7093
  try {
6913
7094
  const thisFile = fileURLToPath2(import.meta.url);
6914
- const cleanupScript = path18.join(path18.dirname(thisFile), "..", "bin", "exe-session-cleanup.js");
6915
- if (existsSync14(cleanupScript)) {
7095
+ const cleanupScript = path19.join(path19.dirname(thisFile), "..", "bin", "exe-session-cleanup.js");
7096
+ if (existsSync16(cleanupScript)) {
6916
7097
  cleanupSuffix = `; ${process.execPath} "${cleanupScript}" "${employeeName}" "${exeSession2}"`;
6917
7098
  }
6918
7099
  } catch {
6919
7100
  }
6920
7101
  try {
6921
- const claudeJsonPath = path18.join(os10.homedir(), ".claude.json");
7102
+ const claudeJsonPath = path19.join(os11.homedir(), ".claude.json");
6922
7103
  let claudeJson = {};
6923
7104
  try {
6924
- claudeJson = JSON.parse(readFileSync11(claudeJsonPath, "utf8"));
7105
+ claudeJson = JSON.parse(readFileSync12(claudeJsonPath, "utf8"));
6925
7106
  } catch {
6926
7107
  }
6927
7108
  if (!claudeJson.projects) claudeJson.projects = {};
@@ -6929,17 +7110,17 @@ function spawnEmployee(employeeName, exeSession2, projectDir, opts) {
6929
7110
  const trustDir = opts?.cwd ?? projectDir;
6930
7111
  if (!projects[trustDir]) projects[trustDir] = {};
6931
7112
  projects[trustDir].hasTrustDialogAccepted = true;
6932
- writeFileSync7(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
7113
+ writeFileSync8(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
6933
7114
  } catch {
6934
7115
  }
6935
7116
  try {
6936
- const settingsDir = path18.join(os10.homedir(), ".claude", "projects");
7117
+ const settingsDir = path19.join(os11.homedir(), ".claude", "projects");
6937
7118
  const normalizedKey = (opts?.cwd ?? projectDir).replace(/\//g, "-").replace(/^-/, "");
6938
- const projSettingsDir = path18.join(settingsDir, normalizedKey);
6939
- const settingsPath = path18.join(projSettingsDir, "settings.json");
7119
+ const projSettingsDir = path19.join(settingsDir, normalizedKey);
7120
+ const settingsPath = path19.join(projSettingsDir, "settings.json");
6940
7121
  let settings = {};
6941
7122
  try {
6942
- settings = JSON.parse(readFileSync11(settingsPath, "utf8"));
7123
+ settings = JSON.parse(readFileSync12(settingsPath, "utf8"));
6943
7124
  } catch {
6944
7125
  }
6945
7126
  const perms = settings.permissions ?? {};
@@ -6968,7 +7149,7 @@ function spawnEmployee(employeeName, exeSession2, projectDir, opts) {
6968
7149
  perms.allow = allow;
6969
7150
  settings.permissions = perms;
6970
7151
  mkdirSync7(projSettingsDir, { recursive: true });
6971
- writeFileSync7(settingsPath, JSON.stringify(settings, null, 2) + "\n");
7152
+ writeFileSync8(settingsPath, JSON.stringify(settings, null, 2) + "\n");
6972
7153
  }
6973
7154
  } catch {
6974
7155
  }
@@ -6983,8 +7164,8 @@ function spawnEmployee(employeeName, exeSession2, projectDir, opts) {
6983
7164
  let behaviorsFlag = "";
6984
7165
  let legacyFallbackWarned = false;
6985
7166
  if (!useExeAgent && !useBinSymlink) {
6986
- const identityPath = path18.join(
6987
- os10.homedir(),
7167
+ const identityPath = path19.join(
7168
+ os11.homedir(),
6988
7169
  ".exe-os",
6989
7170
  "identity",
6990
7171
  `${employeeName}.md`
@@ -6993,13 +7174,13 @@ function spawnEmployee(employeeName, exeSession2, projectDir, opts) {
6993
7174
  const hasAgentFlag = claudeSupportsAgentFlag();
6994
7175
  if (hasAgentFlag) {
6995
7176
  identityFlag = ` --agent ${employeeName}`;
6996
- } else if (existsSync14(identityPath)) {
7177
+ } else if (existsSync16(identityPath)) {
6997
7178
  identityFlag = ` --append-system-prompt-file ${identityPath}`;
6998
7179
  legacyFallbackWarned = true;
6999
7180
  }
7000
7181
  const behaviorsFile = exportBehaviorsSync(
7001
7182
  employeeName,
7002
- path18.basename(spawnCwd),
7183
+ path19.basename(spawnCwd),
7003
7184
  sessionName
7004
7185
  );
7005
7186
  if (behaviorsFile) {
@@ -7014,16 +7195,16 @@ function spawnEmployee(employeeName, exeSession2, projectDir, opts) {
7014
7195
  }
7015
7196
  let sessionContextFlag = "";
7016
7197
  try {
7017
- const ctxDir = path18.join(os10.homedir(), ".exe-os", "session-cache");
7198
+ const ctxDir = path19.join(os11.homedir(), ".exe-os", "session-cache");
7018
7199
  mkdirSync7(ctxDir, { recursive: true });
7019
- const ctxFile = path18.join(ctxDir, `session-context-${sessionName}.md`);
7200
+ const ctxFile = path19.join(ctxDir, `session-context-${sessionName}.md`);
7020
7201
  const ctxContent = [
7021
7202
  `## Session Context`,
7022
7203
  `You are running in tmux session: ${sessionName}.`,
7023
7204
  `Your parent coordinator session is ${exeSession2}.`,
7024
7205
  `Your employees (if any) use the -${exeSession2} suffix.`
7025
7206
  ].join("\n");
7026
- writeFileSync7(ctxFile, ctxContent);
7207
+ writeFileSync8(ctxFile, ctxContent);
7027
7208
  sessionContextFlag = ` --append-system-prompt-file ${ctxFile}`;
7028
7209
  } catch {
7029
7210
  }
@@ -7100,8 +7281,8 @@ function spawnEmployee(employeeName, exeSession2, projectDir, opts) {
7100
7281
  transport.pipeLog(sessionName, logFile);
7101
7282
  try {
7102
7283
  const mySession = getMySession();
7103
- const dispatchInfo = path18.join(SESSION_CACHE, `dispatch-info-${sessionName}.json`);
7104
- writeFileSync7(dispatchInfo, JSON.stringify({
7284
+ const dispatchInfo = path19.join(SESSION_CACHE, `dispatch-info-${sessionName}.json`);
7285
+ writeFileSync8(dispatchInfo, JSON.stringify({
7105
7286
  dispatchedBy: mySession,
7106
7287
  rootExe: exeSession2,
7107
7288
  provider: useBinSymlink ? ccProvider : useExeAgent ? opts.provider : useCodex ? "openai" : useOpencode ? "opencode" : "anthropic",
@@ -7175,15 +7356,15 @@ var init_tmux_routing = __esm({
7175
7356
  init_intercom_queue();
7176
7357
  init_plan_limits();
7177
7358
  init_employees();
7178
- SPAWN_LOCK_DIR = path18.join(os10.homedir(), ".exe-os", "spawn-locks");
7179
- SESSION_CACHE = path18.join(os10.homedir(), ".exe-os", "session-cache");
7359
+ SPAWN_LOCK_DIR = path19.join(os11.homedir(), ".exe-os", "spawn-locks");
7360
+ SESSION_CACHE = path19.join(os11.homedir(), ".exe-os", "session-cache");
7180
7361
  BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
7181
7362
  VALID_SESSION_NAME = /^[a-z]+\d*-[a-zA-Z0-9_]+$/;
7182
7363
  VERIFY_PANE_LINES = 200;
7183
7364
  INTERCOM_DEBOUNCE_MS = 3e4;
7184
7365
  CODEX_DEBOUNCE_MS = 12e4;
7185
- INTERCOM_LOG2 = path18.join(os10.homedir(), ".exe-os", "intercom.log");
7186
- DEBOUNCE_FILE = path18.join(SESSION_CACHE, "intercom-debounce.json");
7366
+ INTERCOM_LOG2 = path19.join(os11.homedir(), ".exe-os", "intercom.log");
7367
+ DEBOUNCE_FILE = path19.join(SESSION_CACHE, "intercom-debounce.json");
7187
7368
  DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
7188
7369
  BUSY_PATTERN = /[✻✽✶✳·].*…|Running…|• Working|• Ran |• Explored|• Called|esc to interrupt/;
7189
7370
  }
@@ -7206,6 +7387,15 @@ function sessionScopeFilter(sessionScope, tableAlias) {
7206
7387
  args: [scope]
7207
7388
  };
7208
7389
  }
7390
+ function strictSessionScopeFilter(sessionScope, tableAlias) {
7391
+ const scope = sessionScope !== void 0 ? sessionScope : getCurrentSessionScope();
7392
+ if (!scope) return { sql: "", args: [] };
7393
+ const col = tableAlias ? `${tableAlias}.session_scope` : "session_scope";
7394
+ return {
7395
+ sql: ` AND ${col} = ?`,
7396
+ args: [scope]
7397
+ };
7398
+ }
7209
7399
  var init_task_scope = __esm({
7210
7400
  "src/lib/task-scope.ts"() {
7211
7401
  "use strict";
@@ -7250,10 +7440,10 @@ async function disposeEmbedder() {
7250
7440
  async function embedDirect(text) {
7251
7441
  const llamaCpp = await import("node-llama-cpp");
7252
7442
  const { MODELS_DIR: MODELS_DIR2 } = await Promise.resolve().then(() => (init_config(), config_exports));
7253
- const { existsSync: existsSync16 } = await import("fs");
7254
- const path20 = await import("path");
7255
- const modelPath = path20.join(MODELS_DIR2, "jina-embeddings-v5-small-q4_k_m.gguf");
7256
- if (!existsSync16(modelPath)) {
7443
+ const { existsSync: existsSync18 } = await import("fs");
7444
+ const path21 = await import("path");
7445
+ const modelPath = path21.join(MODELS_DIR2, "jina-embeddings-v5-small-q4_k_m.gguf");
7446
+ if (!existsSync18(modelPath)) {
7257
7447
  throw new Error(`Embedding model not found at ${modelPath}. Run '/exe-setup' to download it.`);
7258
7448
  }
7259
7449
  const llama = await llamaCpp.getLlama();
@@ -7511,8 +7701,8 @@ __export(worktree_exports, {
7511
7701
  worktreePath: () => worktreePath
7512
7702
  });
7513
7703
  import { execSync as execSync8 } from "child_process";
7514
- import { existsSync as existsSync15, readFileSync as readFileSync12, appendFileSync as appendFileSync2, mkdirSync as mkdirSync8, realpathSync } from "fs";
7515
- import path19 from "path";
7704
+ import { existsSync as existsSync17, readFileSync as readFileSync13, appendFileSync as appendFileSync2, mkdirSync as mkdirSync8, realpathSync } from "fs";
7705
+ import path20 from "path";
7516
7706
  function getGitRoot(dir) {
7517
7707
  try {
7518
7708
  const root = execSync8("git rev-parse --show-toplevel", {
@@ -7532,14 +7722,14 @@ function getMainRepoRoot(dir) {
7532
7722
  "git rev-parse --path-format=absolute --git-common-dir",
7533
7723
  { cwd: dir, encoding: "utf-8", timeout: GIT_TIMEOUT_MS, stdio: ["pipe", "pipe", "pipe"] }
7534
7724
  ).trim();
7535
- return realpath(path19.dirname(commonDir));
7725
+ return realpath(path20.dirname(commonDir));
7536
7726
  } catch {
7537
7727
  return null;
7538
7728
  }
7539
7729
  }
7540
7730
  function worktreePath(repoRoot, employeeName, instance) {
7541
7731
  const label = instanceLabel(employeeName, instance);
7542
- return path19.join(repoRoot, ".worktrees", label);
7732
+ return path20.join(repoRoot, ".worktrees", label);
7543
7733
  }
7544
7734
  function worktreeBranch(employeeName, instance) {
7545
7735
  return `${instanceLabel(employeeName, instance)}-work`;
@@ -7552,10 +7742,10 @@ function ensureWorktree(projectDir, employeeName, instance) {
7552
7742
  if (!repoRoot) return null;
7553
7743
  const wtPath = worktreePath(repoRoot, employeeName, instance);
7554
7744
  const branch = worktreeBranch(employeeName, instance);
7555
- if (existsSync15(path19.join(wtPath, ".git"))) {
7745
+ if (existsSync17(path20.join(wtPath, ".git"))) {
7556
7746
  return wtPath;
7557
7747
  }
7558
- const worktreesDir = path19.join(repoRoot, ".worktrees");
7748
+ const worktreesDir = path20.join(repoRoot, ".worktrees");
7559
7749
  mkdirSync8(worktreesDir, { recursive: true });
7560
7750
  ensureGitignoreEntry(repoRoot, "/.worktrees/");
7561
7751
  try {
@@ -7611,7 +7801,7 @@ function cleanupWorktree(projectDir, employeeName, instance) {
7611
7801
  if (!repoRoot) return { cleaned: false, reason: "not a git repo" };
7612
7802
  const wtPath = worktreePath(repoRoot, employeeName, instance);
7613
7803
  const branch = worktreeBranch(employeeName, instance);
7614
- if (!existsSync15(wtPath)) {
7804
+ if (!existsSync17(wtPath)) {
7615
7805
  return { cleaned: false, reason: "worktree does not exist" };
7616
7806
  }
7617
7807
  if (isWorktreeDirty(wtPath)) {
@@ -7689,9 +7879,9 @@ function realpath(p) {
7689
7879
  }
7690
7880
  function ensureGitignoreEntry(repoRoot, entry) {
7691
7881
  try {
7692
- const gitignorePath = path19.join(repoRoot, ".gitignore");
7693
- if (existsSync15(gitignorePath)) {
7694
- const content = readFileSync12(gitignorePath, "utf-8");
7882
+ const gitignorePath = path20.join(repoRoot, ".gitignore");
7883
+ if (existsSync17(gitignorePath)) {
7884
+ const content = readFileSync13(gitignorePath, "utf-8");
7695
7885
  if (content.includes(entry)) return;
7696
7886
  appendFileSync2(gitignorePath, `
7697
7887
  # Agent worktrees (exe-os)
@@ -7715,7 +7905,7 @@ init_store();
7715
7905
  init_database();
7716
7906
  init_task_scope();
7717
7907
  init_project_name();
7718
- import crypto6 from "crypto";
7908
+ import crypto7 from "crypto";
7719
7909
  import { execSync as execSync9 } from "child_process";
7720
7910
  var agentName = process.argv[2];
7721
7911
  var exeSession = process.argv[3];
@@ -7769,7 +7959,7 @@ try {
7769
7959
  } catch {
7770
7960
  }
7771
7961
  await writeMemory({
7772
- id: crypto6.randomUUID(),
7962
+ id: crypto7.randomUUID(),
7773
7963
  agent_id: agentName,
7774
7964
  agent_role: "employee",
7775
7965
  session_id: `cleanup-${Date.now()}`,