@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.
- package/dist/bin/backfill-conversations.js +222 -49
- package/dist/bin/backfill-responses.js +221 -48
- package/dist/bin/backfill-vectors.js +225 -52
- package/dist/bin/cleanup-stale-review-tasks.js +150 -28
- package/dist/bin/cli.js +1295 -856
- package/dist/bin/exe-agent-config.js +36 -8
- package/dist/bin/exe-agent.js +14 -4
- package/dist/bin/exe-assign.js +221 -48
- package/dist/bin/exe-boot.js +778 -427
- package/dist/bin/exe-call.js +41 -13
- package/dist/bin/exe-cloud.js +163 -58
- package/dist/bin/exe-dispatch.js +276 -139
- package/dist/bin/exe-doctor.js +145 -27
- package/dist/bin/exe-export-behaviors.js +141 -23
- package/dist/bin/exe-forget.js +137 -19
- package/dist/bin/exe-gateway.js +677 -388
- package/dist/bin/exe-heartbeat.js +227 -108
- package/dist/bin/exe-kill.js +138 -20
- package/dist/bin/exe-launch-agent.js +172 -39
- package/dist/bin/exe-link.js +291 -100
- package/dist/bin/exe-new-employee.js +214 -106
- package/dist/bin/exe-pending-messages.js +395 -33
- package/dist/bin/exe-pending-notifications.js +684 -99
- package/dist/bin/exe-pending-reviews.js +420 -74
- package/dist/bin/exe-rename.js +147 -49
- package/dist/bin/exe-review.js +138 -20
- package/dist/bin/exe-search.js +240 -69
- package/dist/bin/exe-session-cleanup.js +440 -250
- package/dist/bin/exe-settings.js +61 -17
- package/dist/bin/exe-start-codex.js +158 -39
- package/dist/bin/exe-start-opencode.js +157 -38
- package/dist/bin/exe-status.js +151 -29
- package/dist/bin/exe-team.js +138 -20
- package/dist/bin/git-sweep.js +404 -212
- package/dist/bin/graph-backfill.js +137 -19
- package/dist/bin/graph-export.js +140 -22
- package/dist/bin/install.js +90 -61
- package/dist/bin/scan-tasks.js +412 -220
- package/dist/bin/setup.js +564 -293
- package/dist/bin/shard-migrate.js +139 -21
- package/dist/bin/update.js +138 -49
- package/dist/bin/wiki-sync.js +137 -19
- package/dist/gateway/index.js +533 -320
- package/dist/hooks/bug-report-worker.js +344 -193
- package/dist/hooks/codex-stop-task-finalizer.js +4678 -0
- package/dist/hooks/commit-complete.js +402 -210
- package/dist/hooks/error-recall.js +245 -74
- package/dist/hooks/exe-heartbeat-hook.js +16 -6
- package/dist/hooks/ingest-worker.js +3423 -3157
- package/dist/hooks/ingest.js +832 -97
- package/dist/hooks/instructions-loaded.js +227 -54
- package/dist/hooks/notification.js +216 -43
- package/dist/hooks/post-compact.js +239 -62
- package/dist/hooks/pre-compact.js +408 -216
- package/dist/hooks/pre-tool-use.js +268 -90
- package/dist/hooks/prompt-ingest-worker.js +352 -102
- package/dist/hooks/prompt-submit.js +541 -328
- package/dist/hooks/response-ingest-worker.js +372 -122
- package/dist/hooks/session-end.js +443 -240
- package/dist/hooks/session-start.js +313 -127
- package/dist/hooks/stop.js +293 -98
- package/dist/hooks/subagent-stop.js +239 -62
- package/dist/hooks/summary-worker.js +568 -236
- package/dist/index.js +538 -324
- package/dist/lib/agent-config.js +28 -6
- package/dist/lib/cloud-sync.js +284 -105
- package/dist/lib/config.js +30 -10
- package/dist/lib/consolidation.js +16 -6
- package/dist/lib/database.js +123 -25
- package/dist/lib/db-daemon-client.js +73 -19
- package/dist/lib/db.js +123 -25
- package/dist/lib/device-registry.js +133 -35
- package/dist/lib/embedder.js +107 -32
- package/dist/lib/employee-templates.js +14 -4
- package/dist/lib/employees.js +41 -13
- package/dist/lib/exe-daemon-client.js +88 -22
- package/dist/lib/exe-daemon.js +935 -587
- package/dist/lib/hybrid-search.js +240 -69
- package/dist/lib/identity.js +18 -8
- package/dist/lib/license.js +133 -48
- package/dist/lib/messaging.js +116 -56
- package/dist/lib/reminders.js +14 -4
- package/dist/lib/schedules.js +137 -19
- package/dist/lib/skill-learning.js +33 -6
- package/dist/lib/store.js +137 -19
- package/dist/lib/task-router.js +14 -4
- package/dist/lib/tasks.js +280 -234
- package/dist/lib/tmux-routing.js +172 -125
- package/dist/lib/token-spend.js +26 -8
- package/dist/mcp/server.js +1326 -609
- package/dist/mcp/tools/complete-reminder.js +14 -4
- package/dist/mcp/tools/create-reminder.js +14 -4
- package/dist/mcp/tools/create-task.js +306 -248
- package/dist/mcp/tools/deactivate-behavior.js +16 -6
- package/dist/mcp/tools/list-reminders.js +14 -4
- package/dist/mcp/tools/list-tasks.js +123 -107
- package/dist/mcp/tools/send-message.js +75 -29
- package/dist/mcp/tools/update-task.js +1848 -199
- package/dist/runtime/index.js +441 -248
- package/dist/tui/App.js +761 -424
- package/package.json +1 -1
|
@@ -19,9 +19,47 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
19
19
|
};
|
|
20
20
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
21
21
|
|
|
22
|
+
// src/lib/secure-files.ts
|
|
23
|
+
import { chmodSync, existsSync, mkdirSync } from "fs";
|
|
24
|
+
import { chmod, mkdir } from "fs/promises";
|
|
25
|
+
async function ensurePrivateDir(dirPath) {
|
|
26
|
+
await mkdir(dirPath, { recursive: true, mode: PRIVATE_DIR_MODE });
|
|
27
|
+
try {
|
|
28
|
+
await chmod(dirPath, PRIVATE_DIR_MODE);
|
|
29
|
+
} catch {
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
function ensurePrivateDirSync(dirPath) {
|
|
33
|
+
mkdirSync(dirPath, { recursive: true, mode: PRIVATE_DIR_MODE });
|
|
34
|
+
try {
|
|
35
|
+
chmodSync(dirPath, PRIVATE_DIR_MODE);
|
|
36
|
+
} catch {
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
async function enforcePrivateFile(filePath) {
|
|
40
|
+
try {
|
|
41
|
+
await chmod(filePath, PRIVATE_FILE_MODE);
|
|
42
|
+
} catch {
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function enforcePrivateFileSync(filePath) {
|
|
46
|
+
try {
|
|
47
|
+
if (existsSync(filePath)) chmodSync(filePath, PRIVATE_FILE_MODE);
|
|
48
|
+
} catch {
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
var PRIVATE_DIR_MODE, PRIVATE_FILE_MODE;
|
|
52
|
+
var init_secure_files = __esm({
|
|
53
|
+
"src/lib/secure-files.ts"() {
|
|
54
|
+
"use strict";
|
|
55
|
+
PRIVATE_DIR_MODE = 448;
|
|
56
|
+
PRIVATE_FILE_MODE = 384;
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
|
|
22
60
|
// src/lib/config.ts
|
|
23
|
-
import { readFile, writeFile
|
|
24
|
-
import { readFileSync, existsSync, renameSync } from "fs";
|
|
61
|
+
import { readFile, writeFile } from "fs/promises";
|
|
62
|
+
import { readFileSync, existsSync as existsSync2, renameSync } from "fs";
|
|
25
63
|
import path from "path";
|
|
26
64
|
import os from "os";
|
|
27
65
|
function resolveDataDir() {
|
|
@@ -29,7 +67,7 @@ function resolveDataDir() {
|
|
|
29
67
|
if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
|
|
30
68
|
const newDir = path.join(os.homedir(), ".exe-os");
|
|
31
69
|
const legacyDir = path.join(os.homedir(), ".exe-mem");
|
|
32
|
-
if (!
|
|
70
|
+
if (!existsSync2(newDir) && existsSync2(legacyDir)) {
|
|
33
71
|
try {
|
|
34
72
|
renameSync(legacyDir, newDir);
|
|
35
73
|
process.stderr.write(`[exe-os] Migrated data directory: ~/.exe-mem \u2192 ~/.exe-os
|
|
@@ -92,9 +130,9 @@ function normalizeAutoUpdate(raw) {
|
|
|
92
130
|
}
|
|
93
131
|
async function loadConfig() {
|
|
94
132
|
const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
|
|
95
|
-
await
|
|
133
|
+
await ensurePrivateDir(dir);
|
|
96
134
|
const configPath = path.join(dir, "config.json");
|
|
97
|
-
if (!
|
|
135
|
+
if (!existsSync2(configPath)) {
|
|
98
136
|
return { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db") };
|
|
99
137
|
}
|
|
100
138
|
const raw = await readFile(configPath, "utf-8");
|
|
@@ -107,6 +145,7 @@ async function loadConfig() {
|
|
|
107
145
|
`);
|
|
108
146
|
try {
|
|
109
147
|
await writeFile(configPath, JSON.stringify(migratedCfg, null, 2) + "\n");
|
|
148
|
+
await enforcePrivateFile(configPath);
|
|
110
149
|
} catch {
|
|
111
150
|
}
|
|
112
151
|
}
|
|
@@ -126,6 +165,7 @@ var EXE_AI_DIR, DB_PATH, MODELS_DIR, CONFIG_PATH, LEGACY_LANCE_PATH, CURRENT_CON
|
|
|
126
165
|
var init_config = __esm({
|
|
127
166
|
"src/lib/config.ts"() {
|
|
128
167
|
"use strict";
|
|
168
|
+
init_secure_files();
|
|
129
169
|
EXE_AI_DIR = resolveDataDir();
|
|
130
170
|
DB_PATH = path.join(EXE_AI_DIR, "memories.db");
|
|
131
171
|
MODELS_DIR = path.join(EXE_AI_DIR, "models");
|
|
@@ -272,7 +312,7 @@ var init_session_key = __esm({
|
|
|
272
312
|
|
|
273
313
|
// src/lib/employees.ts
|
|
274
314
|
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
275
|
-
import { existsSync as
|
|
315
|
+
import { existsSync as existsSync3, symlinkSync, readlinkSync, readFileSync as readFileSync2, renameSync as renameSync2, unlinkSync, writeFileSync } from "fs";
|
|
276
316
|
import { execSync as execSync2 } from "child_process";
|
|
277
317
|
import path2 from "path";
|
|
278
318
|
import os2 from "os";
|
|
@@ -289,7 +329,7 @@ function getCoordinatorName(employees = loadEmployeesSync()) {
|
|
|
289
329
|
return getCoordinatorEmployee(employees)?.name ?? DEFAULT_COORDINATOR_TEMPLATE_NAME;
|
|
290
330
|
}
|
|
291
331
|
function loadEmployeesSync(employeesPath = EMPLOYEES_PATH) {
|
|
292
|
-
if (!
|
|
332
|
+
if (!existsSync3(employeesPath)) return [];
|
|
293
333
|
try {
|
|
294
334
|
return JSON.parse(readFileSync2(employeesPath, "utf-8"));
|
|
295
335
|
} catch {
|
|
@@ -485,7 +525,7 @@ var init_runtime_table = __esm({
|
|
|
485
525
|
});
|
|
486
526
|
|
|
487
527
|
// src/lib/agent-config.ts
|
|
488
|
-
import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, existsSync as
|
|
528
|
+
import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, existsSync as existsSync4 } from "fs";
|
|
489
529
|
import path5 from "path";
|
|
490
530
|
var AGENT_CONFIG_PATH, DEFAULT_MODELS;
|
|
491
531
|
var init_agent_config = __esm({
|
|
@@ -493,6 +533,7 @@ var init_agent_config = __esm({
|
|
|
493
533
|
"use strict";
|
|
494
534
|
init_config();
|
|
495
535
|
init_runtime_table();
|
|
536
|
+
init_secure_files();
|
|
496
537
|
AGENT_CONFIG_PATH = path5.join(EXE_AI_DIR, "agent-config.json");
|
|
497
538
|
DEFAULT_MODELS = {
|
|
498
539
|
claude: "claude-opus-4",
|
|
@@ -503,7 +544,7 @@ var init_agent_config = __esm({
|
|
|
503
544
|
});
|
|
504
545
|
|
|
505
546
|
// src/lib/intercom-queue.ts
|
|
506
|
-
import { readFileSync as readFileSync5, writeFileSync as writeFileSync4, renameSync as renameSync3, existsSync as
|
|
547
|
+
import { readFileSync as readFileSync5, writeFileSync as writeFileSync4, renameSync as renameSync3, existsSync as existsSync5, mkdirSync as mkdirSync3 } from "fs";
|
|
507
548
|
import path6 from "path";
|
|
508
549
|
import os4 from "os";
|
|
509
550
|
var QUEUE_PATH, TTL_MS, INTERCOM_LOG;
|
|
@@ -1155,13 +1196,50 @@ var init_database_adapter = __esm({
|
|
|
1155
1196
|
}
|
|
1156
1197
|
});
|
|
1157
1198
|
|
|
1199
|
+
// src/lib/daemon-auth.ts
|
|
1200
|
+
import crypto from "crypto";
|
|
1201
|
+
import path8 from "path";
|
|
1202
|
+
import { existsSync as existsSync6, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "fs";
|
|
1203
|
+
function normalizeToken(token) {
|
|
1204
|
+
if (!token) return null;
|
|
1205
|
+
const trimmed = token.trim();
|
|
1206
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
1207
|
+
}
|
|
1208
|
+
function readDaemonToken() {
|
|
1209
|
+
try {
|
|
1210
|
+
if (!existsSync6(DAEMON_TOKEN_PATH)) return null;
|
|
1211
|
+
return normalizeToken(readFileSync6(DAEMON_TOKEN_PATH, "utf8"));
|
|
1212
|
+
} catch {
|
|
1213
|
+
return null;
|
|
1214
|
+
}
|
|
1215
|
+
}
|
|
1216
|
+
function ensureDaemonToken(seed) {
|
|
1217
|
+
const existing = readDaemonToken();
|
|
1218
|
+
if (existing) return existing;
|
|
1219
|
+
const token = normalizeToken(seed) ?? crypto.randomBytes(32).toString("hex");
|
|
1220
|
+
ensurePrivateDirSync(EXE_AI_DIR);
|
|
1221
|
+
writeFileSync5(DAEMON_TOKEN_PATH, `${token}
|
|
1222
|
+
`, "utf8");
|
|
1223
|
+
enforcePrivateFileSync(DAEMON_TOKEN_PATH);
|
|
1224
|
+
return token;
|
|
1225
|
+
}
|
|
1226
|
+
var DAEMON_TOKEN_PATH;
|
|
1227
|
+
var init_daemon_auth = __esm({
|
|
1228
|
+
"src/lib/daemon-auth.ts"() {
|
|
1229
|
+
"use strict";
|
|
1230
|
+
init_config();
|
|
1231
|
+
init_secure_files();
|
|
1232
|
+
DAEMON_TOKEN_PATH = path8.join(EXE_AI_DIR, "exed.token");
|
|
1233
|
+
}
|
|
1234
|
+
});
|
|
1235
|
+
|
|
1158
1236
|
// src/lib/exe-daemon-client.ts
|
|
1159
1237
|
import net from "net";
|
|
1160
1238
|
import os6 from "os";
|
|
1161
1239
|
import { spawn } from "child_process";
|
|
1162
1240
|
import { randomUUID } from "crypto";
|
|
1163
|
-
import { existsSync as
|
|
1164
|
-
import
|
|
1241
|
+
import { existsSync as existsSync7, unlinkSync as unlinkSync3, readFileSync as readFileSync7, openSync, closeSync, statSync } from "fs";
|
|
1242
|
+
import path9 from "path";
|
|
1165
1243
|
import { fileURLToPath } from "url";
|
|
1166
1244
|
function handleData(chunk) {
|
|
1167
1245
|
_buffer += chunk.toString();
|
|
@@ -1189,9 +1267,9 @@ function handleData(chunk) {
|
|
|
1189
1267
|
}
|
|
1190
1268
|
}
|
|
1191
1269
|
function cleanupStaleFiles() {
|
|
1192
|
-
if (
|
|
1270
|
+
if (existsSync7(PID_PATH)) {
|
|
1193
1271
|
try {
|
|
1194
|
-
const pid = parseInt(
|
|
1272
|
+
const pid = parseInt(readFileSync7(PID_PATH, "utf8").trim(), 10);
|
|
1195
1273
|
if (pid > 0) {
|
|
1196
1274
|
try {
|
|
1197
1275
|
process.kill(pid, 0);
|
|
@@ -1212,11 +1290,11 @@ function cleanupStaleFiles() {
|
|
|
1212
1290
|
}
|
|
1213
1291
|
}
|
|
1214
1292
|
function findPackageRoot() {
|
|
1215
|
-
let dir =
|
|
1216
|
-
const { root } =
|
|
1293
|
+
let dir = path9.dirname(fileURLToPath(import.meta.url));
|
|
1294
|
+
const { root } = path9.parse(dir);
|
|
1217
1295
|
while (dir !== root) {
|
|
1218
|
-
if (
|
|
1219
|
-
dir =
|
|
1296
|
+
if (existsSync7(path9.join(dir, "package.json"))) return dir;
|
|
1297
|
+
dir = path9.dirname(dir);
|
|
1220
1298
|
}
|
|
1221
1299
|
return null;
|
|
1222
1300
|
}
|
|
@@ -1242,16 +1320,17 @@ function spawnDaemon() {
|
|
|
1242
1320
|
process.stderr.write("[exed-client] WARN: cannot find package root\n");
|
|
1243
1321
|
return;
|
|
1244
1322
|
}
|
|
1245
|
-
const daemonPath =
|
|
1246
|
-
if (!
|
|
1323
|
+
const daemonPath = path9.join(pkgRoot, "dist", "lib", "exe-daemon.js");
|
|
1324
|
+
if (!existsSync7(daemonPath)) {
|
|
1247
1325
|
process.stderr.write(`[exed-client] WARN: daemon script not found at ${daemonPath}
|
|
1248
1326
|
`);
|
|
1249
1327
|
return;
|
|
1250
1328
|
}
|
|
1251
1329
|
const resolvedPath = daemonPath;
|
|
1330
|
+
const daemonToken = ensureDaemonToken(process.env[DAEMON_TOKEN_ENV] ?? null);
|
|
1252
1331
|
process.stderr.write(`[exed-client] Spawning daemon: ${resolvedPath}
|
|
1253
1332
|
`);
|
|
1254
|
-
const logPath =
|
|
1333
|
+
const logPath = path9.join(path9.dirname(SOCKET_PATH), "exed.log");
|
|
1255
1334
|
let stderrFd = "ignore";
|
|
1256
1335
|
try {
|
|
1257
1336
|
stderrFd = openSync(logPath, "a");
|
|
@@ -1269,7 +1348,8 @@ function spawnDaemon() {
|
|
|
1269
1348
|
TMUX_PANE: void 0,
|
|
1270
1349
|
// Prevents resolveExeSession() from scoping to one session
|
|
1271
1350
|
EXE_DAEMON_SOCK: SOCKET_PATH,
|
|
1272
|
-
EXE_DAEMON_PID: PID_PATH
|
|
1351
|
+
EXE_DAEMON_PID: PID_PATH,
|
|
1352
|
+
[DAEMON_TOKEN_ENV]: daemonToken
|
|
1273
1353
|
}
|
|
1274
1354
|
});
|
|
1275
1355
|
child.unref();
|
|
@@ -1376,13 +1456,14 @@ function sendDaemonRequest(payload, timeoutMs = REQUEST_TIMEOUT_MS) {
|
|
|
1376
1456
|
return;
|
|
1377
1457
|
}
|
|
1378
1458
|
const id = randomUUID();
|
|
1459
|
+
const token = process.env[DAEMON_TOKEN_ENV] ?? readDaemonToken();
|
|
1379
1460
|
const timer = setTimeout(() => {
|
|
1380
1461
|
_pending.delete(id);
|
|
1381
1462
|
resolve({ error: "Request timeout" });
|
|
1382
1463
|
}, timeoutMs);
|
|
1383
1464
|
_pending.set(id, { resolve, timer });
|
|
1384
1465
|
try {
|
|
1385
|
-
_socket.write(JSON.stringify({ id, ...payload }) + "\n");
|
|
1466
|
+
_socket.write(JSON.stringify({ id, token, ...payload }) + "\n");
|
|
1386
1467
|
} catch {
|
|
1387
1468
|
clearTimeout(timer);
|
|
1388
1469
|
_pending.delete(id);
|
|
@@ -1393,17 +1474,19 @@ function sendDaemonRequest(payload, timeoutMs = REQUEST_TIMEOUT_MS) {
|
|
|
1393
1474
|
function isClientConnected() {
|
|
1394
1475
|
return _connected;
|
|
1395
1476
|
}
|
|
1396
|
-
var SOCKET_PATH, PID_PATH, SPAWN_LOCK_PATH, SPAWN_LOCK_STALE_MS, CONNECT_TIMEOUT_MS, REQUEST_TIMEOUT_MS, _socket, _connected, _buffer, _pending, MAX_BUFFER;
|
|
1477
|
+
var SOCKET_PATH, PID_PATH, SPAWN_LOCK_PATH, SPAWN_LOCK_STALE_MS, CONNECT_TIMEOUT_MS, REQUEST_TIMEOUT_MS, DAEMON_TOKEN_ENV, _socket, _connected, _buffer, _pending, MAX_BUFFER;
|
|
1397
1478
|
var init_exe_daemon_client = __esm({
|
|
1398
1479
|
"src/lib/exe-daemon-client.ts"() {
|
|
1399
1480
|
"use strict";
|
|
1400
1481
|
init_config();
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1482
|
+
init_daemon_auth();
|
|
1483
|
+
SOCKET_PATH = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ?? path9.join(EXE_AI_DIR, "exed.sock");
|
|
1484
|
+
PID_PATH = process.env.EXE_DAEMON_PID ?? process.env.EXE_EMBED_PID ?? path9.join(EXE_AI_DIR, "exed.pid");
|
|
1485
|
+
SPAWN_LOCK_PATH = path9.join(EXE_AI_DIR, "exed-spawn.lock");
|
|
1404
1486
|
SPAWN_LOCK_STALE_MS = 3e4;
|
|
1405
1487
|
CONNECT_TIMEOUT_MS = 15e3;
|
|
1406
1488
|
REQUEST_TIMEOUT_MS = 3e4;
|
|
1489
|
+
DAEMON_TOKEN_ENV = "EXE_DAEMON_TOKEN";
|
|
1407
1490
|
_socket = null;
|
|
1408
1491
|
_connected = false;
|
|
1409
1492
|
_buffer = "";
|
|
@@ -1982,6 +2065,7 @@ async function ensureSchema() {
|
|
|
1982
2065
|
project TEXT NOT NULL,
|
|
1983
2066
|
summary TEXT NOT NULL,
|
|
1984
2067
|
task_file TEXT,
|
|
2068
|
+
session_scope TEXT,
|
|
1985
2069
|
read INTEGER NOT NULL DEFAULT 0,
|
|
1986
2070
|
created_at TEXT NOT NULL
|
|
1987
2071
|
);
|
|
@@ -1990,7 +2074,7 @@ async function ensureSchema() {
|
|
|
1990
2074
|
ON notifications(read);
|
|
1991
2075
|
|
|
1992
2076
|
CREATE INDEX IF NOT EXISTS idx_notifications_agent
|
|
1993
|
-
ON notifications(agent_id);
|
|
2077
|
+
ON notifications(agent_id, session_scope);
|
|
1994
2078
|
|
|
1995
2079
|
CREATE INDEX IF NOT EXISTS idx_notifications_task_file
|
|
1996
2080
|
ON notifications(task_file);
|
|
@@ -2028,6 +2112,7 @@ async function ensureSchema() {
|
|
|
2028
2112
|
target_agent TEXT NOT NULL,
|
|
2029
2113
|
target_project TEXT,
|
|
2030
2114
|
target_device TEXT NOT NULL DEFAULT 'local',
|
|
2115
|
+
session_scope TEXT,
|
|
2031
2116
|
content TEXT NOT NULL,
|
|
2032
2117
|
priority TEXT DEFAULT 'normal',
|
|
2033
2118
|
status TEXT DEFAULT 'pending',
|
|
@@ -2041,10 +2126,31 @@ async function ensureSchema() {
|
|
|
2041
2126
|
);
|
|
2042
2127
|
|
|
2043
2128
|
CREATE INDEX IF NOT EXISTS idx_messages_target
|
|
2044
|
-
ON messages(target_agent, status);
|
|
2129
|
+
ON messages(target_agent, session_scope, status);
|
|
2045
2130
|
|
|
2046
2131
|
CREATE INDEX IF NOT EXISTS idx_messages_conversation_order
|
|
2047
|
-
ON messages(target_agent, from_agent, server_seq);
|
|
2132
|
+
ON messages(target_agent, session_scope, from_agent, server_seq);
|
|
2133
|
+
`);
|
|
2134
|
+
try {
|
|
2135
|
+
await client.execute({
|
|
2136
|
+
sql: `ALTER TABLE notifications ADD COLUMN session_scope TEXT`,
|
|
2137
|
+
args: []
|
|
2138
|
+
});
|
|
2139
|
+
} catch {
|
|
2140
|
+
}
|
|
2141
|
+
try {
|
|
2142
|
+
await client.execute({
|
|
2143
|
+
sql: `ALTER TABLE messages ADD COLUMN session_scope TEXT`,
|
|
2144
|
+
args: []
|
|
2145
|
+
});
|
|
2146
|
+
} catch {
|
|
2147
|
+
}
|
|
2148
|
+
await client.executeMultiple(`
|
|
2149
|
+
CREATE INDEX IF NOT EXISTS idx_notifications_agent_scope_read
|
|
2150
|
+
ON notifications(agent_id, session_scope, read, created_at);
|
|
2151
|
+
|
|
2152
|
+
CREATE INDEX IF NOT EXISTS idx_messages_target_scope_status
|
|
2153
|
+
ON messages(target_agent, session_scope, status, created_at);
|
|
2048
2154
|
`);
|
|
2049
2155
|
try {
|
|
2050
2156
|
await client.execute({
|
|
@@ -2628,6 +2734,13 @@ async function ensureSchema() {
|
|
|
2628
2734
|
} catch {
|
|
2629
2735
|
}
|
|
2630
2736
|
}
|
|
2737
|
+
try {
|
|
2738
|
+
await client.execute({
|
|
2739
|
+
sql: `UPDATE tasks SET status = 'closed' WHERE status = 'done' AND result IS NOT NULL`,
|
|
2740
|
+
args: []
|
|
2741
|
+
});
|
|
2742
|
+
} catch {
|
|
2743
|
+
}
|
|
2631
2744
|
}
|
|
2632
2745
|
async function disposeDatabase() {
|
|
2633
2746
|
if (_walCheckpointTimer) {
|
|
@@ -2666,24 +2779,27 @@ var init_database = __esm({
|
|
|
2666
2779
|
});
|
|
2667
2780
|
|
|
2668
2781
|
// src/lib/license.ts
|
|
2669
|
-
import { readFileSync as
|
|
2782
|
+
import { readFileSync as readFileSync8, writeFileSync as writeFileSync6, existsSync as existsSync8, mkdirSync as mkdirSync4 } from "fs";
|
|
2670
2783
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
2671
|
-
import
|
|
2784
|
+
import { createRequire as createRequire2 } from "module";
|
|
2785
|
+
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
2786
|
+
import os7 from "os";
|
|
2787
|
+
import path10 from "path";
|
|
2672
2788
|
import { jwtVerify, importSPKI } from "jose";
|
|
2673
2789
|
var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH;
|
|
2674
2790
|
var init_license = __esm({
|
|
2675
2791
|
"src/lib/license.ts"() {
|
|
2676
2792
|
"use strict";
|
|
2677
2793
|
init_config();
|
|
2678
|
-
LICENSE_PATH =
|
|
2679
|
-
CACHE_PATH =
|
|
2680
|
-
DEVICE_ID_PATH =
|
|
2794
|
+
LICENSE_PATH = path10.join(EXE_AI_DIR, "license.key");
|
|
2795
|
+
CACHE_PATH = path10.join(EXE_AI_DIR, "license-cache.json");
|
|
2796
|
+
DEVICE_ID_PATH = path10.join(EXE_AI_DIR, "device-id");
|
|
2681
2797
|
}
|
|
2682
2798
|
});
|
|
2683
2799
|
|
|
2684
2800
|
// src/lib/plan-limits.ts
|
|
2685
|
-
import { readFileSync as
|
|
2686
|
-
import
|
|
2801
|
+
import { readFileSync as readFileSync9, existsSync as existsSync9 } from "fs";
|
|
2802
|
+
import path11 from "path";
|
|
2687
2803
|
var CACHE_PATH2;
|
|
2688
2804
|
var init_plan_limits = __esm({
|
|
2689
2805
|
"src/lib/plan-limits.ts"() {
|
|
@@ -2692,14 +2808,14 @@ var init_plan_limits = __esm({
|
|
|
2692
2808
|
init_employees();
|
|
2693
2809
|
init_license();
|
|
2694
2810
|
init_config();
|
|
2695
|
-
CACHE_PATH2 =
|
|
2811
|
+
CACHE_PATH2 = path11.join(EXE_AI_DIR, "license-cache.json");
|
|
2696
2812
|
}
|
|
2697
2813
|
});
|
|
2698
2814
|
|
|
2699
2815
|
// src/lib/tmux-routing.ts
|
|
2700
|
-
import { readFileSync as
|
|
2701
|
-
import
|
|
2702
|
-
import
|
|
2816
|
+
import { readFileSync as readFileSync10, writeFileSync as writeFileSync7, mkdirSync as mkdirSync5, existsSync as existsSync10, appendFileSync, readdirSync as readdirSync2 } from "fs";
|
|
2817
|
+
import path12 from "path";
|
|
2818
|
+
import os8 from "os";
|
|
2703
2819
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
2704
2820
|
function getMySession() {
|
|
2705
2821
|
return getTransport().getMySession();
|
|
@@ -2712,7 +2828,7 @@ function extractRootExe(name) {
|
|
|
2712
2828
|
}
|
|
2713
2829
|
function getParentExe(sessionKey) {
|
|
2714
2830
|
try {
|
|
2715
|
-
const data = JSON.parse(
|
|
2831
|
+
const data = JSON.parse(readFileSync10(path12.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
|
|
2716
2832
|
return data.parentExe || null;
|
|
2717
2833
|
} catch {
|
|
2718
2834
|
return null;
|
|
@@ -2755,10 +2871,10 @@ var init_tmux_routing = __esm({
|
|
|
2755
2871
|
init_intercom_queue();
|
|
2756
2872
|
init_plan_limits();
|
|
2757
2873
|
init_employees();
|
|
2758
|
-
SPAWN_LOCK_DIR =
|
|
2759
|
-
SESSION_CACHE =
|
|
2760
|
-
INTERCOM_LOG2 =
|
|
2761
|
-
DEBOUNCE_FILE =
|
|
2874
|
+
SPAWN_LOCK_DIR = path12.join(os8.homedir(), ".exe-os", "spawn-locks");
|
|
2875
|
+
SESSION_CACHE = path12.join(os8.homedir(), ".exe-os", "session-cache");
|
|
2876
|
+
INTERCOM_LOG2 = path12.join(os8.homedir(), ".exe-os", "intercom.log");
|
|
2877
|
+
DEBOUNCE_FILE = path12.join(SESSION_CACHE, "intercom-debounce.json");
|
|
2762
2878
|
DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
|
|
2763
2879
|
}
|
|
2764
2880
|
});
|
|
@@ -2798,14 +2914,14 @@ var init_memory = __esm({
|
|
|
2798
2914
|
|
|
2799
2915
|
// src/lib/keychain.ts
|
|
2800
2916
|
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
|
|
2801
|
-
import { existsSync as
|
|
2802
|
-
import
|
|
2803
|
-
import
|
|
2917
|
+
import { existsSync as existsSync11 } from "fs";
|
|
2918
|
+
import path13 from "path";
|
|
2919
|
+
import os9 from "os";
|
|
2804
2920
|
function getKeyDir() {
|
|
2805
|
-
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ??
|
|
2921
|
+
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path13.join(os9.homedir(), ".exe-os");
|
|
2806
2922
|
}
|
|
2807
2923
|
function getKeyPath() {
|
|
2808
|
-
return
|
|
2924
|
+
return path13.join(getKeyDir(), "master.key");
|
|
2809
2925
|
}
|
|
2810
2926
|
async function tryKeytar() {
|
|
2811
2927
|
try {
|
|
@@ -2826,9 +2942,9 @@ async function getMasterKey() {
|
|
|
2826
2942
|
}
|
|
2827
2943
|
}
|
|
2828
2944
|
const keyPath = getKeyPath();
|
|
2829
|
-
if (!
|
|
2945
|
+
if (!existsSync11(keyPath)) {
|
|
2830
2946
|
process.stderr.write(
|
|
2831
|
-
`[keychain] Key not found at ${keyPath} (HOME=${
|
|
2947
|
+
`[keychain] Key not found at ${keyPath} (HOME=${os9.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
|
|
2832
2948
|
`
|
|
2833
2949
|
);
|
|
2834
2950
|
return null;
|
|
@@ -2913,6 +3029,7 @@ var shard_manager_exports = {};
|
|
|
2913
3029
|
__export(shard_manager_exports, {
|
|
2914
3030
|
disposeShards: () => disposeShards,
|
|
2915
3031
|
ensureShardSchema: () => ensureShardSchema,
|
|
3032
|
+
getOpenShardCount: () => getOpenShardCount,
|
|
2916
3033
|
getReadyShardClient: () => getReadyShardClient,
|
|
2917
3034
|
getShardClient: () => getShardClient,
|
|
2918
3035
|
getShardsDir: () => getShardsDir,
|
|
@@ -2921,15 +3038,18 @@ __export(shard_manager_exports, {
|
|
|
2921
3038
|
listShards: () => listShards,
|
|
2922
3039
|
shardExists: () => shardExists
|
|
2923
3040
|
});
|
|
2924
|
-
import
|
|
2925
|
-
import { existsSync as
|
|
3041
|
+
import path14 from "path";
|
|
3042
|
+
import { existsSync as existsSync12, mkdirSync as mkdirSync6, readdirSync as readdirSync3 } from "fs";
|
|
2926
3043
|
import { createClient as createClient2 } from "@libsql/client";
|
|
2927
3044
|
function initShardManager(encryptionKey) {
|
|
2928
3045
|
_encryptionKey = encryptionKey;
|
|
2929
|
-
if (!
|
|
3046
|
+
if (!existsSync12(SHARDS_DIR)) {
|
|
2930
3047
|
mkdirSync6(SHARDS_DIR, { recursive: true });
|
|
2931
3048
|
}
|
|
2932
3049
|
_shardingEnabled = true;
|
|
3050
|
+
if (_evictionTimer) clearInterval(_evictionTimer);
|
|
3051
|
+
_evictionTimer = setInterval(evictIdleShards, EVICTION_INTERVAL_MS);
|
|
3052
|
+
_evictionTimer.unref();
|
|
2933
3053
|
}
|
|
2934
3054
|
function isShardingEnabled() {
|
|
2935
3055
|
return _shardingEnabled;
|
|
@@ -2946,21 +3066,28 @@ function getShardClient(projectName) {
|
|
|
2946
3066
|
throw new Error(`Invalid project name for shard: "${projectName}"`);
|
|
2947
3067
|
}
|
|
2948
3068
|
const cached = _shards.get(safeName);
|
|
2949
|
-
if (cached)
|
|
2950
|
-
|
|
3069
|
+
if (cached) {
|
|
3070
|
+
_shardLastAccess.set(safeName, Date.now());
|
|
3071
|
+
return cached;
|
|
3072
|
+
}
|
|
3073
|
+
while (_shards.size >= MAX_OPEN_SHARDS) {
|
|
3074
|
+
evictLRU();
|
|
3075
|
+
}
|
|
3076
|
+
const dbPath = path14.join(SHARDS_DIR, `${safeName}.db`);
|
|
2951
3077
|
const client = createClient2({
|
|
2952
3078
|
url: `file:${dbPath}`,
|
|
2953
3079
|
encryptionKey: _encryptionKey
|
|
2954
3080
|
});
|
|
2955
3081
|
_shards.set(safeName, client);
|
|
3082
|
+
_shardLastAccess.set(safeName, Date.now());
|
|
2956
3083
|
return client;
|
|
2957
3084
|
}
|
|
2958
3085
|
function shardExists(projectName) {
|
|
2959
3086
|
const safeName = projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
2960
|
-
return
|
|
3087
|
+
return existsSync12(path14.join(SHARDS_DIR, `${safeName}.db`));
|
|
2961
3088
|
}
|
|
2962
3089
|
function listShards() {
|
|
2963
|
-
if (!
|
|
3090
|
+
if (!existsSync12(SHARDS_DIR)) return [];
|
|
2964
3091
|
return readdirSync3(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
|
|
2965
3092
|
}
|
|
2966
3093
|
async function ensureShardSchema(client) {
|
|
@@ -3012,6 +3139,8 @@ async function ensureShardSchema(client) {
|
|
|
3012
3139
|
for (const col of [
|
|
3013
3140
|
"ALTER TABLE memories ADD COLUMN task_id TEXT",
|
|
3014
3141
|
"ALTER TABLE memories ADD COLUMN consolidated INTEGER NOT NULL DEFAULT 0",
|
|
3142
|
+
"ALTER TABLE memories ADD COLUMN author_device_id TEXT",
|
|
3143
|
+
"ALTER TABLE memories ADD COLUMN scope TEXT NOT NULL DEFAULT 'business'",
|
|
3015
3144
|
"ALTER TABLE memories ADD COLUMN importance INTEGER DEFAULT 5",
|
|
3016
3145
|
"ALTER TABLE memories ADD COLUMN status TEXT DEFAULT 'active'",
|
|
3017
3146
|
"ALTER TABLE memories ADD COLUMN wiki_synced INTEGER DEFAULT 0",
|
|
@@ -3149,21 +3278,69 @@ async function getReadyShardClient(projectName) {
|
|
|
3149
3278
|
await ensureShardSchema(client);
|
|
3150
3279
|
return client;
|
|
3151
3280
|
}
|
|
3281
|
+
function evictLRU() {
|
|
3282
|
+
let oldest = null;
|
|
3283
|
+
let oldestTime = Infinity;
|
|
3284
|
+
for (const [name, time] of _shardLastAccess) {
|
|
3285
|
+
if (time < oldestTime) {
|
|
3286
|
+
oldestTime = time;
|
|
3287
|
+
oldest = name;
|
|
3288
|
+
}
|
|
3289
|
+
}
|
|
3290
|
+
if (oldest) {
|
|
3291
|
+
const client = _shards.get(oldest);
|
|
3292
|
+
if (client) {
|
|
3293
|
+
client.close();
|
|
3294
|
+
}
|
|
3295
|
+
_shards.delete(oldest);
|
|
3296
|
+
_shardLastAccess.delete(oldest);
|
|
3297
|
+
}
|
|
3298
|
+
}
|
|
3299
|
+
function evictIdleShards() {
|
|
3300
|
+
const now = Date.now();
|
|
3301
|
+
const toEvict = [];
|
|
3302
|
+
for (const [name, lastAccess] of _shardLastAccess) {
|
|
3303
|
+
if (now - lastAccess > SHARD_IDLE_MS) {
|
|
3304
|
+
toEvict.push(name);
|
|
3305
|
+
}
|
|
3306
|
+
}
|
|
3307
|
+
for (const name of toEvict) {
|
|
3308
|
+
const client = _shards.get(name);
|
|
3309
|
+
if (client) {
|
|
3310
|
+
client.close();
|
|
3311
|
+
}
|
|
3312
|
+
_shards.delete(name);
|
|
3313
|
+
_shardLastAccess.delete(name);
|
|
3314
|
+
}
|
|
3315
|
+
}
|
|
3316
|
+
function getOpenShardCount() {
|
|
3317
|
+
return _shards.size;
|
|
3318
|
+
}
|
|
3152
3319
|
function disposeShards() {
|
|
3320
|
+
if (_evictionTimer) {
|
|
3321
|
+
clearInterval(_evictionTimer);
|
|
3322
|
+
_evictionTimer = null;
|
|
3323
|
+
}
|
|
3153
3324
|
for (const [, client] of _shards) {
|
|
3154
3325
|
client.close();
|
|
3155
3326
|
}
|
|
3156
3327
|
_shards.clear();
|
|
3328
|
+
_shardLastAccess.clear();
|
|
3157
3329
|
_shardingEnabled = false;
|
|
3158
3330
|
_encryptionKey = null;
|
|
3159
3331
|
}
|
|
3160
|
-
var SHARDS_DIR, _shards, _encryptionKey, _shardingEnabled;
|
|
3332
|
+
var SHARDS_DIR, SHARD_IDLE_MS, MAX_OPEN_SHARDS, EVICTION_INTERVAL_MS, _shards, _shardLastAccess, _evictionTimer, _encryptionKey, _shardingEnabled;
|
|
3161
3333
|
var init_shard_manager = __esm({
|
|
3162
3334
|
"src/lib/shard-manager.ts"() {
|
|
3163
3335
|
"use strict";
|
|
3164
3336
|
init_config();
|
|
3165
|
-
SHARDS_DIR =
|
|
3337
|
+
SHARDS_DIR = path14.join(EXE_AI_DIR, "shards");
|
|
3338
|
+
SHARD_IDLE_MS = 5 * 60 * 1e3;
|
|
3339
|
+
MAX_OPEN_SHARDS = 10;
|
|
3340
|
+
EVICTION_INTERVAL_MS = 60 * 1e3;
|
|
3166
3341
|
_shards = /* @__PURE__ */ new Map();
|
|
3342
|
+
_shardLastAccess = /* @__PURE__ */ new Map();
|
|
3343
|
+
_evictionTimer = null;
|
|
3167
3344
|
_encryptionKey = null;
|
|
3168
3345
|
_shardingEnabled = false;
|
|
3169
3346
|
}
|
|
@@ -3930,7 +4107,7 @@ var init_store = __esm({
|
|
|
3930
4107
|
init_config();
|
|
3931
4108
|
init_session_key();
|
|
3932
4109
|
init_employees();
|
|
3933
|
-
import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, mkdirSync, unlinkSync as unlinkSync2, readdirSync } from "fs";
|
|
4110
|
+
import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2, unlinkSync as unlinkSync2, readdirSync } from "fs";
|
|
3934
4111
|
import { execSync as execSync3 } from "child_process";
|
|
3935
4112
|
import path3 from "path";
|
|
3936
4113
|
var CACHE_DIR = path3.join(EXE_AI_DIR, "session-cache");
|