@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,6 +19,44 @@ 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
61
|
var config_exports = {};
|
|
24
62
|
__export(config_exports, {
|
|
@@ -35,8 +73,8 @@ __export(config_exports, {
|
|
|
35
73
|
migrateConfig: () => migrateConfig,
|
|
36
74
|
saveConfig: () => saveConfig
|
|
37
75
|
});
|
|
38
|
-
import { readFile, writeFile
|
|
39
|
-
import { readFileSync, existsSync, renameSync } from "fs";
|
|
76
|
+
import { readFile, writeFile } from "fs/promises";
|
|
77
|
+
import { readFileSync, existsSync as existsSync2, renameSync } from "fs";
|
|
40
78
|
import path from "path";
|
|
41
79
|
import os from "os";
|
|
42
80
|
function resolveDataDir() {
|
|
@@ -44,7 +82,7 @@ function resolveDataDir() {
|
|
|
44
82
|
if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
|
|
45
83
|
const newDir = path.join(os.homedir(), ".exe-os");
|
|
46
84
|
const legacyDir = path.join(os.homedir(), ".exe-mem");
|
|
47
|
-
if (!
|
|
85
|
+
if (!existsSync2(newDir) && existsSync2(legacyDir)) {
|
|
48
86
|
try {
|
|
49
87
|
renameSync(legacyDir, newDir);
|
|
50
88
|
process.stderr.write(`[exe-os] Migrated data directory: ~/.exe-mem \u2192 ~/.exe-os
|
|
@@ -107,9 +145,9 @@ function normalizeAutoUpdate(raw) {
|
|
|
107
145
|
}
|
|
108
146
|
async function loadConfig() {
|
|
109
147
|
const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
|
|
110
|
-
await
|
|
148
|
+
await ensurePrivateDir(dir);
|
|
111
149
|
const configPath = path.join(dir, "config.json");
|
|
112
|
-
if (!
|
|
150
|
+
if (!existsSync2(configPath)) {
|
|
113
151
|
return { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db") };
|
|
114
152
|
}
|
|
115
153
|
const raw = await readFile(configPath, "utf-8");
|
|
@@ -122,6 +160,7 @@ async function loadConfig() {
|
|
|
122
160
|
`);
|
|
123
161
|
try {
|
|
124
162
|
await writeFile(configPath, JSON.stringify(migratedCfg, null, 2) + "\n");
|
|
163
|
+
await enforcePrivateFile(configPath);
|
|
125
164
|
} catch {
|
|
126
165
|
}
|
|
127
166
|
}
|
|
@@ -140,7 +179,7 @@ async function loadConfig() {
|
|
|
140
179
|
function loadConfigSync() {
|
|
141
180
|
const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
|
|
142
181
|
const configPath = path.join(dir, "config.json");
|
|
143
|
-
if (!
|
|
182
|
+
if (!existsSync2(configPath)) {
|
|
144
183
|
return { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db") };
|
|
145
184
|
}
|
|
146
185
|
try {
|
|
@@ -158,12 +197,10 @@ function loadConfigSync() {
|
|
|
158
197
|
}
|
|
159
198
|
async function saveConfig(config) {
|
|
160
199
|
const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
|
|
161
|
-
await
|
|
200
|
+
await ensurePrivateDir(dir);
|
|
162
201
|
const configPath = path.join(dir, "config.json");
|
|
163
202
|
await writeFile(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
164
|
-
|
|
165
|
-
await chmod(configPath, 384);
|
|
166
|
-
}
|
|
203
|
+
await enforcePrivateFile(configPath);
|
|
167
204
|
}
|
|
168
205
|
async function loadConfigFrom(configPath) {
|
|
169
206
|
const raw = await readFile(configPath, "utf-8");
|
|
@@ -183,6 +220,7 @@ var EXE_AI_DIR, DB_PATH, MODELS_DIR, CONFIG_PATH, LEGACY_LANCE_PATH, CURRENT_CON
|
|
|
183
220
|
var init_config = __esm({
|
|
184
221
|
"src/lib/config.ts"() {
|
|
185
222
|
"use strict";
|
|
223
|
+
init_secure_files();
|
|
186
224
|
EXE_AI_DIR = resolveDataDir();
|
|
187
225
|
DB_PATH = path.join(EXE_AI_DIR, "memories.db");
|
|
188
226
|
MODELS_DIR = path.join(EXE_AI_DIR, "models");
|
|
@@ -363,10 +401,10 @@ __export(agent_config_exports, {
|
|
|
363
401
|
saveAgentConfig: () => saveAgentConfig,
|
|
364
402
|
setAgentRuntime: () => setAgentRuntime
|
|
365
403
|
});
|
|
366
|
-
import { readFileSync as readFileSync2, writeFileSync, existsSync as
|
|
404
|
+
import { readFileSync as readFileSync2, writeFileSync, existsSync as existsSync3 } from "fs";
|
|
367
405
|
import path2 from "path";
|
|
368
406
|
function loadAgentConfig() {
|
|
369
|
-
if (!
|
|
407
|
+
if (!existsSync3(AGENT_CONFIG_PATH)) return {};
|
|
370
408
|
try {
|
|
371
409
|
return JSON.parse(readFileSync2(AGENT_CONFIG_PATH, "utf-8"));
|
|
372
410
|
} catch {
|
|
@@ -375,8 +413,9 @@ function loadAgentConfig() {
|
|
|
375
413
|
}
|
|
376
414
|
function saveAgentConfig(config) {
|
|
377
415
|
const dir = path2.dirname(AGENT_CONFIG_PATH);
|
|
378
|
-
|
|
416
|
+
ensurePrivateDirSync(dir);
|
|
379
417
|
writeFileSync(AGENT_CONFIG_PATH, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
418
|
+
enforcePrivateFileSync(AGENT_CONFIG_PATH);
|
|
380
419
|
}
|
|
381
420
|
function getAgentRuntime(agentId) {
|
|
382
421
|
const config = loadAgentConfig();
|
|
@@ -416,6 +455,7 @@ var init_agent_config = __esm({
|
|
|
416
455
|
"use strict";
|
|
417
456
|
init_config();
|
|
418
457
|
init_runtime_table();
|
|
458
|
+
init_secure_files();
|
|
419
459
|
AGENT_CONFIG_PATH = path2.join(EXE_AI_DIR, "agent-config.json");
|
|
420
460
|
KNOWN_RUNTIMES = {
|
|
421
461
|
claude: ["claude-opus-4", "claude-sonnet-4", "claude-haiku-4.5"],
|
|
@@ -463,7 +503,7 @@ __export(employees_exports, {
|
|
|
463
503
|
validateEmployeeName: () => validateEmployeeName
|
|
464
504
|
});
|
|
465
505
|
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
466
|
-
import { existsSync as
|
|
506
|
+
import { existsSync as existsSync4, symlinkSync, readlinkSync, readFileSync as readFileSync3, renameSync as renameSync2, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
|
|
467
507
|
import { execSync } from "child_process";
|
|
468
508
|
import path3 from "path";
|
|
469
509
|
import os2 from "os";
|
|
@@ -502,7 +542,7 @@ function validateEmployeeName(name) {
|
|
|
502
542
|
return { valid: true };
|
|
503
543
|
}
|
|
504
544
|
async function loadEmployees(employeesPath = EMPLOYEES_PATH) {
|
|
505
|
-
if (!
|
|
545
|
+
if (!existsSync4(employeesPath)) {
|
|
506
546
|
return [];
|
|
507
547
|
}
|
|
508
548
|
const raw = await readFile2(employeesPath, "utf-8");
|
|
@@ -517,7 +557,7 @@ async function saveEmployees(employees, employeesPath = EMPLOYEES_PATH) {
|
|
|
517
557
|
await writeFile2(employeesPath, JSON.stringify(employees, null, 2) + "\n", "utf-8");
|
|
518
558
|
}
|
|
519
559
|
function loadEmployeesSync(employeesPath = EMPLOYEES_PATH) {
|
|
520
|
-
if (!
|
|
560
|
+
if (!existsSync4(employeesPath)) return [];
|
|
521
561
|
try {
|
|
522
562
|
return JSON.parse(readFileSync3(employeesPath, "utf-8"));
|
|
523
563
|
} catch {
|
|
@@ -565,7 +605,7 @@ function appendToCoordinatorTeam(employee) {
|
|
|
565
605
|
const coordinator = getCoordinatorEmployee(loadEmployeesSync());
|
|
566
606
|
if (!coordinator) return;
|
|
567
607
|
const idPath = path3.join(IDENTITY_DIR, `${coordinator.name}.md`);
|
|
568
|
-
if (!
|
|
608
|
+
if (!existsSync4(idPath)) return;
|
|
569
609
|
const content = readFileSync3(idPath, "utf-8");
|
|
570
610
|
if (content.includes(`**${capitalize(employee.name)}`)) return;
|
|
571
611
|
const teamMatch = content.match(TEAM_SECTION_RE);
|
|
@@ -619,9 +659,9 @@ async function normalizeRosterCase(rosterPath) {
|
|
|
619
659
|
const identityDir = path3.join(os2.homedir(), ".exe-os", "identity");
|
|
620
660
|
const oldPath = path3.join(identityDir, `${oldName}.md`);
|
|
621
661
|
const newPath = path3.join(identityDir, `${emp.name}.md`);
|
|
622
|
-
if (
|
|
662
|
+
if (existsSync4(oldPath) && !existsSync4(newPath)) {
|
|
623
663
|
renameSync2(oldPath, newPath);
|
|
624
|
-
} else if (
|
|
664
|
+
} else if (existsSync4(oldPath) && oldPath !== newPath) {
|
|
625
665
|
const content = readFileSync3(oldPath, "utf-8");
|
|
626
666
|
writeFileSync2(newPath, content, "utf-8");
|
|
627
667
|
if (oldPath.toLowerCase() !== newPath.toLowerCase()) {
|
|
@@ -664,7 +704,7 @@ function registerBinSymlinks(name) {
|
|
|
664
704
|
for (const suffix of ["", "-opencode"]) {
|
|
665
705
|
const linkName = `${name}${suffix}`;
|
|
666
706
|
const linkPath = path3.join(binDir, linkName);
|
|
667
|
-
if (
|
|
707
|
+
if (existsSync4(linkPath)) {
|
|
668
708
|
skipped.push(linkName);
|
|
669
709
|
continue;
|
|
670
710
|
}
|
|
@@ -1275,13 +1315,50 @@ var init_database_adapter = __esm({
|
|
|
1275
1315
|
}
|
|
1276
1316
|
});
|
|
1277
1317
|
|
|
1318
|
+
// src/lib/daemon-auth.ts
|
|
1319
|
+
import crypto from "crypto";
|
|
1320
|
+
import path5 from "path";
|
|
1321
|
+
import { existsSync as existsSync5, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "fs";
|
|
1322
|
+
function normalizeToken(token) {
|
|
1323
|
+
if (!token) return null;
|
|
1324
|
+
const trimmed = token.trim();
|
|
1325
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
1326
|
+
}
|
|
1327
|
+
function readDaemonToken() {
|
|
1328
|
+
try {
|
|
1329
|
+
if (!existsSync5(DAEMON_TOKEN_PATH)) return null;
|
|
1330
|
+
return normalizeToken(readFileSync4(DAEMON_TOKEN_PATH, "utf8"));
|
|
1331
|
+
} catch {
|
|
1332
|
+
return null;
|
|
1333
|
+
}
|
|
1334
|
+
}
|
|
1335
|
+
function ensureDaemonToken(seed) {
|
|
1336
|
+
const existing = readDaemonToken();
|
|
1337
|
+
if (existing) return existing;
|
|
1338
|
+
const token = normalizeToken(seed) ?? crypto.randomBytes(32).toString("hex");
|
|
1339
|
+
ensurePrivateDirSync(EXE_AI_DIR);
|
|
1340
|
+
writeFileSync3(DAEMON_TOKEN_PATH, `${token}
|
|
1341
|
+
`, "utf8");
|
|
1342
|
+
enforcePrivateFileSync(DAEMON_TOKEN_PATH);
|
|
1343
|
+
return token;
|
|
1344
|
+
}
|
|
1345
|
+
var DAEMON_TOKEN_PATH;
|
|
1346
|
+
var init_daemon_auth = __esm({
|
|
1347
|
+
"src/lib/daemon-auth.ts"() {
|
|
1348
|
+
"use strict";
|
|
1349
|
+
init_config();
|
|
1350
|
+
init_secure_files();
|
|
1351
|
+
DAEMON_TOKEN_PATH = path5.join(EXE_AI_DIR, "exed.token");
|
|
1352
|
+
}
|
|
1353
|
+
});
|
|
1354
|
+
|
|
1278
1355
|
// src/lib/exe-daemon-client.ts
|
|
1279
1356
|
import net from "net";
|
|
1280
1357
|
import os4 from "os";
|
|
1281
1358
|
import { spawn } from "child_process";
|
|
1282
1359
|
import { randomUUID } from "crypto";
|
|
1283
|
-
import { existsSync as
|
|
1284
|
-
import
|
|
1360
|
+
import { existsSync as existsSync6, unlinkSync as unlinkSync2, readFileSync as readFileSync5, openSync, closeSync, statSync } from "fs";
|
|
1361
|
+
import path6 from "path";
|
|
1285
1362
|
import { fileURLToPath } from "url";
|
|
1286
1363
|
function handleData(chunk) {
|
|
1287
1364
|
_buffer += chunk.toString();
|
|
@@ -1309,9 +1386,9 @@ function handleData(chunk) {
|
|
|
1309
1386
|
}
|
|
1310
1387
|
}
|
|
1311
1388
|
function cleanupStaleFiles() {
|
|
1312
|
-
if (
|
|
1389
|
+
if (existsSync6(PID_PATH)) {
|
|
1313
1390
|
try {
|
|
1314
|
-
const pid = parseInt(
|
|
1391
|
+
const pid = parseInt(readFileSync5(PID_PATH, "utf8").trim(), 10);
|
|
1315
1392
|
if (pid > 0) {
|
|
1316
1393
|
try {
|
|
1317
1394
|
process.kill(pid, 0);
|
|
@@ -1332,11 +1409,11 @@ function cleanupStaleFiles() {
|
|
|
1332
1409
|
}
|
|
1333
1410
|
}
|
|
1334
1411
|
function findPackageRoot() {
|
|
1335
|
-
let dir =
|
|
1336
|
-
const { root } =
|
|
1412
|
+
let dir = path6.dirname(fileURLToPath(import.meta.url));
|
|
1413
|
+
const { root } = path6.parse(dir);
|
|
1337
1414
|
while (dir !== root) {
|
|
1338
|
-
if (
|
|
1339
|
-
dir =
|
|
1415
|
+
if (existsSync6(path6.join(dir, "package.json"))) return dir;
|
|
1416
|
+
dir = path6.dirname(dir);
|
|
1340
1417
|
}
|
|
1341
1418
|
return null;
|
|
1342
1419
|
}
|
|
@@ -1362,16 +1439,17 @@ function spawnDaemon() {
|
|
|
1362
1439
|
process.stderr.write("[exed-client] WARN: cannot find package root\n");
|
|
1363
1440
|
return;
|
|
1364
1441
|
}
|
|
1365
|
-
const daemonPath =
|
|
1366
|
-
if (!
|
|
1442
|
+
const daemonPath = path6.join(pkgRoot, "dist", "lib", "exe-daemon.js");
|
|
1443
|
+
if (!existsSync6(daemonPath)) {
|
|
1367
1444
|
process.stderr.write(`[exed-client] WARN: daemon script not found at ${daemonPath}
|
|
1368
1445
|
`);
|
|
1369
1446
|
return;
|
|
1370
1447
|
}
|
|
1371
1448
|
const resolvedPath = daemonPath;
|
|
1449
|
+
const daemonToken = ensureDaemonToken(process.env[DAEMON_TOKEN_ENV] ?? null);
|
|
1372
1450
|
process.stderr.write(`[exed-client] Spawning daemon: ${resolvedPath}
|
|
1373
1451
|
`);
|
|
1374
|
-
const logPath =
|
|
1452
|
+
const logPath = path6.join(path6.dirname(SOCKET_PATH), "exed.log");
|
|
1375
1453
|
let stderrFd = "ignore";
|
|
1376
1454
|
try {
|
|
1377
1455
|
stderrFd = openSync(logPath, "a");
|
|
@@ -1389,7 +1467,8 @@ function spawnDaemon() {
|
|
|
1389
1467
|
TMUX_PANE: void 0,
|
|
1390
1468
|
// Prevents resolveExeSession() from scoping to one session
|
|
1391
1469
|
EXE_DAEMON_SOCK: SOCKET_PATH,
|
|
1392
|
-
EXE_DAEMON_PID: PID_PATH
|
|
1470
|
+
EXE_DAEMON_PID: PID_PATH,
|
|
1471
|
+
[DAEMON_TOKEN_ENV]: daemonToken
|
|
1393
1472
|
}
|
|
1394
1473
|
});
|
|
1395
1474
|
child.unref();
|
|
@@ -1499,13 +1578,14 @@ function sendDaemonRequest(payload, timeoutMs = REQUEST_TIMEOUT_MS) {
|
|
|
1499
1578
|
return;
|
|
1500
1579
|
}
|
|
1501
1580
|
const id = randomUUID();
|
|
1581
|
+
const token = process.env[DAEMON_TOKEN_ENV] ?? readDaemonToken();
|
|
1502
1582
|
const timer = setTimeout(() => {
|
|
1503
1583
|
_pending.delete(id);
|
|
1504
1584
|
resolve({ error: "Request timeout" });
|
|
1505
1585
|
}, timeoutMs);
|
|
1506
1586
|
_pending.set(id, { resolve, timer });
|
|
1507
1587
|
try {
|
|
1508
|
-
_socket.write(JSON.stringify({ id, ...payload }) + "\n");
|
|
1588
|
+
_socket.write(JSON.stringify({ id, token, ...payload }) + "\n");
|
|
1509
1589
|
} catch {
|
|
1510
1590
|
clearTimeout(timer);
|
|
1511
1591
|
_pending.delete(id);
|
|
@@ -1534,9 +1614,9 @@ function killAndRespawnDaemon() {
|
|
|
1534
1614
|
}
|
|
1535
1615
|
try {
|
|
1536
1616
|
process.stderr.write("[exed-client] Killing daemon for restart...\n");
|
|
1537
|
-
if (
|
|
1617
|
+
if (existsSync6(PID_PATH)) {
|
|
1538
1618
|
try {
|
|
1539
|
-
const pid = parseInt(
|
|
1619
|
+
const pid = parseInt(readFileSync5(PID_PATH, "utf8").trim(), 10);
|
|
1540
1620
|
if (pid > 0) {
|
|
1541
1621
|
try {
|
|
1542
1622
|
process.kill(pid, "SIGKILL");
|
|
@@ -1656,17 +1736,19 @@ function disconnectClient() {
|
|
|
1656
1736
|
function isClientConnected() {
|
|
1657
1737
|
return _connected;
|
|
1658
1738
|
}
|
|
1659
|
-
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;
|
|
1739
|
+
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;
|
|
1660
1740
|
var init_exe_daemon_client = __esm({
|
|
1661
1741
|
"src/lib/exe-daemon-client.ts"() {
|
|
1662
1742
|
"use strict";
|
|
1663
1743
|
init_config();
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1744
|
+
init_daemon_auth();
|
|
1745
|
+
SOCKET_PATH = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ?? path6.join(EXE_AI_DIR, "exed.sock");
|
|
1746
|
+
PID_PATH = process.env.EXE_DAEMON_PID ?? process.env.EXE_EMBED_PID ?? path6.join(EXE_AI_DIR, "exed.pid");
|
|
1747
|
+
SPAWN_LOCK_PATH = path6.join(EXE_AI_DIR, "exed-spawn.lock");
|
|
1667
1748
|
SPAWN_LOCK_STALE_MS = 3e4;
|
|
1668
1749
|
CONNECT_TIMEOUT_MS = 15e3;
|
|
1669
1750
|
REQUEST_TIMEOUT_MS = 3e4;
|
|
1751
|
+
DAEMON_TOKEN_ENV = "EXE_DAEMON_TOKEN";
|
|
1670
1752
|
_socket = null;
|
|
1671
1753
|
_connected = false;
|
|
1672
1754
|
_buffer = "";
|
|
@@ -2251,6 +2333,7 @@ async function ensureSchema() {
|
|
|
2251
2333
|
project TEXT NOT NULL,
|
|
2252
2334
|
summary TEXT NOT NULL,
|
|
2253
2335
|
task_file TEXT,
|
|
2336
|
+
session_scope TEXT,
|
|
2254
2337
|
read INTEGER NOT NULL DEFAULT 0,
|
|
2255
2338
|
created_at TEXT NOT NULL
|
|
2256
2339
|
);
|
|
@@ -2259,7 +2342,7 @@ async function ensureSchema() {
|
|
|
2259
2342
|
ON notifications(read);
|
|
2260
2343
|
|
|
2261
2344
|
CREATE INDEX IF NOT EXISTS idx_notifications_agent
|
|
2262
|
-
ON notifications(agent_id);
|
|
2345
|
+
ON notifications(agent_id, session_scope);
|
|
2263
2346
|
|
|
2264
2347
|
CREATE INDEX IF NOT EXISTS idx_notifications_task_file
|
|
2265
2348
|
ON notifications(task_file);
|
|
@@ -2297,6 +2380,7 @@ async function ensureSchema() {
|
|
|
2297
2380
|
target_agent TEXT NOT NULL,
|
|
2298
2381
|
target_project TEXT,
|
|
2299
2382
|
target_device TEXT NOT NULL DEFAULT 'local',
|
|
2383
|
+
session_scope TEXT,
|
|
2300
2384
|
content TEXT NOT NULL,
|
|
2301
2385
|
priority TEXT DEFAULT 'normal',
|
|
2302
2386
|
status TEXT DEFAULT 'pending',
|
|
@@ -2310,10 +2394,31 @@ async function ensureSchema() {
|
|
|
2310
2394
|
);
|
|
2311
2395
|
|
|
2312
2396
|
CREATE INDEX IF NOT EXISTS idx_messages_target
|
|
2313
|
-
ON messages(target_agent, status);
|
|
2397
|
+
ON messages(target_agent, session_scope, status);
|
|
2314
2398
|
|
|
2315
2399
|
CREATE INDEX IF NOT EXISTS idx_messages_conversation_order
|
|
2316
|
-
ON messages(target_agent, from_agent, server_seq);
|
|
2400
|
+
ON messages(target_agent, session_scope, from_agent, server_seq);
|
|
2401
|
+
`);
|
|
2402
|
+
try {
|
|
2403
|
+
await client.execute({
|
|
2404
|
+
sql: `ALTER TABLE notifications ADD COLUMN session_scope TEXT`,
|
|
2405
|
+
args: []
|
|
2406
|
+
});
|
|
2407
|
+
} catch {
|
|
2408
|
+
}
|
|
2409
|
+
try {
|
|
2410
|
+
await client.execute({
|
|
2411
|
+
sql: `ALTER TABLE messages ADD COLUMN session_scope TEXT`,
|
|
2412
|
+
args: []
|
|
2413
|
+
});
|
|
2414
|
+
} catch {
|
|
2415
|
+
}
|
|
2416
|
+
await client.executeMultiple(`
|
|
2417
|
+
CREATE INDEX IF NOT EXISTS idx_notifications_agent_scope_read
|
|
2418
|
+
ON notifications(agent_id, session_scope, read, created_at);
|
|
2419
|
+
|
|
2420
|
+
CREATE INDEX IF NOT EXISTS idx_messages_target_scope_status
|
|
2421
|
+
ON messages(target_agent, session_scope, status, created_at);
|
|
2317
2422
|
`);
|
|
2318
2423
|
try {
|
|
2319
2424
|
await client.execute({
|
|
@@ -2897,6 +3002,13 @@ async function ensureSchema() {
|
|
|
2897
3002
|
} catch {
|
|
2898
3003
|
}
|
|
2899
3004
|
}
|
|
3005
|
+
try {
|
|
3006
|
+
await client.execute({
|
|
3007
|
+
sql: `UPDATE tasks SET status = 'closed' WHERE status = 'done' AND result IS NOT NULL`,
|
|
3008
|
+
args: []
|
|
3009
|
+
});
|
|
3010
|
+
} catch {
|
|
3011
|
+
}
|
|
2900
3012
|
}
|
|
2901
3013
|
async function disposeDatabase() {
|
|
2902
3014
|
if (_walCheckpointTimer) {
|
|
@@ -2936,14 +3048,14 @@ var init_database = __esm({
|
|
|
2936
3048
|
|
|
2937
3049
|
// src/lib/keychain.ts
|
|
2938
3050
|
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
|
|
2939
|
-
import { existsSync as
|
|
2940
|
-
import
|
|
3051
|
+
import { existsSync as existsSync7 } from "fs";
|
|
3052
|
+
import path7 from "path";
|
|
2941
3053
|
import os5 from "os";
|
|
2942
3054
|
function getKeyDir() {
|
|
2943
|
-
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ??
|
|
3055
|
+
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path7.join(os5.homedir(), ".exe-os");
|
|
2944
3056
|
}
|
|
2945
3057
|
function getKeyPath() {
|
|
2946
|
-
return
|
|
3058
|
+
return path7.join(getKeyDir(), "master.key");
|
|
2947
3059
|
}
|
|
2948
3060
|
async function tryKeytar() {
|
|
2949
3061
|
try {
|
|
@@ -2964,7 +3076,7 @@ async function getMasterKey() {
|
|
|
2964
3076
|
}
|
|
2965
3077
|
}
|
|
2966
3078
|
const keyPath = getKeyPath();
|
|
2967
|
-
if (!
|
|
3079
|
+
if (!existsSync7(keyPath)) {
|
|
2968
3080
|
process.stderr.write(
|
|
2969
3081
|
`[keychain] Key not found at ${keyPath} (HOME=${os5.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
|
|
2970
3082
|
`
|
|
@@ -3051,6 +3163,7 @@ var shard_manager_exports = {};
|
|
|
3051
3163
|
__export(shard_manager_exports, {
|
|
3052
3164
|
disposeShards: () => disposeShards,
|
|
3053
3165
|
ensureShardSchema: () => ensureShardSchema,
|
|
3166
|
+
getOpenShardCount: () => getOpenShardCount,
|
|
3054
3167
|
getReadyShardClient: () => getReadyShardClient,
|
|
3055
3168
|
getShardClient: () => getShardClient,
|
|
3056
3169
|
getShardsDir: () => getShardsDir,
|
|
@@ -3059,15 +3172,18 @@ __export(shard_manager_exports, {
|
|
|
3059
3172
|
listShards: () => listShards,
|
|
3060
3173
|
shardExists: () => shardExists
|
|
3061
3174
|
});
|
|
3062
|
-
import
|
|
3063
|
-
import { existsSync as
|
|
3175
|
+
import path8 from "path";
|
|
3176
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync2, readdirSync } from "fs";
|
|
3064
3177
|
import { createClient as createClient2 } from "@libsql/client";
|
|
3065
3178
|
function initShardManager(encryptionKey) {
|
|
3066
3179
|
_encryptionKey = encryptionKey;
|
|
3067
|
-
if (!
|
|
3180
|
+
if (!existsSync8(SHARDS_DIR)) {
|
|
3068
3181
|
mkdirSync2(SHARDS_DIR, { recursive: true });
|
|
3069
3182
|
}
|
|
3070
3183
|
_shardingEnabled = true;
|
|
3184
|
+
if (_evictionTimer) clearInterval(_evictionTimer);
|
|
3185
|
+
_evictionTimer = setInterval(evictIdleShards, EVICTION_INTERVAL_MS);
|
|
3186
|
+
_evictionTimer.unref();
|
|
3071
3187
|
}
|
|
3072
3188
|
function isShardingEnabled() {
|
|
3073
3189
|
return _shardingEnabled;
|
|
@@ -3084,21 +3200,28 @@ function getShardClient(projectName) {
|
|
|
3084
3200
|
throw new Error(`Invalid project name for shard: "${projectName}"`);
|
|
3085
3201
|
}
|
|
3086
3202
|
const cached = _shards.get(safeName);
|
|
3087
|
-
if (cached)
|
|
3088
|
-
|
|
3203
|
+
if (cached) {
|
|
3204
|
+
_shardLastAccess.set(safeName, Date.now());
|
|
3205
|
+
return cached;
|
|
3206
|
+
}
|
|
3207
|
+
while (_shards.size >= MAX_OPEN_SHARDS) {
|
|
3208
|
+
evictLRU();
|
|
3209
|
+
}
|
|
3210
|
+
const dbPath = path8.join(SHARDS_DIR, `${safeName}.db`);
|
|
3089
3211
|
const client = createClient2({
|
|
3090
3212
|
url: `file:${dbPath}`,
|
|
3091
3213
|
encryptionKey: _encryptionKey
|
|
3092
3214
|
});
|
|
3093
3215
|
_shards.set(safeName, client);
|
|
3216
|
+
_shardLastAccess.set(safeName, Date.now());
|
|
3094
3217
|
return client;
|
|
3095
3218
|
}
|
|
3096
3219
|
function shardExists(projectName) {
|
|
3097
3220
|
const safeName = projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
3098
|
-
return
|
|
3221
|
+
return existsSync8(path8.join(SHARDS_DIR, `${safeName}.db`));
|
|
3099
3222
|
}
|
|
3100
3223
|
function listShards() {
|
|
3101
|
-
if (!
|
|
3224
|
+
if (!existsSync8(SHARDS_DIR)) return [];
|
|
3102
3225
|
return readdirSync(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
|
|
3103
3226
|
}
|
|
3104
3227
|
async function ensureShardSchema(client) {
|
|
@@ -3150,6 +3273,8 @@ async function ensureShardSchema(client) {
|
|
|
3150
3273
|
for (const col of [
|
|
3151
3274
|
"ALTER TABLE memories ADD COLUMN task_id TEXT",
|
|
3152
3275
|
"ALTER TABLE memories ADD COLUMN consolidated INTEGER NOT NULL DEFAULT 0",
|
|
3276
|
+
"ALTER TABLE memories ADD COLUMN author_device_id TEXT",
|
|
3277
|
+
"ALTER TABLE memories ADD COLUMN scope TEXT NOT NULL DEFAULT 'business'",
|
|
3153
3278
|
"ALTER TABLE memories ADD COLUMN importance INTEGER DEFAULT 5",
|
|
3154
3279
|
"ALTER TABLE memories ADD COLUMN status TEXT DEFAULT 'active'",
|
|
3155
3280
|
"ALTER TABLE memories ADD COLUMN wiki_synced INTEGER DEFAULT 0",
|
|
@@ -3287,21 +3412,69 @@ async function getReadyShardClient(projectName) {
|
|
|
3287
3412
|
await ensureShardSchema(client);
|
|
3288
3413
|
return client;
|
|
3289
3414
|
}
|
|
3415
|
+
function evictLRU() {
|
|
3416
|
+
let oldest = null;
|
|
3417
|
+
let oldestTime = Infinity;
|
|
3418
|
+
for (const [name, time] of _shardLastAccess) {
|
|
3419
|
+
if (time < oldestTime) {
|
|
3420
|
+
oldestTime = time;
|
|
3421
|
+
oldest = name;
|
|
3422
|
+
}
|
|
3423
|
+
}
|
|
3424
|
+
if (oldest) {
|
|
3425
|
+
const client = _shards.get(oldest);
|
|
3426
|
+
if (client) {
|
|
3427
|
+
client.close();
|
|
3428
|
+
}
|
|
3429
|
+
_shards.delete(oldest);
|
|
3430
|
+
_shardLastAccess.delete(oldest);
|
|
3431
|
+
}
|
|
3432
|
+
}
|
|
3433
|
+
function evictIdleShards() {
|
|
3434
|
+
const now = Date.now();
|
|
3435
|
+
const toEvict = [];
|
|
3436
|
+
for (const [name, lastAccess] of _shardLastAccess) {
|
|
3437
|
+
if (now - lastAccess > SHARD_IDLE_MS) {
|
|
3438
|
+
toEvict.push(name);
|
|
3439
|
+
}
|
|
3440
|
+
}
|
|
3441
|
+
for (const name of toEvict) {
|
|
3442
|
+
const client = _shards.get(name);
|
|
3443
|
+
if (client) {
|
|
3444
|
+
client.close();
|
|
3445
|
+
}
|
|
3446
|
+
_shards.delete(name);
|
|
3447
|
+
_shardLastAccess.delete(name);
|
|
3448
|
+
}
|
|
3449
|
+
}
|
|
3450
|
+
function getOpenShardCount() {
|
|
3451
|
+
return _shards.size;
|
|
3452
|
+
}
|
|
3290
3453
|
function disposeShards() {
|
|
3454
|
+
if (_evictionTimer) {
|
|
3455
|
+
clearInterval(_evictionTimer);
|
|
3456
|
+
_evictionTimer = null;
|
|
3457
|
+
}
|
|
3291
3458
|
for (const [, client] of _shards) {
|
|
3292
3459
|
client.close();
|
|
3293
3460
|
}
|
|
3294
3461
|
_shards.clear();
|
|
3462
|
+
_shardLastAccess.clear();
|
|
3295
3463
|
_shardingEnabled = false;
|
|
3296
3464
|
_encryptionKey = null;
|
|
3297
3465
|
}
|
|
3298
|
-
var SHARDS_DIR, _shards, _encryptionKey, _shardingEnabled;
|
|
3466
|
+
var SHARDS_DIR, SHARD_IDLE_MS, MAX_OPEN_SHARDS, EVICTION_INTERVAL_MS, _shards, _shardLastAccess, _evictionTimer, _encryptionKey, _shardingEnabled;
|
|
3299
3467
|
var init_shard_manager = __esm({
|
|
3300
3468
|
"src/lib/shard-manager.ts"() {
|
|
3301
3469
|
"use strict";
|
|
3302
3470
|
init_config();
|
|
3303
|
-
SHARDS_DIR =
|
|
3471
|
+
SHARDS_DIR = path8.join(EXE_AI_DIR, "shards");
|
|
3472
|
+
SHARD_IDLE_MS = 5 * 60 * 1e3;
|
|
3473
|
+
MAX_OPEN_SHARDS = 10;
|
|
3474
|
+
EVICTION_INTERVAL_MS = 60 * 1e3;
|
|
3304
3475
|
_shards = /* @__PURE__ */ new Map();
|
|
3476
|
+
_shardLastAccess = /* @__PURE__ */ new Map();
|
|
3477
|
+
_evictionTimer = null;
|
|
3305
3478
|
_encryptionKey = null;
|
|
3306
3479
|
_shardingEnabled = false;
|
|
3307
3480
|
}
|
|
@@ -4163,8 +4336,8 @@ __export(reranker_exports, {
|
|
|
4163
4336
|
rerankWithContext: () => rerankWithContext,
|
|
4164
4337
|
rerankWithScores: () => rerankWithScores
|
|
4165
4338
|
});
|
|
4166
|
-
import
|
|
4167
|
-
import { existsSync as
|
|
4339
|
+
import path9 from "path";
|
|
4340
|
+
import { existsSync as existsSync9 } from "fs";
|
|
4168
4341
|
function resetIdleTimer() {
|
|
4169
4342
|
if (_idleTimer) clearTimeout(_idleTimer);
|
|
4170
4343
|
_idleTimer = setTimeout(() => {
|
|
@@ -4175,18 +4348,18 @@ function resetIdleTimer() {
|
|
|
4175
4348
|
}
|
|
4176
4349
|
}
|
|
4177
4350
|
function isRerankerAvailable() {
|
|
4178
|
-
return
|
|
4351
|
+
return existsSync9(path9.join(MODELS_DIR, RERANKER_MODEL_FILE));
|
|
4179
4352
|
}
|
|
4180
4353
|
function getRerankerModelPath() {
|
|
4181
|
-
return
|
|
4354
|
+
return path9.join(MODELS_DIR, RERANKER_MODEL_FILE);
|
|
4182
4355
|
}
|
|
4183
4356
|
async function ensureLoaded() {
|
|
4184
4357
|
if (_rerankerContext) {
|
|
4185
4358
|
resetIdleTimer();
|
|
4186
4359
|
return;
|
|
4187
4360
|
}
|
|
4188
|
-
const modelPath =
|
|
4189
|
-
if (!
|
|
4361
|
+
const modelPath = path9.join(MODELS_DIR, RERANKER_MODEL_FILE);
|
|
4362
|
+
if (!existsSync9(modelPath)) {
|
|
4190
4363
|
throw new Error(
|
|
4191
4364
|
`Reranker model not found at ${modelPath}. Run /exe-setup to download it.`
|
|
4192
4365
|
);
|
|
@@ -4319,10 +4492,10 @@ async function disposeEmbedder() {
|
|
|
4319
4492
|
async function embedDirect(text) {
|
|
4320
4493
|
const llamaCpp = await import("node-llama-cpp");
|
|
4321
4494
|
const { MODELS_DIR: MODELS_DIR2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
4322
|
-
const { existsSync:
|
|
4323
|
-
const
|
|
4324
|
-
const modelPath =
|
|
4325
|
-
if (!
|
|
4495
|
+
const { existsSync: existsSync16 } = await import("fs");
|
|
4496
|
+
const path19 = await import("path");
|
|
4497
|
+
const modelPath = path19.join(MODELS_DIR2, "jina-embeddings-v5-small-q4_k_m.gguf");
|
|
4498
|
+
if (!existsSync16(modelPath)) {
|
|
4326
4499
|
throw new Error(`Embedding model not found at ${modelPath}. Run '/exe-setup' to download it.`);
|
|
4327
4500
|
}
|
|
4328
4501
|
const llama = await llamaCpp.getLlama();
|
|
@@ -4357,7 +4530,7 @@ __export(project_name_exports, {
|
|
|
4357
4530
|
getProjectName: () => getProjectName
|
|
4358
4531
|
});
|
|
4359
4532
|
import { execSync as execSync2 } from "child_process";
|
|
4360
|
-
import
|
|
4533
|
+
import path10 from "path";
|
|
4361
4534
|
function getProjectName(cwd) {
|
|
4362
4535
|
const dir = cwd ?? process.cwd();
|
|
4363
4536
|
if (_cached && _cachedCwd === dir) return _cached;
|
|
@@ -4370,7 +4543,7 @@ function getProjectName(cwd) {
|
|
|
4370
4543
|
timeout: 2e3,
|
|
4371
4544
|
stdio: ["pipe", "pipe", "pipe"]
|
|
4372
4545
|
}).trim();
|
|
4373
|
-
repoRoot =
|
|
4546
|
+
repoRoot = path10.dirname(gitCommonDir);
|
|
4374
4547
|
} catch {
|
|
4375
4548
|
repoRoot = execSync2("git rev-parse --show-toplevel", {
|
|
4376
4549
|
cwd: dir,
|
|
@@ -4379,11 +4552,11 @@ function getProjectName(cwd) {
|
|
|
4379
4552
|
stdio: ["pipe", "pipe", "pipe"]
|
|
4380
4553
|
}).trim();
|
|
4381
4554
|
}
|
|
4382
|
-
_cached =
|
|
4555
|
+
_cached = path10.basename(repoRoot);
|
|
4383
4556
|
_cachedCwd = dir;
|
|
4384
4557
|
return _cached;
|
|
4385
4558
|
} catch {
|
|
4386
|
-
_cached =
|
|
4559
|
+
_cached = path10.basename(dir);
|
|
4387
4560
|
_cachedCwd = dir;
|
|
4388
4561
|
return _cached;
|
|
4389
4562
|
}
|
|
@@ -4407,9 +4580,9 @@ __export(file_grep_exports, {
|
|
|
4407
4580
|
grepProjectFiles: () => grepProjectFiles
|
|
4408
4581
|
});
|
|
4409
4582
|
import { execSync as execSync3 } from "child_process";
|
|
4410
|
-
import { readFileSync as
|
|
4411
|
-
import
|
|
4412
|
-
import
|
|
4583
|
+
import { readFileSync as readFileSync6, readdirSync as readdirSync2, statSync as statSync2, existsSync as existsSync10 } from "fs";
|
|
4584
|
+
import path11 from "path";
|
|
4585
|
+
import crypto2 from "crypto";
|
|
4413
4586
|
function hasRipgrep() {
|
|
4414
4587
|
if (_hasRg === null) {
|
|
4415
4588
|
try {
|
|
@@ -4442,13 +4615,13 @@ async function grepProjectFiles(query, projectRoot, options) {
|
|
|
4442
4615
|
const chunkCtx = getChunkContext(hit.filePath, hit.lineNumber);
|
|
4443
4616
|
const prefix = chunkCtx ? `[file: ${hit.filePath}:${hit.lineNumber} in ${chunkCtx}]` : `[file: ${hit.filePath}:${hit.lineNumber}]`;
|
|
4444
4617
|
return {
|
|
4445
|
-
id:
|
|
4618
|
+
id: crypto2.createHash("sha256").update(`${hit.filePath}:${hit.lineNumber}`).digest("hex").slice(0, 36),
|
|
4446
4619
|
agent_id: "project",
|
|
4447
4620
|
agent_role: "file",
|
|
4448
4621
|
session_id: "file-grep",
|
|
4449
4622
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4450
4623
|
tool_name: "file_grep",
|
|
4451
|
-
project_name:
|
|
4624
|
+
project_name: path11.basename(projectRoot),
|
|
4452
4625
|
has_error: false,
|
|
4453
4626
|
raw_text: `${prefix} ${buildSnippet(hit, projectRoot)}`,
|
|
4454
4627
|
vector: null,
|
|
@@ -4460,7 +4633,7 @@ function getChunkContext(filePath, lineNumber) {
|
|
|
4460
4633
|
try {
|
|
4461
4634
|
const ext = filePath.split(".").pop()?.toLowerCase();
|
|
4462
4635
|
if (ext !== "ts" && ext !== "tsx" && ext !== "js" && ext !== "jsx") return "";
|
|
4463
|
-
const source =
|
|
4636
|
+
const source = readFileSync6(filePath, "utf8");
|
|
4464
4637
|
const lines = source.split("\n");
|
|
4465
4638
|
for (let i = Math.min(lineNumber - 1, lines.length - 1); i >= 0; i--) {
|
|
4466
4639
|
const line = lines[i];
|
|
@@ -4522,11 +4695,11 @@ function grepWithNodeFs(pattern, projectRoot, patterns) {
|
|
|
4522
4695
|
const files = collectFiles(projectRoot, patterns ?? DEFAULT_PATTERNS);
|
|
4523
4696
|
const hits = [];
|
|
4524
4697
|
for (const filePath of files.slice(0, MAX_FILES)) {
|
|
4525
|
-
const absPath =
|
|
4698
|
+
const absPath = path11.join(projectRoot, filePath);
|
|
4526
4699
|
try {
|
|
4527
4700
|
const stat = statSync2(absPath);
|
|
4528
4701
|
if (stat.size > MAX_FILE_SIZE) continue;
|
|
4529
|
-
const content =
|
|
4702
|
+
const content = readFileSync6(absPath, "utf8");
|
|
4530
4703
|
const lines = content.split("\n");
|
|
4531
4704
|
const matches = content.match(regex);
|
|
4532
4705
|
if (!matches || matches.length === 0) continue;
|
|
@@ -4549,15 +4722,15 @@ function collectFiles(root, patterns) {
|
|
|
4549
4722
|
const files = [];
|
|
4550
4723
|
function walk(dir, relative) {
|
|
4551
4724
|
if (files.length >= MAX_FILES) return;
|
|
4552
|
-
const basename =
|
|
4725
|
+
const basename = path11.basename(dir);
|
|
4553
4726
|
if (EXCLUDE_DIRS.includes(basename)) return;
|
|
4554
4727
|
try {
|
|
4555
4728
|
const entries = readdirSync2(dir, { withFileTypes: true });
|
|
4556
4729
|
for (const entry of entries) {
|
|
4557
4730
|
if (files.length >= MAX_FILES) return;
|
|
4558
|
-
const rel =
|
|
4731
|
+
const rel = path11.join(relative, entry.name);
|
|
4559
4732
|
if (entry.isDirectory()) {
|
|
4560
|
-
walk(
|
|
4733
|
+
walk(path11.join(dir, entry.name), rel);
|
|
4561
4734
|
} else if (entry.isFile()) {
|
|
4562
4735
|
for (const pat of patterns) {
|
|
4563
4736
|
if (matchGlob(rel, pat)) {
|
|
@@ -4589,7 +4762,7 @@ function matchGlob(filePath, pattern) {
|
|
|
4589
4762
|
if (slashIdx !== -1) {
|
|
4590
4763
|
const dir = pattern.slice(0, slashIdx);
|
|
4591
4764
|
const ext2 = pattern.slice(slashIdx + 1).replace("*", "");
|
|
4592
|
-
const fileDir =
|
|
4765
|
+
const fileDir = path11.dirname(filePath);
|
|
4593
4766
|
return fileDir === dir && filePath.endsWith(ext2);
|
|
4594
4767
|
}
|
|
4595
4768
|
const ext = pattern.replace("*", "");
|
|
@@ -4597,9 +4770,9 @@ function matchGlob(filePath, pattern) {
|
|
|
4597
4770
|
}
|
|
4598
4771
|
function buildSnippet(hit, projectRoot) {
|
|
4599
4772
|
try {
|
|
4600
|
-
const absPath =
|
|
4601
|
-
if (!
|
|
4602
|
-
const lines =
|
|
4773
|
+
const absPath = path11.join(projectRoot, hit.filePath);
|
|
4774
|
+
if (!existsSync10(absPath)) return hit.matchLine;
|
|
4775
|
+
const lines = readFileSync6(absPath, "utf8").split("\n");
|
|
4603
4776
|
const start = Math.max(0, hit.lineNumber - 3);
|
|
4604
4777
|
const end = Math.min(lines.length, hit.lineNumber + 2);
|
|
4605
4778
|
return lines.slice(start, end).join("\n").slice(0, 500);
|
|
@@ -5815,9 +5988,9 @@ var init_session_key = __esm({
|
|
|
5815
5988
|
});
|
|
5816
5989
|
|
|
5817
5990
|
// src/lib/active-agent.ts
|
|
5818
|
-
import { readFileSync as
|
|
5991
|
+
import { readFileSync as readFileSync7, writeFileSync as writeFileSync4, mkdirSync as mkdirSync3, unlinkSync as unlinkSync3, readdirSync as readdirSync3 } from "fs";
|
|
5819
5992
|
import { execSync as execSync5 } from "child_process";
|
|
5820
|
-
import
|
|
5993
|
+
import path12 from "path";
|
|
5821
5994
|
function isNameWithOptionalInstance(candidate, baseName) {
|
|
5822
5995
|
if (candidate === baseName) return true;
|
|
5823
5996
|
if (!candidate.startsWith(baseName)) return false;
|
|
@@ -5861,12 +6034,12 @@ function resolveActiveAgentFromTmuxSession(sessionName) {
|
|
|
5861
6034
|
return null;
|
|
5862
6035
|
}
|
|
5863
6036
|
function getMarkerPath() {
|
|
5864
|
-
return
|
|
6037
|
+
return path12.join(CACHE_DIR, `active-agent-${getSessionKey()}.json`);
|
|
5865
6038
|
}
|
|
5866
6039
|
function writeActiveAgent(agentId, agentRole) {
|
|
5867
6040
|
try {
|
|
5868
6041
|
mkdirSync3(CACHE_DIR, { recursive: true });
|
|
5869
|
-
|
|
6042
|
+
writeFileSync4(
|
|
5870
6043
|
getMarkerPath(),
|
|
5871
6044
|
JSON.stringify({ agentId, agentRole, startedAt: (/* @__PURE__ */ new Date()).toISOString() })
|
|
5872
6045
|
);
|
|
@@ -5882,7 +6055,7 @@ function clearActiveAgent() {
|
|
|
5882
6055
|
function getActiveAgent() {
|
|
5883
6056
|
try {
|
|
5884
6057
|
const markerPath = getMarkerPath();
|
|
5885
|
-
const raw =
|
|
6058
|
+
const raw = readFileSync7(markerPath, "utf8");
|
|
5886
6059
|
const data = JSON.parse(raw);
|
|
5887
6060
|
if (data.agentId) {
|
|
5888
6061
|
if (data.startedAt) {
|
|
@@ -5930,14 +6103,14 @@ function getAllActiveAgents() {
|
|
|
5930
6103
|
const key = file.slice("active-agent-".length, -".json".length);
|
|
5931
6104
|
if (key === "undefined") continue;
|
|
5932
6105
|
try {
|
|
5933
|
-
const raw =
|
|
6106
|
+
const raw = readFileSync7(path12.join(CACHE_DIR, file), "utf8");
|
|
5934
6107
|
const data = JSON.parse(raw);
|
|
5935
6108
|
if (!data.agentId) continue;
|
|
5936
6109
|
if (data.startedAt) {
|
|
5937
6110
|
const age = Date.now() - new Date(data.startedAt).getTime();
|
|
5938
6111
|
if (age > STALE_MS) {
|
|
5939
6112
|
try {
|
|
5940
|
-
unlinkSync3(
|
|
6113
|
+
unlinkSync3(path12.join(CACHE_DIR, file));
|
|
5941
6114
|
} catch {
|
|
5942
6115
|
}
|
|
5943
6116
|
continue;
|
|
@@ -5960,11 +6133,11 @@ function getAllActiveAgents() {
|
|
|
5960
6133
|
function cleanupSessionMarkers() {
|
|
5961
6134
|
const key = getSessionKey();
|
|
5962
6135
|
try {
|
|
5963
|
-
unlinkSync3(
|
|
6136
|
+
unlinkSync3(path12.join(CACHE_DIR, `active-agent-${key}.json`));
|
|
5964
6137
|
} catch {
|
|
5965
6138
|
}
|
|
5966
6139
|
try {
|
|
5967
|
-
unlinkSync3(
|
|
6140
|
+
unlinkSync3(path12.join(CACHE_DIR, "active-agent-undefined.json"));
|
|
5968
6141
|
} catch {
|
|
5969
6142
|
}
|
|
5970
6143
|
}
|
|
@@ -5975,7 +6148,7 @@ var init_active_agent = __esm({
|
|
|
5975
6148
|
init_config();
|
|
5976
6149
|
init_session_key();
|
|
5977
6150
|
init_employees();
|
|
5978
|
-
CACHE_DIR =
|
|
6151
|
+
CACHE_DIR = path12.join(EXE_AI_DIR, "session-cache");
|
|
5979
6152
|
STALE_MS = 24 * 60 * 60 * 1e3;
|
|
5980
6153
|
}
|
|
5981
6154
|
});
|
|
@@ -5998,13 +6171,13 @@ var init_active_agent2 = __esm({
|
|
|
5998
6171
|
});
|
|
5999
6172
|
|
|
6000
6173
|
// src/lib/session-registry.ts
|
|
6001
|
-
import
|
|
6174
|
+
import path13 from "path";
|
|
6002
6175
|
import os6 from "os";
|
|
6003
6176
|
var REGISTRY_PATH;
|
|
6004
6177
|
var init_session_registry = __esm({
|
|
6005
6178
|
"src/lib/session-registry.ts"() {
|
|
6006
6179
|
"use strict";
|
|
6007
|
-
REGISTRY_PATH =
|
|
6180
|
+
REGISTRY_PATH = path13.join(os6.homedir(), ".exe-os", "session-registry.json");
|
|
6008
6181
|
}
|
|
6009
6182
|
});
|
|
6010
6183
|
|
|
@@ -6145,38 +6318,41 @@ var init_provider_table = __esm({
|
|
|
6145
6318
|
});
|
|
6146
6319
|
|
|
6147
6320
|
// src/lib/intercom-queue.ts
|
|
6148
|
-
import { readFileSync as
|
|
6149
|
-
import
|
|
6321
|
+
import { readFileSync as readFileSync8, writeFileSync as writeFileSync5, renameSync as renameSync3, existsSync as existsSync11, mkdirSync as mkdirSync4 } from "fs";
|
|
6322
|
+
import path14 from "path";
|
|
6150
6323
|
import os7 from "os";
|
|
6151
6324
|
var QUEUE_PATH, TTL_MS, INTERCOM_LOG;
|
|
6152
6325
|
var init_intercom_queue = __esm({
|
|
6153
6326
|
"src/lib/intercom-queue.ts"() {
|
|
6154
6327
|
"use strict";
|
|
6155
|
-
QUEUE_PATH =
|
|
6328
|
+
QUEUE_PATH = path14.join(os7.homedir(), ".exe-os", "intercom-queue.json");
|
|
6156
6329
|
TTL_MS = 60 * 60 * 1e3;
|
|
6157
|
-
INTERCOM_LOG =
|
|
6330
|
+
INTERCOM_LOG = path14.join(os7.homedir(), ".exe-os", "intercom.log");
|
|
6158
6331
|
}
|
|
6159
6332
|
});
|
|
6160
6333
|
|
|
6161
6334
|
// src/lib/license.ts
|
|
6162
|
-
import { readFileSync as
|
|
6335
|
+
import { readFileSync as readFileSync9, writeFileSync as writeFileSync6, existsSync as existsSync12, mkdirSync as mkdirSync5 } from "fs";
|
|
6163
6336
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
6164
|
-
import
|
|
6337
|
+
import { createRequire as createRequire2 } from "module";
|
|
6338
|
+
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
6339
|
+
import os8 from "os";
|
|
6340
|
+
import path15 from "path";
|
|
6165
6341
|
import { jwtVerify, importSPKI } from "jose";
|
|
6166
6342
|
var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH;
|
|
6167
6343
|
var init_license = __esm({
|
|
6168
6344
|
"src/lib/license.ts"() {
|
|
6169
6345
|
"use strict";
|
|
6170
6346
|
init_config();
|
|
6171
|
-
LICENSE_PATH =
|
|
6172
|
-
CACHE_PATH =
|
|
6173
|
-
DEVICE_ID_PATH =
|
|
6347
|
+
LICENSE_PATH = path15.join(EXE_AI_DIR, "license.key");
|
|
6348
|
+
CACHE_PATH = path15.join(EXE_AI_DIR, "license-cache.json");
|
|
6349
|
+
DEVICE_ID_PATH = path15.join(EXE_AI_DIR, "device-id");
|
|
6174
6350
|
}
|
|
6175
6351
|
});
|
|
6176
6352
|
|
|
6177
6353
|
// src/lib/plan-limits.ts
|
|
6178
|
-
import { readFileSync as
|
|
6179
|
-
import
|
|
6354
|
+
import { readFileSync as readFileSync10, existsSync as existsSync13 } from "fs";
|
|
6355
|
+
import path16 from "path";
|
|
6180
6356
|
var CACHE_PATH2;
|
|
6181
6357
|
var init_plan_limits = __esm({
|
|
6182
6358
|
"src/lib/plan-limits.ts"() {
|
|
@@ -6185,14 +6361,14 @@ var init_plan_limits = __esm({
|
|
|
6185
6361
|
init_employees();
|
|
6186
6362
|
init_license();
|
|
6187
6363
|
init_config();
|
|
6188
|
-
CACHE_PATH2 =
|
|
6364
|
+
CACHE_PATH2 = path16.join(EXE_AI_DIR, "license-cache.json");
|
|
6189
6365
|
}
|
|
6190
6366
|
});
|
|
6191
6367
|
|
|
6192
6368
|
// src/lib/tmux-routing.ts
|
|
6193
|
-
import { readFileSync as
|
|
6194
|
-
import
|
|
6195
|
-
import
|
|
6369
|
+
import { readFileSync as readFileSync11, writeFileSync as writeFileSync7, mkdirSync as mkdirSync6, existsSync as existsSync14, appendFileSync, readdirSync as readdirSync4 } from "fs";
|
|
6370
|
+
import path17 from "path";
|
|
6371
|
+
import os9 from "os";
|
|
6196
6372
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
6197
6373
|
function getMySession() {
|
|
6198
6374
|
return getTransport().getMySession();
|
|
@@ -6205,7 +6381,7 @@ function extractRootExe(name) {
|
|
|
6205
6381
|
}
|
|
6206
6382
|
function getParentExe(sessionKey) {
|
|
6207
6383
|
try {
|
|
6208
|
-
const data = JSON.parse(
|
|
6384
|
+
const data = JSON.parse(readFileSync11(path17.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
|
|
6209
6385
|
return data.parentExe || null;
|
|
6210
6386
|
} catch {
|
|
6211
6387
|
return null;
|
|
@@ -6248,10 +6424,10 @@ var init_tmux_routing = __esm({
|
|
|
6248
6424
|
init_intercom_queue();
|
|
6249
6425
|
init_plan_limits();
|
|
6250
6426
|
init_employees();
|
|
6251
|
-
SPAWN_LOCK_DIR =
|
|
6252
|
-
SESSION_CACHE =
|
|
6253
|
-
INTERCOM_LOG2 =
|
|
6254
|
-
DEBOUNCE_FILE =
|
|
6427
|
+
SPAWN_LOCK_DIR = path17.join(os9.homedir(), ".exe-os", "spawn-locks");
|
|
6428
|
+
SESSION_CACHE = path17.join(os9.homedir(), ".exe-os", "session-cache");
|
|
6429
|
+
INTERCOM_LOG2 = path17.join(os9.homedir(), ".exe-os", "intercom.log");
|
|
6430
|
+
DEBOUNCE_FILE = path17.join(SESSION_CACHE, "intercom-debounce.json");
|
|
6255
6431
|
DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
|
|
6256
6432
|
}
|
|
6257
6433
|
});
|
|
@@ -6260,7 +6436,8 @@ var init_tmux_routing = __esm({
|
|
|
6260
6436
|
var task_scope_exports = {};
|
|
6261
6437
|
__export(task_scope_exports, {
|
|
6262
6438
|
getCurrentSessionScope: () => getCurrentSessionScope,
|
|
6263
|
-
sessionScopeFilter: () => sessionScopeFilter
|
|
6439
|
+
sessionScopeFilter: () => sessionScopeFilter,
|
|
6440
|
+
strictSessionScopeFilter: () => strictSessionScopeFilter
|
|
6264
6441
|
});
|
|
6265
6442
|
function getCurrentSessionScope() {
|
|
6266
6443
|
try {
|
|
@@ -6278,6 +6455,15 @@ function sessionScopeFilter(sessionScope, tableAlias) {
|
|
|
6278
6455
|
args: [scope]
|
|
6279
6456
|
};
|
|
6280
6457
|
}
|
|
6458
|
+
function strictSessionScopeFilter(sessionScope, tableAlias) {
|
|
6459
|
+
const scope = sessionScope !== void 0 ? sessionScope : getCurrentSessionScope();
|
|
6460
|
+
if (!scope) return { sql: "", args: [] };
|
|
6461
|
+
const col = tableAlias ? `${tableAlias}.session_scope` : "session_scope";
|
|
6462
|
+
return {
|
|
6463
|
+
sql: ` AND ${col} = ?`,
|
|
6464
|
+
args: [scope]
|
|
6465
|
+
};
|
|
6466
|
+
}
|
|
6281
6467
|
var init_task_scope = __esm({
|
|
6282
6468
|
"src/lib/task-scope.ts"() {
|
|
6283
6469
|
"use strict";
|
|
@@ -6287,8 +6473,8 @@ var init_task_scope = __esm({
|
|
|
6287
6473
|
|
|
6288
6474
|
// src/adapters/claude/hooks/session-start.ts
|
|
6289
6475
|
init_config();
|
|
6290
|
-
import
|
|
6291
|
-
import { unlinkSync as unlinkSync4, existsSync as
|
|
6476
|
+
import path18 from "path";
|
|
6477
|
+
import { unlinkSync as unlinkSync4, existsSync as existsSync15, readFileSync as readFileSync12 } from "fs";
|
|
6292
6478
|
if (!process.env.AGENT_ID) {
|
|
6293
6479
|
process.env.AGENT_ID = "default";
|
|
6294
6480
|
process.env.AGENT_ROLE = "employee";
|
|
@@ -6321,8 +6507,8 @@ process.stdin.on("end", async () => {
|
|
|
6321
6507
|
const source = data.source ?? "startup";
|
|
6322
6508
|
if (source === "startup") {
|
|
6323
6509
|
try {
|
|
6324
|
-
const undefinedPath =
|
|
6325
|
-
process.env.EXE_OS_DIR ??
|
|
6510
|
+
const undefinedPath = path18.join(
|
|
6511
|
+
process.env.EXE_OS_DIR ?? path18.join(process.env.HOME ?? "", ".exe-os"),
|
|
6326
6512
|
"session-cache",
|
|
6327
6513
|
"active-agent-undefined.json"
|
|
6328
6514
|
);
|
|
@@ -6335,13 +6521,13 @@ process.stdin.on("end", async () => {
|
|
|
6335
6521
|
const agentId = agent.agentId;
|
|
6336
6522
|
if (agentId !== "default") {
|
|
6337
6523
|
try {
|
|
6338
|
-
const cacheDir =
|
|
6339
|
-
process.env.EXE_OS_DIR ??
|
|
6524
|
+
const cacheDir = path18.join(
|
|
6525
|
+
process.env.EXE_OS_DIR ?? path18.join(process.env.HOME ?? "", ".exe-os"),
|
|
6340
6526
|
"session-cache"
|
|
6341
6527
|
);
|
|
6342
|
-
const markerPath =
|
|
6343
|
-
if (
|
|
6344
|
-
const marker = JSON.parse(
|
|
6528
|
+
const markerPath = path18.join(cacheDir, `current-task-${agentId}.json`);
|
|
6529
|
+
if (existsSync15(markerPath)) {
|
|
6530
|
+
const marker = JSON.parse(readFileSync12(markerPath, "utf-8"));
|
|
6345
6531
|
if (marker.taskId) {
|
|
6346
6532
|
const client = getClient2();
|
|
6347
6533
|
const result = await client.execute({
|