@askexenow/exe-os 0.9.12 → 0.9.13
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 +22 -1
- package/dist/bin/backfill-responses.js +22 -1
- package/dist/bin/backfill-vectors.js +22 -1
- package/dist/bin/cleanup-stale-review-tasks.js +22 -1
- package/dist/bin/cli.js +22 -1
- package/dist/bin/exe-assign.js +22 -1
- package/dist/bin/exe-boot.js +22 -1
- package/dist/bin/exe-dispatch.js +22 -1
- package/dist/bin/exe-doctor.js +22 -1
- package/dist/bin/exe-export-behaviors.js +22 -1
- package/dist/bin/exe-forget.js +22 -1
- package/dist/bin/exe-gateway.js +22 -1
- package/dist/bin/exe-heartbeat.js +22 -1
- package/dist/bin/exe-kill.js +22 -1
- package/dist/bin/exe-launch-agent.js +22 -1
- package/dist/bin/exe-link.js +22 -1
- package/dist/bin/exe-pending-messages.js +22 -1
- package/dist/bin/exe-pending-notifications.js +22 -1
- package/dist/bin/exe-pending-reviews.js +22 -1
- package/dist/bin/exe-rename.js +22 -1
- package/dist/bin/exe-review.js +22 -1
- package/dist/bin/exe-search.js +22 -1
- package/dist/bin/exe-session-cleanup.js +22 -1
- package/dist/bin/exe-start-codex.js +22 -1
- package/dist/bin/exe-start-opencode.js +22 -1
- package/dist/bin/exe-status.js +22 -1
- package/dist/bin/exe-team.js +22 -1
- package/dist/bin/git-sweep.js +22 -1
- package/dist/bin/graph-backfill.js +22 -1
- package/dist/bin/graph-export.js +22 -1
- package/dist/bin/scan-tasks.js +22 -1
- package/dist/bin/setup.js +22 -1
- package/dist/bin/shard-migrate.js +22 -1
- package/dist/bin/wiki-sync.js +22 -1
- package/dist/gateway/index.js +22 -1
- package/dist/hooks/bug-report-worker.js +22 -1
- package/dist/hooks/codex-stop-task-finalizer.js +22 -1
- package/dist/hooks/commit-complete.js +22 -1
- package/dist/hooks/error-recall.js +22 -1
- package/dist/hooks/ingest-worker.js +22 -1
- package/dist/hooks/ingest.js +3345 -232
- package/dist/hooks/instructions-loaded.js +22 -1
- package/dist/hooks/notification.js +22 -1
- package/dist/hooks/post-compact.js +22 -1
- package/dist/hooks/pre-compact.js +22 -1
- package/dist/hooks/pre-tool-use.js +22 -1
- package/dist/hooks/prompt-ingest-worker.js +22 -1
- package/dist/hooks/prompt-submit.js +1700 -1396
- package/dist/hooks/response-ingest-worker.js +22 -1
- package/dist/hooks/session-end.js +345 -187
- package/dist/hooks/session-start.js +304 -15
- package/dist/hooks/stop.js +22 -1
- package/dist/hooks/subagent-stop.js +22 -1
- package/dist/hooks/summary-worker.js +22 -1
- package/dist/index.js +22 -1
- package/dist/lib/cloud-sync.js +22 -1
- package/dist/lib/database.js +22 -1
- package/dist/lib/db.js +22 -1
- package/dist/lib/device-registry.js +22 -1
- package/dist/lib/exe-daemon.js +22 -1
- package/dist/lib/hybrid-search.js +22 -1
- package/dist/lib/schedules.js +22 -1
- package/dist/lib/store.js +22 -1
- package/dist/mcp/server.js +126 -1
- package/dist/runtime/index.js +22 -1
- package/dist/tui/App.js +22 -1
- package/package.json +1 -1
|
@@ -391,13 +391,13 @@ var init_employees = __esm({
|
|
|
391
391
|
});
|
|
392
392
|
|
|
393
393
|
// src/lib/session-registry.ts
|
|
394
|
-
import { readFileSync as
|
|
395
|
-
import
|
|
396
|
-
import
|
|
394
|
+
import { readFileSync as readFileSync5, writeFileSync as writeFileSync4, mkdirSync as mkdirSync4, existsSync as existsSync5 } from "fs";
|
|
395
|
+
import path5 from "path";
|
|
396
|
+
import os4 from "os";
|
|
397
397
|
function registerSession(entry) {
|
|
398
|
-
const dir =
|
|
399
|
-
if (!
|
|
400
|
-
|
|
398
|
+
const dir = path5.dirname(REGISTRY_PATH);
|
|
399
|
+
if (!existsSync5(dir)) {
|
|
400
|
+
mkdirSync4(dir, { recursive: true });
|
|
401
401
|
}
|
|
402
402
|
const sessions = listSessions();
|
|
403
403
|
const idx = sessions.findIndex((s) => s.windowName === entry.windowName);
|
|
@@ -406,11 +406,11 @@ function registerSession(entry) {
|
|
|
406
406
|
} else {
|
|
407
407
|
sessions.push(entry);
|
|
408
408
|
}
|
|
409
|
-
|
|
409
|
+
writeFileSync4(REGISTRY_PATH, JSON.stringify(sessions, null, 2));
|
|
410
410
|
}
|
|
411
411
|
function listSessions() {
|
|
412
412
|
try {
|
|
413
|
-
const raw =
|
|
413
|
+
const raw = readFileSync5(REGISTRY_PATH, "utf8");
|
|
414
414
|
return JSON.parse(raw);
|
|
415
415
|
} catch {
|
|
416
416
|
return [];
|
|
@@ -420,7 +420,7 @@ var REGISTRY_PATH;
|
|
|
420
420
|
var init_session_registry = __esm({
|
|
421
421
|
"src/lib/session-registry.ts"() {
|
|
422
422
|
"use strict";
|
|
423
|
-
REGISTRY_PATH =
|
|
423
|
+
REGISTRY_PATH = path5.join(os4.homedir(), ".exe-os", "session-registry.json");
|
|
424
424
|
}
|
|
425
425
|
});
|
|
426
426
|
|
|
@@ -632,12 +632,12 @@ var init_runtime_table = __esm({
|
|
|
632
632
|
});
|
|
633
633
|
|
|
634
634
|
// src/lib/agent-config.ts
|
|
635
|
-
import { readFileSync as
|
|
636
|
-
import
|
|
635
|
+
import { readFileSync as readFileSync6, writeFileSync as writeFileSync5, existsSync as existsSync6 } from "fs";
|
|
636
|
+
import path6 from "path";
|
|
637
637
|
function loadAgentConfig() {
|
|
638
|
-
if (!
|
|
638
|
+
if (!existsSync6(AGENT_CONFIG_PATH)) return {};
|
|
639
639
|
try {
|
|
640
|
-
return JSON.parse(
|
|
640
|
+
return JSON.parse(readFileSync6(AGENT_CONFIG_PATH, "utf-8"));
|
|
641
641
|
} catch {
|
|
642
642
|
return {};
|
|
643
643
|
}
|
|
@@ -657,7 +657,7 @@ var init_agent_config = __esm({
|
|
|
657
657
|
init_config();
|
|
658
658
|
init_runtime_table();
|
|
659
659
|
init_secure_files();
|
|
660
|
-
AGENT_CONFIG_PATH =
|
|
660
|
+
AGENT_CONFIG_PATH = path6.join(EXE_AI_DIR, "agent-config.json");
|
|
661
661
|
DEFAULT_MODELS = {
|
|
662
662
|
claude: "claude-opus-4",
|
|
663
663
|
codex: RUNTIME_TABLE.codex?.defaultModel ?? "gpt-5.4",
|
|
@@ -675,17 +675,17 @@ __export(intercom_queue_exports, {
|
|
|
675
675
|
queueIntercom: () => queueIntercom,
|
|
676
676
|
readQueue: () => readQueue
|
|
677
677
|
});
|
|
678
|
-
import { readFileSync as
|
|
679
|
-
import
|
|
680
|
-
import
|
|
678
|
+
import { readFileSync as readFileSync7, writeFileSync as writeFileSync6, renameSync as renameSync3, existsSync as existsSync7, mkdirSync as mkdirSync5 } from "fs";
|
|
679
|
+
import path7 from "path";
|
|
680
|
+
import os5 from "os";
|
|
681
681
|
function ensureDir() {
|
|
682
|
-
const dir =
|
|
683
|
-
if (!
|
|
682
|
+
const dir = path7.dirname(QUEUE_PATH);
|
|
683
|
+
if (!existsSync7(dir)) mkdirSync5(dir, { recursive: true });
|
|
684
684
|
}
|
|
685
685
|
function readQueue() {
|
|
686
686
|
try {
|
|
687
|
-
if (!
|
|
688
|
-
return JSON.parse(
|
|
687
|
+
if (!existsSync7(QUEUE_PATH)) return [];
|
|
688
|
+
return JSON.parse(readFileSync7(QUEUE_PATH, "utf8"));
|
|
689
689
|
} catch {
|
|
690
690
|
return [];
|
|
691
691
|
}
|
|
@@ -693,7 +693,7 @@ function readQueue() {
|
|
|
693
693
|
function writeQueue(queue) {
|
|
694
694
|
ensureDir();
|
|
695
695
|
const tmp = `${QUEUE_PATH}.tmp`;
|
|
696
|
-
|
|
696
|
+
writeFileSync6(tmp, JSON.stringify(queue, null, 2));
|
|
697
697
|
renameSync3(tmp, QUEUE_PATH);
|
|
698
698
|
}
|
|
699
699
|
function queueIntercom(targetSession, reason) {
|
|
@@ -785,10 +785,10 @@ var QUEUE_PATH, MAX_RETRIES, TTL_MS, INTERCOM_LOG;
|
|
|
785
785
|
var init_intercom_queue = __esm({
|
|
786
786
|
"src/lib/intercom-queue.ts"() {
|
|
787
787
|
"use strict";
|
|
788
|
-
QUEUE_PATH =
|
|
788
|
+
QUEUE_PATH = path7.join(os5.homedir(), ".exe-os", "intercom-queue.json");
|
|
789
789
|
MAX_RETRIES = 5;
|
|
790
790
|
TTL_MS = 60 * 60 * 1e3;
|
|
791
|
-
INTERCOM_LOG =
|
|
791
|
+
INTERCOM_LOG = path7.join(os5.homedir(), ".exe-os", "intercom.log");
|
|
792
792
|
}
|
|
793
793
|
});
|
|
794
794
|
|
|
@@ -848,8 +848,8 @@ var init_db_retry = __esm({
|
|
|
848
848
|
});
|
|
849
849
|
|
|
850
850
|
// src/lib/database-adapter.ts
|
|
851
|
-
import
|
|
852
|
-
import
|
|
851
|
+
import os6 from "os";
|
|
852
|
+
import path8 from "path";
|
|
853
853
|
import { createRequire } from "module";
|
|
854
854
|
import { pathToFileURL } from "url";
|
|
855
855
|
function quotedIdentifier(identifier) {
|
|
@@ -1160,8 +1160,8 @@ async function loadPrismaClient() {
|
|
|
1160
1160
|
}
|
|
1161
1161
|
return new PrismaClient2();
|
|
1162
1162
|
}
|
|
1163
|
-
const exeDbRoot = process.env.EXE_DB_ROOT ??
|
|
1164
|
-
const requireFromExeDb = createRequire(
|
|
1163
|
+
const exeDbRoot = process.env.EXE_DB_ROOT ?? path8.join(os6.homedir(), "exe-db");
|
|
1164
|
+
const requireFromExeDb = createRequire(path8.join(exeDbRoot, "package.json"));
|
|
1165
1165
|
const prismaEntry = requireFromExeDb.resolve("@prisma/client");
|
|
1166
1166
|
const module = await import(pathToFileURL(prismaEntry).href);
|
|
1167
1167
|
const PrismaClient = module.PrismaClient ?? module.default?.PrismaClient;
|
|
@@ -1433,8 +1433,8 @@ var init_database_adapter = __esm({
|
|
|
1433
1433
|
|
|
1434
1434
|
// src/lib/daemon-auth.ts
|
|
1435
1435
|
import crypto from "crypto";
|
|
1436
|
-
import
|
|
1437
|
-
import { existsSync as
|
|
1436
|
+
import path9 from "path";
|
|
1437
|
+
import { existsSync as existsSync8, readFileSync as readFileSync8, writeFileSync as writeFileSync7 } from "fs";
|
|
1438
1438
|
function normalizeToken(token) {
|
|
1439
1439
|
if (!token) return null;
|
|
1440
1440
|
const trimmed = token.trim();
|
|
@@ -1442,8 +1442,8 @@ function normalizeToken(token) {
|
|
|
1442
1442
|
}
|
|
1443
1443
|
function readDaemonToken() {
|
|
1444
1444
|
try {
|
|
1445
|
-
if (!
|
|
1446
|
-
return normalizeToken(
|
|
1445
|
+
if (!existsSync8(DAEMON_TOKEN_PATH)) return null;
|
|
1446
|
+
return normalizeToken(readFileSync8(DAEMON_TOKEN_PATH, "utf8"));
|
|
1447
1447
|
} catch {
|
|
1448
1448
|
return null;
|
|
1449
1449
|
}
|
|
@@ -1453,7 +1453,7 @@ function ensureDaemonToken(seed) {
|
|
|
1453
1453
|
if (existing) return existing;
|
|
1454
1454
|
const token = normalizeToken(seed) ?? crypto.randomBytes(32).toString("hex");
|
|
1455
1455
|
ensurePrivateDirSync(EXE_AI_DIR);
|
|
1456
|
-
|
|
1456
|
+
writeFileSync7(DAEMON_TOKEN_PATH, `${token}
|
|
1457
1457
|
`, "utf8");
|
|
1458
1458
|
enforcePrivateFileSync(DAEMON_TOKEN_PATH);
|
|
1459
1459
|
return token;
|
|
@@ -1464,17 +1464,17 @@ var init_daemon_auth = __esm({
|
|
|
1464
1464
|
"use strict";
|
|
1465
1465
|
init_config();
|
|
1466
1466
|
init_secure_files();
|
|
1467
|
-
DAEMON_TOKEN_PATH =
|
|
1467
|
+
DAEMON_TOKEN_PATH = path9.join(EXE_AI_DIR, "exed.token");
|
|
1468
1468
|
}
|
|
1469
1469
|
});
|
|
1470
1470
|
|
|
1471
1471
|
// src/lib/exe-daemon-client.ts
|
|
1472
1472
|
import net from "net";
|
|
1473
|
-
import
|
|
1473
|
+
import os7 from "os";
|
|
1474
1474
|
import { spawn } from "child_process";
|
|
1475
1475
|
import { randomUUID } from "crypto";
|
|
1476
|
-
import { existsSync as
|
|
1477
|
-
import
|
|
1476
|
+
import { existsSync as existsSync9, unlinkSync as unlinkSync4, readFileSync as readFileSync9, openSync, closeSync, statSync } from "fs";
|
|
1477
|
+
import path10 from "path";
|
|
1478
1478
|
import { fileURLToPath } from "url";
|
|
1479
1479
|
function handleData(chunk) {
|
|
1480
1480
|
_buffer += chunk.toString();
|
|
@@ -1502,9 +1502,9 @@ function handleData(chunk) {
|
|
|
1502
1502
|
}
|
|
1503
1503
|
}
|
|
1504
1504
|
function cleanupStaleFiles() {
|
|
1505
|
-
if (
|
|
1505
|
+
if (existsSync9(PID_PATH)) {
|
|
1506
1506
|
try {
|
|
1507
|
-
const pid = parseInt(
|
|
1507
|
+
const pid = parseInt(readFileSync9(PID_PATH, "utf8").trim(), 10);
|
|
1508
1508
|
if (pid > 0) {
|
|
1509
1509
|
try {
|
|
1510
1510
|
process.kill(pid, 0);
|
|
@@ -1515,27 +1515,27 @@ function cleanupStaleFiles() {
|
|
|
1515
1515
|
} catch {
|
|
1516
1516
|
}
|
|
1517
1517
|
try {
|
|
1518
|
-
|
|
1518
|
+
unlinkSync4(PID_PATH);
|
|
1519
1519
|
} catch {
|
|
1520
1520
|
}
|
|
1521
1521
|
try {
|
|
1522
|
-
|
|
1522
|
+
unlinkSync4(SOCKET_PATH);
|
|
1523
1523
|
} catch {
|
|
1524
1524
|
}
|
|
1525
1525
|
}
|
|
1526
1526
|
}
|
|
1527
1527
|
function findPackageRoot() {
|
|
1528
|
-
let dir =
|
|
1529
|
-
const { root } =
|
|
1528
|
+
let dir = path10.dirname(fileURLToPath(import.meta.url));
|
|
1529
|
+
const { root } = path10.parse(dir);
|
|
1530
1530
|
while (dir !== root) {
|
|
1531
|
-
if (
|
|
1532
|
-
dir =
|
|
1531
|
+
if (existsSync9(path10.join(dir, "package.json"))) return dir;
|
|
1532
|
+
dir = path10.dirname(dir);
|
|
1533
1533
|
}
|
|
1534
1534
|
return null;
|
|
1535
1535
|
}
|
|
1536
1536
|
function spawnDaemon() {
|
|
1537
|
-
const freeGB =
|
|
1538
|
-
const totalGB =
|
|
1537
|
+
const freeGB = os7.freemem() / (1024 * 1024 * 1024);
|
|
1538
|
+
const totalGB = os7.totalmem() / (1024 * 1024 * 1024);
|
|
1539
1539
|
if (totalGB <= 8) {
|
|
1540
1540
|
process.stderr.write(
|
|
1541
1541
|
`[exed-client] SKIP: ${totalGB.toFixed(0)}GB system \u2014 embedding daemon disabled. Using keyword search only. Minimum 16GB recommended for vector search.
|
|
@@ -1555,8 +1555,8 @@ function spawnDaemon() {
|
|
|
1555
1555
|
process.stderr.write("[exed-client] WARN: cannot find package root\n");
|
|
1556
1556
|
return;
|
|
1557
1557
|
}
|
|
1558
|
-
const daemonPath =
|
|
1559
|
-
if (!
|
|
1558
|
+
const daemonPath = path10.join(pkgRoot, "dist", "lib", "exe-daemon.js");
|
|
1559
|
+
if (!existsSync9(daemonPath)) {
|
|
1560
1560
|
process.stderr.write(`[exed-client] WARN: daemon script not found at ${daemonPath}
|
|
1561
1561
|
`);
|
|
1562
1562
|
return;
|
|
@@ -1565,7 +1565,7 @@ function spawnDaemon() {
|
|
|
1565
1565
|
const daemonToken = ensureDaemonToken(process.env[DAEMON_TOKEN_ENV] ?? null);
|
|
1566
1566
|
process.stderr.write(`[exed-client] Spawning daemon: ${resolvedPath}
|
|
1567
1567
|
`);
|
|
1568
|
-
const logPath =
|
|
1568
|
+
const logPath = path10.join(path10.dirname(SOCKET_PATH), "exed.log");
|
|
1569
1569
|
let stderrFd = "ignore";
|
|
1570
1570
|
try {
|
|
1571
1571
|
stderrFd = openSync(logPath, "a");
|
|
@@ -1605,7 +1605,7 @@ function acquireSpawnLock() {
|
|
|
1605
1605
|
const stat = statSync(SPAWN_LOCK_PATH);
|
|
1606
1606
|
if (Date.now() - stat.mtimeMs > SPAWN_LOCK_STALE_MS) {
|
|
1607
1607
|
try {
|
|
1608
|
-
|
|
1608
|
+
unlinkSync4(SPAWN_LOCK_PATH);
|
|
1609
1609
|
} catch {
|
|
1610
1610
|
}
|
|
1611
1611
|
try {
|
|
@@ -1622,7 +1622,7 @@ function acquireSpawnLock() {
|
|
|
1622
1622
|
}
|
|
1623
1623
|
function releaseSpawnLock() {
|
|
1624
1624
|
try {
|
|
1625
|
-
|
|
1625
|
+
unlinkSync4(SPAWN_LOCK_PATH);
|
|
1626
1626
|
} catch {
|
|
1627
1627
|
}
|
|
1628
1628
|
}
|
|
@@ -1715,9 +1715,9 @@ var init_exe_daemon_client = __esm({
|
|
|
1715
1715
|
"use strict";
|
|
1716
1716
|
init_config();
|
|
1717
1717
|
init_daemon_auth();
|
|
1718
|
-
SOCKET_PATH = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ??
|
|
1719
|
-
PID_PATH = process.env.EXE_DAEMON_PID ?? process.env.EXE_EMBED_PID ??
|
|
1720
|
-
SPAWN_LOCK_PATH =
|
|
1718
|
+
SOCKET_PATH = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ?? path10.join(EXE_AI_DIR, "exed.sock");
|
|
1719
|
+
PID_PATH = process.env.EXE_DAEMON_PID ?? process.env.EXE_EMBED_PID ?? path10.join(EXE_AI_DIR, "exed.pid");
|
|
1720
|
+
SPAWN_LOCK_PATH = path10.join(EXE_AI_DIR, "exed-spawn.lock");
|
|
1721
1721
|
SPAWN_LOCK_STALE_MS = 3e4;
|
|
1722
1722
|
CONNECT_TIMEOUT_MS = 15e3;
|
|
1723
1723
|
REQUEST_TIMEOUT_MS = 3e4;
|
|
@@ -2794,12 +2794,26 @@ async function ensureSchema() {
|
|
|
2794
2794
|
session_name TEXT,
|
|
2795
2795
|
task_id TEXT,
|
|
2796
2796
|
project_name TEXT,
|
|
2797
|
-
started_at TEXT NOT NULL
|
|
2797
|
+
started_at TEXT NOT NULL,
|
|
2798
|
+
cache_cold_count INTEGER NOT NULL DEFAULT 0
|
|
2798
2799
|
);
|
|
2799
2800
|
|
|
2800
2801
|
CREATE INDEX IF NOT EXISTS idx_session_agent_map_agent
|
|
2801
2802
|
ON session_agent_map(agent_id);
|
|
2802
2803
|
`);
|
|
2804
|
+
await client.executeMultiple(`
|
|
2805
|
+
CREATE TABLE IF NOT EXISTS agent_file_reads (
|
|
2806
|
+
session_uuid TEXT NOT NULL,
|
|
2807
|
+
agent_id TEXT NOT NULL,
|
|
2808
|
+
file_path TEXT NOT NULL,
|
|
2809
|
+
read_at TEXT NOT NULL,
|
|
2810
|
+
commit_hash TEXT,
|
|
2811
|
+
PRIMARY KEY (session_uuid, file_path)
|
|
2812
|
+
);
|
|
2813
|
+
|
|
2814
|
+
CREATE INDEX IF NOT EXISTS idx_agent_file_reads_agent_read_at
|
|
2815
|
+
ON agent_file_reads(agent_id, read_at);
|
|
2816
|
+
`);
|
|
2803
2817
|
try {
|
|
2804
2818
|
const mapCount = await client.execute({ sql: `SELECT COUNT(*) as cnt FROM session_agent_map`, args: [] });
|
|
2805
2819
|
if (Number(mapCount.rows[0]?.cnt ?? 0) === 0) {
|
|
@@ -2814,6 +2828,13 @@ async function ensureSchema() {
|
|
|
2814
2828
|
}
|
|
2815
2829
|
} catch {
|
|
2816
2830
|
}
|
|
2831
|
+
try {
|
|
2832
|
+
await client.execute({
|
|
2833
|
+
sql: `ALTER TABLE session_agent_map ADD COLUMN cache_cold_count INTEGER NOT NULL DEFAULT 0`,
|
|
2834
|
+
args: []
|
|
2835
|
+
});
|
|
2836
|
+
} catch {
|
|
2837
|
+
}
|
|
2817
2838
|
try {
|
|
2818
2839
|
await client.execute({
|
|
2819
2840
|
sql: `ALTER TABLE tasks ADD COLUMN budget_tokens INTEGER`,
|
|
@@ -3014,21 +3035,21 @@ var init_database = __esm({
|
|
|
3014
3035
|
});
|
|
3015
3036
|
|
|
3016
3037
|
// src/lib/license.ts
|
|
3017
|
-
import { readFileSync as
|
|
3038
|
+
import { readFileSync as readFileSync10, writeFileSync as writeFileSync8, existsSync as existsSync10, mkdirSync as mkdirSync6 } from "fs";
|
|
3018
3039
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
3019
3040
|
import { createRequire as createRequire2 } from "module";
|
|
3020
3041
|
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
3021
|
-
import
|
|
3022
|
-
import
|
|
3042
|
+
import os8 from "os";
|
|
3043
|
+
import path11 from "path";
|
|
3023
3044
|
import { jwtVerify, importSPKI } from "jose";
|
|
3024
3045
|
var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH, PLAN_LIMITS;
|
|
3025
3046
|
var init_license = __esm({
|
|
3026
3047
|
"src/lib/license.ts"() {
|
|
3027
3048
|
"use strict";
|
|
3028
3049
|
init_config();
|
|
3029
|
-
LICENSE_PATH =
|
|
3030
|
-
CACHE_PATH =
|
|
3031
|
-
DEVICE_ID_PATH =
|
|
3050
|
+
LICENSE_PATH = path11.join(EXE_AI_DIR, "license.key");
|
|
3051
|
+
CACHE_PATH = path11.join(EXE_AI_DIR, "license-cache.json");
|
|
3052
|
+
DEVICE_ID_PATH = path11.join(EXE_AI_DIR, "device-id");
|
|
3032
3053
|
PLAN_LIMITS = {
|
|
3033
3054
|
free: { devices: 1, employees: 1, memories: 5e3 },
|
|
3034
3055
|
pro: { devices: 3, employees: 5, memories: 1e5 },
|
|
@@ -3040,12 +3061,12 @@ var init_license = __esm({
|
|
|
3040
3061
|
});
|
|
3041
3062
|
|
|
3042
3063
|
// src/lib/plan-limits.ts
|
|
3043
|
-
import { readFileSync as
|
|
3044
|
-
import
|
|
3064
|
+
import { readFileSync as readFileSync11, existsSync as existsSync11 } from "fs";
|
|
3065
|
+
import path12 from "path";
|
|
3045
3066
|
function getLicenseSync() {
|
|
3046
3067
|
try {
|
|
3047
|
-
if (!
|
|
3048
|
-
const raw = JSON.parse(
|
|
3068
|
+
if (!existsSync11(CACHE_PATH2)) return freeLicense();
|
|
3069
|
+
const raw = JSON.parse(readFileSync11(CACHE_PATH2, "utf8"));
|
|
3049
3070
|
if (!raw.token || typeof raw.token !== "string") return freeLicense();
|
|
3050
3071
|
const parts = raw.token.split(".");
|
|
3051
3072
|
if (parts.length !== 3) return freeLicense();
|
|
@@ -3083,8 +3104,8 @@ function assertEmployeeLimitSync(rosterPath) {
|
|
|
3083
3104
|
const filePath = rosterPath ?? EMPLOYEES_PATH;
|
|
3084
3105
|
let count = 0;
|
|
3085
3106
|
try {
|
|
3086
|
-
if (
|
|
3087
|
-
const raw =
|
|
3107
|
+
if (existsSync11(filePath)) {
|
|
3108
|
+
const raw = readFileSync11(filePath, "utf8");
|
|
3088
3109
|
const employees = JSON.parse(raw);
|
|
3089
3110
|
count = Array.isArray(employees) ? employees.length : 0;
|
|
3090
3111
|
}
|
|
@@ -3113,7 +3134,7 @@ var init_plan_limits = __esm({
|
|
|
3113
3134
|
this.name = "PlanLimitError";
|
|
3114
3135
|
}
|
|
3115
3136
|
};
|
|
3116
|
-
CACHE_PATH2 =
|
|
3137
|
+
CACHE_PATH2 = path12.join(EXE_AI_DIR, "license-cache.json");
|
|
3117
3138
|
}
|
|
3118
3139
|
});
|
|
3119
3140
|
|
|
@@ -3130,13 +3151,13 @@ __export(notifications_exports, {
|
|
|
3130
3151
|
writeNotification: () => writeNotification
|
|
3131
3152
|
});
|
|
3132
3153
|
import crypto2 from "crypto";
|
|
3133
|
-
import
|
|
3134
|
-
import
|
|
3154
|
+
import path13 from "path";
|
|
3155
|
+
import os9 from "os";
|
|
3135
3156
|
import {
|
|
3136
|
-
readFileSync as
|
|
3157
|
+
readFileSync as readFileSync12,
|
|
3137
3158
|
readdirSync as readdirSync2,
|
|
3138
|
-
unlinkSync as
|
|
3139
|
-
existsSync as
|
|
3159
|
+
unlinkSync as unlinkSync5,
|
|
3160
|
+
existsSync as existsSync12,
|
|
3140
3161
|
rmdirSync
|
|
3141
3162
|
} from "fs";
|
|
3142
3163
|
async function writeNotification(notification) {
|
|
@@ -3282,9 +3303,9 @@ function formatNotifications(notifications) {
|
|
|
3282
3303
|
return lines.join("\n");
|
|
3283
3304
|
}
|
|
3284
3305
|
async function migrateJsonNotifications() {
|
|
3285
|
-
const base = process.env.EXE_OS_DIR || process.env.EXE_MEM_DIR ||
|
|
3286
|
-
const notifDir =
|
|
3287
|
-
if (!
|
|
3306
|
+
const base = process.env.EXE_OS_DIR || process.env.EXE_MEM_DIR || path13.join(os9.homedir(), ".exe-os");
|
|
3307
|
+
const notifDir = path13.join(base, "notifications");
|
|
3308
|
+
if (!existsSync12(notifDir)) return 0;
|
|
3288
3309
|
let migrated = 0;
|
|
3289
3310
|
try {
|
|
3290
3311
|
const files = readdirSync2(notifDir).filter((f) => f.endsWith(".json"));
|
|
@@ -3292,8 +3313,8 @@ async function migrateJsonNotifications() {
|
|
|
3292
3313
|
const client = getClient();
|
|
3293
3314
|
for (const file of files) {
|
|
3294
3315
|
try {
|
|
3295
|
-
const filePath =
|
|
3296
|
-
const data = JSON.parse(
|
|
3316
|
+
const filePath = path13.join(notifDir, file);
|
|
3317
|
+
const data = JSON.parse(readFileSync12(filePath, "utf8"));
|
|
3297
3318
|
await client.execute({
|
|
3298
3319
|
sql: `INSERT OR IGNORE INTO notifications (id, agent_id, agent_role, event, project, summary, task_file, session_scope, read, created_at)
|
|
3299
3320
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
@@ -3310,7 +3331,7 @@ async function migrateJsonNotifications() {
|
|
|
3310
3331
|
data.timestamp ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
3311
3332
|
]
|
|
3312
3333
|
});
|
|
3313
|
-
|
|
3334
|
+
unlinkSync5(filePath);
|
|
3314
3335
|
migrated++;
|
|
3315
3336
|
} catch {
|
|
3316
3337
|
}
|
|
@@ -3455,7 +3476,7 @@ var init_state_bus = __esm({
|
|
|
3455
3476
|
|
|
3456
3477
|
// src/lib/project-name.ts
|
|
3457
3478
|
import { execSync as execSync5 } from "child_process";
|
|
3458
|
-
import
|
|
3479
|
+
import path14 from "path";
|
|
3459
3480
|
function getProjectName(cwd) {
|
|
3460
3481
|
const dir = cwd ?? process.cwd();
|
|
3461
3482
|
if (_cached2 && _cachedCwd === dir) return _cached2;
|
|
@@ -3468,7 +3489,7 @@ function getProjectName(cwd) {
|
|
|
3468
3489
|
timeout: 2e3,
|
|
3469
3490
|
stdio: ["pipe", "pipe", "pipe"]
|
|
3470
3491
|
}).trim();
|
|
3471
|
-
repoRoot =
|
|
3492
|
+
repoRoot = path14.dirname(gitCommonDir);
|
|
3472
3493
|
} catch {
|
|
3473
3494
|
repoRoot = execSync5("git rev-parse --show-toplevel", {
|
|
3474
3495
|
cwd: dir,
|
|
@@ -3477,11 +3498,11 @@ function getProjectName(cwd) {
|
|
|
3477
3498
|
stdio: ["pipe", "pipe", "pipe"]
|
|
3478
3499
|
}).trim();
|
|
3479
3500
|
}
|
|
3480
|
-
_cached2 =
|
|
3501
|
+
_cached2 = path14.basename(repoRoot);
|
|
3481
3502
|
_cachedCwd = dir;
|
|
3482
3503
|
return _cached2;
|
|
3483
3504
|
} catch {
|
|
3484
|
-
_cached2 =
|
|
3505
|
+
_cached2 = path14.basename(dir);
|
|
3485
3506
|
_cachedCwd = dir;
|
|
3486
3507
|
return _cached2;
|
|
3487
3508
|
}
|
|
@@ -3575,11 +3596,11 @@ __export(tasks_crud_exports, {
|
|
|
3575
3596
|
writeCheckpoint: () => writeCheckpoint
|
|
3576
3597
|
});
|
|
3577
3598
|
import crypto4 from "crypto";
|
|
3578
|
-
import
|
|
3579
|
-
import
|
|
3599
|
+
import path15 from "path";
|
|
3600
|
+
import os10 from "os";
|
|
3580
3601
|
import { execSync as execSync6 } from "child_process";
|
|
3581
3602
|
import { mkdir as mkdir3, writeFile as writeFile3, appendFile } from "fs/promises";
|
|
3582
|
-
import { existsSync as
|
|
3603
|
+
import { existsSync as existsSync13, readFileSync as readFileSync13 } from "fs";
|
|
3583
3604
|
async function writeCheckpoint(input2) {
|
|
3584
3605
|
const client = getClient();
|
|
3585
3606
|
const row = await resolveTask(client, input2.taskId);
|
|
@@ -3773,8 +3794,8 @@ ${scopeMismatchWarning}` : scopeMismatchWarning;
|
|
|
3773
3794
|
}
|
|
3774
3795
|
if (input2.baseDir) {
|
|
3775
3796
|
try {
|
|
3776
|
-
await mkdir3(
|
|
3777
|
-
await mkdir3(
|
|
3797
|
+
await mkdir3(path15.join(input2.baseDir, "exe", "output"), { recursive: true });
|
|
3798
|
+
await mkdir3(path15.join(input2.baseDir, "exe", "research"), { recursive: true });
|
|
3778
3799
|
await ensureArchitectureDoc(input2.baseDir, input2.projectName);
|
|
3779
3800
|
await ensureGitignoreExe(input2.baseDir);
|
|
3780
3801
|
} catch {
|
|
@@ -3810,10 +3831,10 @@ ${scopeMismatchWarning}` : scopeMismatchWarning;
|
|
|
3810
3831
|
});
|
|
3811
3832
|
if (input2.baseDir) {
|
|
3812
3833
|
try {
|
|
3813
|
-
const EXE_OS_DIR =
|
|
3814
|
-
const mdPath =
|
|
3815
|
-
const mdDir =
|
|
3816
|
-
if (!
|
|
3834
|
+
const EXE_OS_DIR = path15.join(os10.homedir(), ".exe-os");
|
|
3835
|
+
const mdPath = path15.join(EXE_OS_DIR, taskFile);
|
|
3836
|
+
const mdDir = path15.dirname(mdPath);
|
|
3837
|
+
if (!existsSync13(mdDir)) await mkdir3(mdDir, { recursive: true });
|
|
3817
3838
|
const reviewer = input2.reviewer ?? input2.assignedBy;
|
|
3818
3839
|
const mdContent = `# ${input2.title}
|
|
3819
3840
|
|
|
@@ -4113,9 +4134,9 @@ async function deleteTaskCore(taskId, _baseDir) {
|
|
|
4113
4134
|
return { taskFile, assignedTo, assignedBy, taskSlug };
|
|
4114
4135
|
}
|
|
4115
4136
|
async function ensureArchitectureDoc(baseDir, projectName) {
|
|
4116
|
-
const archPath =
|
|
4137
|
+
const archPath = path15.join(baseDir, "exe", "ARCHITECTURE.md");
|
|
4117
4138
|
try {
|
|
4118
|
-
if (
|
|
4139
|
+
if (existsSync13(archPath)) return;
|
|
4119
4140
|
const template = [
|
|
4120
4141
|
`# ${projectName} \u2014 System Architecture`,
|
|
4121
4142
|
"",
|
|
@@ -4148,10 +4169,10 @@ async function ensureArchitectureDoc(baseDir, projectName) {
|
|
|
4148
4169
|
}
|
|
4149
4170
|
}
|
|
4150
4171
|
async function ensureGitignoreExe(baseDir) {
|
|
4151
|
-
const gitignorePath =
|
|
4172
|
+
const gitignorePath = path15.join(baseDir, ".gitignore");
|
|
4152
4173
|
try {
|
|
4153
|
-
if (
|
|
4154
|
-
const content =
|
|
4174
|
+
if (existsSync13(gitignorePath)) {
|
|
4175
|
+
const content = readFileSync13(gitignorePath, "utf-8");
|
|
4155
4176
|
if (/^\/?exe\/?$/m.test(content)) return;
|
|
4156
4177
|
await appendFile(gitignorePath, "\n# Employee task assignments (private)\n/exe/\n");
|
|
4157
4178
|
} else {
|
|
@@ -4194,8 +4215,8 @@ __export(tasks_review_exports, {
|
|
|
4194
4215
|
isStale: () => isStale,
|
|
4195
4216
|
listPendingReviews: () => listPendingReviews
|
|
4196
4217
|
});
|
|
4197
|
-
import
|
|
4198
|
-
import { existsSync as
|
|
4218
|
+
import path16 from "path";
|
|
4219
|
+
import { existsSync as existsSync14, readdirSync as readdirSync3, unlinkSync as unlinkSync6 } from "fs";
|
|
4199
4220
|
function formatAge(isoTimestamp) {
|
|
4200
4221
|
if (!isoTimestamp) return "";
|
|
4201
4222
|
const ms = Date.now() - new Date(isoTimestamp).getTime();
|
|
@@ -4464,11 +4485,11 @@ async function cleanupReviewFile(row, taskFile, _baseDir) {
|
|
|
4464
4485
|
);
|
|
4465
4486
|
}
|
|
4466
4487
|
try {
|
|
4467
|
-
const cacheDir =
|
|
4468
|
-
if (
|
|
4488
|
+
const cacheDir = path16.join(EXE_AI_DIR, "session-cache");
|
|
4489
|
+
if (existsSync14(cacheDir)) {
|
|
4469
4490
|
for (const f of readdirSync3(cacheDir)) {
|
|
4470
4491
|
if (f.startsWith("review-notified-")) {
|
|
4471
|
-
|
|
4492
|
+
unlinkSync6(path16.join(cacheDir, f));
|
|
4472
4493
|
}
|
|
4473
4494
|
}
|
|
4474
4495
|
}
|
|
@@ -4490,7 +4511,7 @@ var init_tasks_review = __esm({
|
|
|
4490
4511
|
});
|
|
4491
4512
|
|
|
4492
4513
|
// src/lib/tasks-chain.ts
|
|
4493
|
-
import
|
|
4514
|
+
import path17 from "path";
|
|
4494
4515
|
import { readFile as readFile3, writeFile as writeFile4 } from "fs/promises";
|
|
4495
4516
|
async function cascadeUnblock(taskId, baseDir, now) {
|
|
4496
4517
|
const client = getClient();
|
|
@@ -4507,7 +4528,7 @@ async function cascadeUnblock(taskId, baseDir, now) {
|
|
|
4507
4528
|
});
|
|
4508
4529
|
for (const ur of unblockedRows.rows) {
|
|
4509
4530
|
try {
|
|
4510
|
-
const ubFile =
|
|
4531
|
+
const ubFile = path17.join(baseDir, String(ur.task_file));
|
|
4511
4532
|
let ubContent = await readFile3(ubFile, "utf-8");
|
|
4512
4533
|
ubContent = ubContent.replace(/\*\*Status:\*\* blocked/, "**Status:** open");
|
|
4513
4534
|
ubContent = ubContent.replace(/\n\*\*Blocked by:\*\*.*\n/, "\n");
|
|
@@ -4971,8 +4992,8 @@ __export(tasks_exports, {
|
|
|
4971
4992
|
updateTaskStatus: () => updateTaskStatus,
|
|
4972
4993
|
writeCheckpoint: () => writeCheckpoint
|
|
4973
4994
|
});
|
|
4974
|
-
import
|
|
4975
|
-
import { writeFileSync as
|
|
4995
|
+
import path18 from "path";
|
|
4996
|
+
import { writeFileSync as writeFileSync9, mkdirSync as mkdirSync7, unlinkSync as unlinkSync7 } from "fs";
|
|
4976
4997
|
async function createTask(input2) {
|
|
4977
4998
|
const result = await createTaskCore(input2);
|
|
4978
4999
|
if (!input2.skipDispatch && result.status !== "blocked" && !process.env.VITEST) {
|
|
@@ -4991,14 +5012,14 @@ async function updateTask(input2) {
|
|
|
4991
5012
|
const { row, taskFile, now, taskId } = await updateTaskStatus(input2);
|
|
4992
5013
|
try {
|
|
4993
5014
|
const agent = String(row.assigned_to);
|
|
4994
|
-
const cacheDir =
|
|
4995
|
-
const cachePath =
|
|
5015
|
+
const cacheDir = path18.join(EXE_AI_DIR, "session-cache");
|
|
5016
|
+
const cachePath = path18.join(cacheDir, `current-task-${agent}.json`);
|
|
4996
5017
|
if (input2.status === "in_progress") {
|
|
4997
|
-
|
|
4998
|
-
|
|
5018
|
+
mkdirSync7(cacheDir, { recursive: true });
|
|
5019
|
+
writeFileSync9(cachePath, JSON.stringify({ taskId, title: String(row.title) }));
|
|
4999
5020
|
} else if (input2.status === "done" || input2.status === "blocked" || input2.status === "cancelled" || input2.status === "closed") {
|
|
5000
5021
|
try {
|
|
5001
|
-
|
|
5022
|
+
unlinkSync7(cachePath);
|
|
5002
5023
|
} catch {
|
|
5003
5024
|
}
|
|
5004
5025
|
}
|
|
@@ -5463,13 +5484,13 @@ __export(tmux_routing_exports, {
|
|
|
5463
5484
|
verifyPaneAtCapacity: () => verifyPaneAtCapacity
|
|
5464
5485
|
});
|
|
5465
5486
|
import { execFileSync as execFileSync2, execSync as execSync7 } from "child_process";
|
|
5466
|
-
import { readFileSync as
|
|
5467
|
-
import
|
|
5468
|
-
import
|
|
5487
|
+
import { readFileSync as readFileSync14, writeFileSync as writeFileSync10, mkdirSync as mkdirSync8, existsSync as existsSync15, appendFileSync, readdirSync as readdirSync4 } from "fs";
|
|
5488
|
+
import path19 from "path";
|
|
5489
|
+
import os11 from "os";
|
|
5469
5490
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
5470
|
-
import { unlinkSync as
|
|
5491
|
+
import { unlinkSync as unlinkSync8 } from "fs";
|
|
5471
5492
|
function spawnLockPath(sessionName) {
|
|
5472
|
-
return
|
|
5493
|
+
return path19.join(SPAWN_LOCK_DIR, `${sessionName}.lock`);
|
|
5473
5494
|
}
|
|
5474
5495
|
function isProcessAlive(pid) {
|
|
5475
5496
|
try {
|
|
@@ -5480,13 +5501,13 @@ function isProcessAlive(pid) {
|
|
|
5480
5501
|
}
|
|
5481
5502
|
}
|
|
5482
5503
|
function acquireSpawnLock2(sessionName) {
|
|
5483
|
-
if (!
|
|
5484
|
-
|
|
5504
|
+
if (!existsSync15(SPAWN_LOCK_DIR)) {
|
|
5505
|
+
mkdirSync8(SPAWN_LOCK_DIR, { recursive: true });
|
|
5485
5506
|
}
|
|
5486
5507
|
const lockFile = spawnLockPath(sessionName);
|
|
5487
|
-
if (
|
|
5508
|
+
if (existsSync15(lockFile)) {
|
|
5488
5509
|
try {
|
|
5489
|
-
const lock = JSON.parse(
|
|
5510
|
+
const lock = JSON.parse(readFileSync14(lockFile, "utf8"));
|
|
5490
5511
|
const age = Date.now() - lock.timestamp;
|
|
5491
5512
|
if (isProcessAlive(lock.pid) && age < 6e4) {
|
|
5492
5513
|
return false;
|
|
@@ -5494,25 +5515,25 @@ function acquireSpawnLock2(sessionName) {
|
|
|
5494
5515
|
} catch {
|
|
5495
5516
|
}
|
|
5496
5517
|
}
|
|
5497
|
-
|
|
5518
|
+
writeFileSync10(lockFile, JSON.stringify({ pid: process.pid, timestamp: Date.now() }));
|
|
5498
5519
|
return true;
|
|
5499
5520
|
}
|
|
5500
5521
|
function releaseSpawnLock2(sessionName) {
|
|
5501
5522
|
try {
|
|
5502
|
-
|
|
5523
|
+
unlinkSync8(spawnLockPath(sessionName));
|
|
5503
5524
|
} catch {
|
|
5504
5525
|
}
|
|
5505
5526
|
}
|
|
5506
5527
|
function resolveBehaviorsExporterScript() {
|
|
5507
5528
|
try {
|
|
5508
5529
|
const thisFile = fileURLToPath2(import.meta.url);
|
|
5509
|
-
const scriptPath =
|
|
5510
|
-
|
|
5530
|
+
const scriptPath = path19.join(
|
|
5531
|
+
path19.dirname(thisFile),
|
|
5511
5532
|
"..",
|
|
5512
5533
|
"bin",
|
|
5513
5534
|
"exe-export-behaviors.js"
|
|
5514
5535
|
);
|
|
5515
|
-
return
|
|
5536
|
+
return existsSync15(scriptPath) ? scriptPath : null;
|
|
5516
5537
|
} catch {
|
|
5517
5538
|
return null;
|
|
5518
5539
|
}
|
|
@@ -5578,12 +5599,12 @@ function extractRootExe(name) {
|
|
|
5578
5599
|
return parts.length > 0 ? parts[parts.length - 1] : null;
|
|
5579
5600
|
}
|
|
5580
5601
|
function registerParentExe(sessionKey, parentExe, dispatchedBy) {
|
|
5581
|
-
if (!
|
|
5582
|
-
|
|
5602
|
+
if (!existsSync15(SESSION_CACHE)) {
|
|
5603
|
+
mkdirSync8(SESSION_CACHE, { recursive: true });
|
|
5583
5604
|
}
|
|
5584
5605
|
const rootExe = extractRootExe(parentExe) ?? parentExe;
|
|
5585
|
-
const filePath =
|
|
5586
|
-
|
|
5606
|
+
const filePath = path19.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`);
|
|
5607
|
+
writeFileSync10(filePath, JSON.stringify({
|
|
5587
5608
|
parentExe: rootExe,
|
|
5588
5609
|
dispatchedBy: dispatchedBy || rootExe,
|
|
5589
5610
|
registeredAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -5591,7 +5612,7 @@ function registerParentExe(sessionKey, parentExe, dispatchedBy) {
|
|
|
5591
5612
|
}
|
|
5592
5613
|
function getParentExe(sessionKey) {
|
|
5593
5614
|
try {
|
|
5594
|
-
const data = JSON.parse(
|
|
5615
|
+
const data = JSON.parse(readFileSync14(path19.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
|
|
5595
5616
|
return data.parentExe || null;
|
|
5596
5617
|
} catch {
|
|
5597
5618
|
return null;
|
|
@@ -5599,8 +5620,8 @@ function getParentExe(sessionKey) {
|
|
|
5599
5620
|
}
|
|
5600
5621
|
function getDispatchedBy(sessionKey) {
|
|
5601
5622
|
try {
|
|
5602
|
-
const data = JSON.parse(
|
|
5603
|
-
|
|
5623
|
+
const data = JSON.parse(readFileSync14(
|
|
5624
|
+
path19.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`),
|
|
5604
5625
|
"utf8"
|
|
5605
5626
|
));
|
|
5606
5627
|
return data.dispatchedBy ?? data.parentExe ?? null;
|
|
@@ -5670,8 +5691,8 @@ async function verifyPaneAtCapacity(sessionName) {
|
|
|
5670
5691
|
}
|
|
5671
5692
|
function readDebounceState() {
|
|
5672
5693
|
try {
|
|
5673
|
-
if (!
|
|
5674
|
-
const raw = JSON.parse(
|
|
5694
|
+
if (!existsSync15(DEBOUNCE_FILE)) return {};
|
|
5695
|
+
const raw = JSON.parse(readFileSync14(DEBOUNCE_FILE, "utf8"));
|
|
5675
5696
|
const state = {};
|
|
5676
5697
|
for (const [key, val] of Object.entries(raw)) {
|
|
5677
5698
|
if (typeof val === "number") {
|
|
@@ -5687,8 +5708,8 @@ function readDebounceState() {
|
|
|
5687
5708
|
}
|
|
5688
5709
|
function writeDebounceState(state) {
|
|
5689
5710
|
try {
|
|
5690
|
-
if (!
|
|
5691
|
-
|
|
5711
|
+
if (!existsSync15(SESSION_CACHE)) mkdirSync8(SESSION_CACHE, { recursive: true });
|
|
5712
|
+
writeFileSync10(DEBOUNCE_FILE, JSON.stringify(state));
|
|
5692
5713
|
} catch {
|
|
5693
5714
|
}
|
|
5694
5715
|
}
|
|
@@ -5787,8 +5808,8 @@ function sendIntercom(targetSession) {
|
|
|
5787
5808
|
try {
|
|
5788
5809
|
const rawAgent = targetSession.split("-")[0] ?? targetSession;
|
|
5789
5810
|
const agent = baseAgentName(rawAgent);
|
|
5790
|
-
const markerPath =
|
|
5791
|
-
if (
|
|
5811
|
+
const markerPath = path19.join(SESSION_CACHE, `current-task-${agent}.json`);
|
|
5812
|
+
if (existsSync15(markerPath)) {
|
|
5792
5813
|
logIntercom(`SKIP \u2192 ${targetSession} (has in_progress task marker + not idle \u2014 will auto-chain)`);
|
|
5793
5814
|
return "debounced";
|
|
5794
5815
|
}
|
|
@@ -5798,8 +5819,8 @@ function sendIntercom(targetSession) {
|
|
|
5798
5819
|
try {
|
|
5799
5820
|
const rawAgent = targetSession.split("-")[0] ?? targetSession;
|
|
5800
5821
|
const agent = baseAgentName(rawAgent);
|
|
5801
|
-
const taskDir =
|
|
5802
|
-
if (
|
|
5822
|
+
const taskDir = path19.join(process.cwd(), "exe", agent);
|
|
5823
|
+
if (existsSync15(taskDir)) {
|
|
5803
5824
|
const files = readdirSync4(taskDir).filter(
|
|
5804
5825
|
(f) => f.endsWith(".md") && f !== "DONE.txt"
|
|
5805
5826
|
);
|
|
@@ -5965,26 +5986,26 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
5965
5986
|
const transport = getTransport();
|
|
5966
5987
|
const sessionName = employeeSessionName(employeeName, exeSession, opts?.instance);
|
|
5967
5988
|
const instanceLabel = opts?.instance != null && opts.instance > 0 ? `${employeeName}${opts.instance}` : employeeName;
|
|
5968
|
-
const logDir =
|
|
5969
|
-
const logFile =
|
|
5970
|
-
if (!
|
|
5971
|
-
|
|
5989
|
+
const logDir = path19.join(os11.homedir(), ".exe-os", "session-logs");
|
|
5990
|
+
const logFile = path19.join(logDir, `${instanceLabel}-${Date.now()}.log`);
|
|
5991
|
+
if (!existsSync15(logDir)) {
|
|
5992
|
+
mkdirSync8(logDir, { recursive: true });
|
|
5972
5993
|
}
|
|
5973
5994
|
transport.kill(sessionName);
|
|
5974
5995
|
let cleanupSuffix = "";
|
|
5975
5996
|
try {
|
|
5976
5997
|
const thisFile = fileURLToPath2(import.meta.url);
|
|
5977
|
-
const cleanupScript =
|
|
5978
|
-
if (
|
|
5998
|
+
const cleanupScript = path19.join(path19.dirname(thisFile), "..", "bin", "exe-session-cleanup.js");
|
|
5999
|
+
if (existsSync15(cleanupScript)) {
|
|
5979
6000
|
cleanupSuffix = `; ${process.execPath} "${cleanupScript}" "${employeeName}" "${exeSession}"`;
|
|
5980
6001
|
}
|
|
5981
6002
|
} catch {
|
|
5982
6003
|
}
|
|
5983
6004
|
try {
|
|
5984
|
-
const claudeJsonPath =
|
|
6005
|
+
const claudeJsonPath = path19.join(os11.homedir(), ".claude.json");
|
|
5985
6006
|
let claudeJson = {};
|
|
5986
6007
|
try {
|
|
5987
|
-
claudeJson = JSON.parse(
|
|
6008
|
+
claudeJson = JSON.parse(readFileSync14(claudeJsonPath, "utf8"));
|
|
5988
6009
|
} catch {
|
|
5989
6010
|
}
|
|
5990
6011
|
if (!claudeJson.projects) claudeJson.projects = {};
|
|
@@ -5992,17 +6013,17 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
5992
6013
|
const trustDir = opts?.cwd ?? projectDir;
|
|
5993
6014
|
if (!projects[trustDir]) projects[trustDir] = {};
|
|
5994
6015
|
projects[trustDir].hasTrustDialogAccepted = true;
|
|
5995
|
-
|
|
6016
|
+
writeFileSync10(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
|
|
5996
6017
|
} catch {
|
|
5997
6018
|
}
|
|
5998
6019
|
try {
|
|
5999
|
-
const settingsDir =
|
|
6020
|
+
const settingsDir = path19.join(os11.homedir(), ".claude", "projects");
|
|
6000
6021
|
const normalizedKey = (opts?.cwd ?? projectDir).replace(/\//g, "-").replace(/^-/, "");
|
|
6001
|
-
const projSettingsDir =
|
|
6002
|
-
const settingsPath =
|
|
6022
|
+
const projSettingsDir = path19.join(settingsDir, normalizedKey);
|
|
6023
|
+
const settingsPath = path19.join(projSettingsDir, "settings.json");
|
|
6003
6024
|
let settings = {};
|
|
6004
6025
|
try {
|
|
6005
|
-
settings = JSON.parse(
|
|
6026
|
+
settings = JSON.parse(readFileSync14(settingsPath, "utf8"));
|
|
6006
6027
|
} catch {
|
|
6007
6028
|
}
|
|
6008
6029
|
const perms = settings.permissions ?? {};
|
|
@@ -6030,8 +6051,8 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
6030
6051
|
if (changed) {
|
|
6031
6052
|
perms.allow = allow;
|
|
6032
6053
|
settings.permissions = perms;
|
|
6033
|
-
|
|
6034
|
-
|
|
6054
|
+
mkdirSync8(projSettingsDir, { recursive: true });
|
|
6055
|
+
writeFileSync10(settingsPath, JSON.stringify(settings, null, 2) + "\n");
|
|
6035
6056
|
}
|
|
6036
6057
|
} catch {
|
|
6037
6058
|
}
|
|
@@ -6046,8 +6067,8 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
6046
6067
|
let behaviorsFlag = "";
|
|
6047
6068
|
let legacyFallbackWarned = false;
|
|
6048
6069
|
if (!useExeAgent && !useBinSymlink) {
|
|
6049
|
-
const identityPath =
|
|
6050
|
-
|
|
6070
|
+
const identityPath = path19.join(
|
|
6071
|
+
os11.homedir(),
|
|
6051
6072
|
".exe-os",
|
|
6052
6073
|
"identity",
|
|
6053
6074
|
`${employeeName}.md`
|
|
@@ -6056,13 +6077,13 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
6056
6077
|
const hasAgentFlag = claudeSupportsAgentFlag();
|
|
6057
6078
|
if (hasAgentFlag) {
|
|
6058
6079
|
identityFlag = ` --agent ${employeeName}`;
|
|
6059
|
-
} else if (
|
|
6080
|
+
} else if (existsSync15(identityPath)) {
|
|
6060
6081
|
identityFlag = ` --append-system-prompt-file ${identityPath}`;
|
|
6061
6082
|
legacyFallbackWarned = true;
|
|
6062
6083
|
}
|
|
6063
6084
|
const behaviorsFile = exportBehaviorsSync(
|
|
6064
6085
|
employeeName,
|
|
6065
|
-
|
|
6086
|
+
path19.basename(spawnCwd),
|
|
6066
6087
|
sessionName
|
|
6067
6088
|
);
|
|
6068
6089
|
if (behaviorsFile) {
|
|
@@ -6077,16 +6098,16 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
6077
6098
|
}
|
|
6078
6099
|
let sessionContextFlag = "";
|
|
6079
6100
|
try {
|
|
6080
|
-
const ctxDir =
|
|
6081
|
-
|
|
6082
|
-
const ctxFile =
|
|
6101
|
+
const ctxDir = path19.join(os11.homedir(), ".exe-os", "session-cache");
|
|
6102
|
+
mkdirSync8(ctxDir, { recursive: true });
|
|
6103
|
+
const ctxFile = path19.join(ctxDir, `session-context-${sessionName}.md`);
|
|
6083
6104
|
const ctxContent = [
|
|
6084
6105
|
`## Session Context`,
|
|
6085
6106
|
`You are running in tmux session: ${sessionName}.`,
|
|
6086
6107
|
`Your parent coordinator session is ${exeSession}.`,
|
|
6087
6108
|
`Your employees (if any) use the -${exeSession} suffix.`
|
|
6088
6109
|
].join("\n");
|
|
6089
|
-
|
|
6110
|
+
writeFileSync10(ctxFile, ctxContent);
|
|
6090
6111
|
sessionContextFlag = ` --append-system-prompt-file ${ctxFile}`;
|
|
6091
6112
|
} catch {
|
|
6092
6113
|
}
|
|
@@ -6163,8 +6184,8 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
6163
6184
|
transport.pipeLog(sessionName, logFile);
|
|
6164
6185
|
try {
|
|
6165
6186
|
const mySession = getMySession();
|
|
6166
|
-
const dispatchInfo =
|
|
6167
|
-
|
|
6187
|
+
const dispatchInfo = path19.join(SESSION_CACHE, `dispatch-info-${sessionName}.json`);
|
|
6188
|
+
writeFileSync10(dispatchInfo, JSON.stringify({
|
|
6168
6189
|
dispatchedBy: mySession,
|
|
6169
6190
|
rootExe: exeSession,
|
|
6170
6191
|
provider: useBinSymlink ? ccProvider : useExeAgent ? opts.provider : useCodex ? "openai" : useOpencode ? "opencode" : "anthropic",
|
|
@@ -6238,15 +6259,15 @@ var init_tmux_routing = __esm({
|
|
|
6238
6259
|
init_intercom_queue();
|
|
6239
6260
|
init_plan_limits();
|
|
6240
6261
|
init_employees();
|
|
6241
|
-
SPAWN_LOCK_DIR =
|
|
6242
|
-
SESSION_CACHE =
|
|
6262
|
+
SPAWN_LOCK_DIR = path19.join(os11.homedir(), ".exe-os", "spawn-locks");
|
|
6263
|
+
SESSION_CACHE = path19.join(os11.homedir(), ".exe-os", "session-cache");
|
|
6243
6264
|
BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
|
|
6244
6265
|
VALID_SESSION_NAME = /^[a-z]+\d*-[a-zA-Z0-9_]+$/;
|
|
6245
6266
|
VERIFY_PANE_LINES = 200;
|
|
6246
6267
|
INTERCOM_DEBOUNCE_MS = 3e4;
|
|
6247
6268
|
CODEX_DEBOUNCE_MS = 12e4;
|
|
6248
|
-
INTERCOM_LOG2 =
|
|
6249
|
-
DEBOUNCE_FILE =
|
|
6269
|
+
INTERCOM_LOG2 = path19.join(os11.homedir(), ".exe-os", "intercom.log");
|
|
6270
|
+
DEBOUNCE_FILE = path19.join(SESSION_CACHE, "intercom-debounce.json");
|
|
6250
6271
|
DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
|
|
6251
6272
|
BUSY_PATTERN = /[✻✽✶✳·].*…|Running…|• Working|• Ran |• Explored|• Called|esc to interrupt/;
|
|
6252
6273
|
}
|
|
@@ -6296,14 +6317,14 @@ var init_memory = __esm({
|
|
|
6296
6317
|
|
|
6297
6318
|
// src/lib/keychain.ts
|
|
6298
6319
|
import { readFile as readFile4, writeFile as writeFile5, unlink, mkdir as mkdir4, chmod as chmod2 } from "fs/promises";
|
|
6299
|
-
import { existsSync as
|
|
6300
|
-
import
|
|
6301
|
-
import
|
|
6320
|
+
import { existsSync as existsSync16 } from "fs";
|
|
6321
|
+
import path20 from "path";
|
|
6322
|
+
import os12 from "os";
|
|
6302
6323
|
function getKeyDir() {
|
|
6303
|
-
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ??
|
|
6324
|
+
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path20.join(os12.homedir(), ".exe-os");
|
|
6304
6325
|
}
|
|
6305
6326
|
function getKeyPath() {
|
|
6306
|
-
return
|
|
6327
|
+
return path20.join(getKeyDir(), "master.key");
|
|
6307
6328
|
}
|
|
6308
6329
|
async function tryKeytar() {
|
|
6309
6330
|
try {
|
|
@@ -6324,9 +6345,9 @@ async function getMasterKey() {
|
|
|
6324
6345
|
}
|
|
6325
6346
|
}
|
|
6326
6347
|
const keyPath = getKeyPath();
|
|
6327
|
-
if (!
|
|
6348
|
+
if (!existsSync16(keyPath)) {
|
|
6328
6349
|
process.stderr.write(
|
|
6329
|
-
`[keychain] Key not found at ${keyPath} (HOME=${
|
|
6350
|
+
`[keychain] Key not found at ${keyPath} (HOME=${os12.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
|
|
6330
6351
|
`
|
|
6331
6352
|
);
|
|
6332
6353
|
return null;
|
|
@@ -6365,13 +6386,13 @@ __export(shard_manager_exports, {
|
|
|
6365
6386
|
listShards: () => listShards,
|
|
6366
6387
|
shardExists: () => shardExists
|
|
6367
6388
|
});
|
|
6368
|
-
import
|
|
6369
|
-
import { existsSync as
|
|
6389
|
+
import path21 from "path";
|
|
6390
|
+
import { existsSync as existsSync17, mkdirSync as mkdirSync9, readdirSync as readdirSync5 } from "fs";
|
|
6370
6391
|
import { createClient as createClient2 } from "@libsql/client";
|
|
6371
6392
|
function initShardManager(encryptionKey) {
|
|
6372
6393
|
_encryptionKey = encryptionKey;
|
|
6373
|
-
if (!
|
|
6374
|
-
|
|
6394
|
+
if (!existsSync17(SHARDS_DIR)) {
|
|
6395
|
+
mkdirSync9(SHARDS_DIR, { recursive: true });
|
|
6375
6396
|
}
|
|
6376
6397
|
_shardingEnabled = true;
|
|
6377
6398
|
if (_evictionTimer) clearInterval(_evictionTimer);
|
|
@@ -6400,7 +6421,7 @@ function getShardClient(projectName) {
|
|
|
6400
6421
|
while (_shards.size >= MAX_OPEN_SHARDS) {
|
|
6401
6422
|
evictLRU();
|
|
6402
6423
|
}
|
|
6403
|
-
const dbPath =
|
|
6424
|
+
const dbPath = path21.join(SHARDS_DIR, `${safeName}.db`);
|
|
6404
6425
|
const client = createClient2({
|
|
6405
6426
|
url: `file:${dbPath}`,
|
|
6406
6427
|
encryptionKey: _encryptionKey
|
|
@@ -6411,10 +6432,10 @@ function getShardClient(projectName) {
|
|
|
6411
6432
|
}
|
|
6412
6433
|
function shardExists(projectName) {
|
|
6413
6434
|
const safeName = projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
6414
|
-
return
|
|
6435
|
+
return existsSync17(path21.join(SHARDS_DIR, `${safeName}.db`));
|
|
6415
6436
|
}
|
|
6416
6437
|
function listShards() {
|
|
6417
|
-
if (!
|
|
6438
|
+
if (!existsSync17(SHARDS_DIR)) return [];
|
|
6418
6439
|
return readdirSync5(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
|
|
6419
6440
|
}
|
|
6420
6441
|
async function ensureShardSchema(client) {
|
|
@@ -6661,7 +6682,7 @@ var init_shard_manager = __esm({
|
|
|
6661
6682
|
"src/lib/shard-manager.ts"() {
|
|
6662
6683
|
"use strict";
|
|
6663
6684
|
init_config();
|
|
6664
|
-
SHARDS_DIR =
|
|
6685
|
+
SHARDS_DIR = path21.join(EXE_AI_DIR, "shards");
|
|
6665
6686
|
SHARD_IDLE_MS = 5 * 60 * 1e3;
|
|
6666
6687
|
MAX_OPEN_SHARDS = 10;
|
|
6667
6688
|
EVICTION_INTERVAL_MS = 60 * 1e3;
|
|
@@ -7430,6 +7451,115 @@ var init_store = __esm({
|
|
|
7430
7451
|
}
|
|
7431
7452
|
});
|
|
7432
7453
|
|
|
7454
|
+
// src/lib/git-staleness.ts
|
|
7455
|
+
var git_staleness_exports = {};
|
|
7456
|
+
__export(git_staleness_exports, {
|
|
7457
|
+
clearSessionFileReads: () => clearSessionFileReads,
|
|
7458
|
+
detectStaleFiles: () => detectStaleFiles,
|
|
7459
|
+
recordFileRead: () => recordFileRead
|
|
7460
|
+
});
|
|
7461
|
+
import { execSync as execSync8 } from "child_process";
|
|
7462
|
+
import path22 from "path";
|
|
7463
|
+
function getHeadCommit(cwd) {
|
|
7464
|
+
try {
|
|
7465
|
+
return execSync8("git rev-parse --short HEAD", {
|
|
7466
|
+
cwd,
|
|
7467
|
+
timeout: GIT_TIMEOUT_MS,
|
|
7468
|
+
encoding: "utf-8"
|
|
7469
|
+
}).trim() || null;
|
|
7470
|
+
} catch {
|
|
7471
|
+
return null;
|
|
7472
|
+
}
|
|
7473
|
+
}
|
|
7474
|
+
function normalizeTrackedPath(cwd, filePath) {
|
|
7475
|
+
const resolved = path22.resolve(cwd, filePath);
|
|
7476
|
+
const relative = path22.relative(cwd, resolved);
|
|
7477
|
+
if (!relative || relative.startsWith("..") || path22.isAbsolute(relative)) {
|
|
7478
|
+
return null;
|
|
7479
|
+
}
|
|
7480
|
+
return relative;
|
|
7481
|
+
}
|
|
7482
|
+
function formatGitSummary(filePath, summary) {
|
|
7483
|
+
const match = summary.trim().match(/^([a-f0-9]+)\s+([^:]+):\s+(.+)$/i);
|
|
7484
|
+
if (!match) return `${filePath} (${summary.trim()})`;
|
|
7485
|
+
const [, hash, author, subject] = match;
|
|
7486
|
+
return `${filePath} (modified by ${author} in commit ${hash}: "${subject}")`;
|
|
7487
|
+
}
|
|
7488
|
+
async function recordFileRead(sessionUuid, agentId, cwd, filePath) {
|
|
7489
|
+
if (!sessionUuid || !filePath) return;
|
|
7490
|
+
const trackedPath = normalizeTrackedPath(cwd, filePath);
|
|
7491
|
+
if (!trackedPath) return;
|
|
7492
|
+
const client = getClient();
|
|
7493
|
+
await client.execute({
|
|
7494
|
+
sql: `INSERT INTO agent_file_reads (session_uuid, agent_id, file_path, read_at, commit_hash)
|
|
7495
|
+
VALUES (?, ?, ?, ?, ?)
|
|
7496
|
+
ON CONFLICT(session_uuid, file_path) DO UPDATE SET
|
|
7497
|
+
read_at = excluded.read_at,
|
|
7498
|
+
commit_hash = excluded.commit_hash`,
|
|
7499
|
+
args: [
|
|
7500
|
+
sessionUuid,
|
|
7501
|
+
agentId,
|
|
7502
|
+
trackedPath,
|
|
7503
|
+
(/* @__PURE__ */ new Date()).toISOString(),
|
|
7504
|
+
getHeadCommit(cwd)
|
|
7505
|
+
]
|
|
7506
|
+
});
|
|
7507
|
+
}
|
|
7508
|
+
async function detectStaleFiles(agentId, cwd) {
|
|
7509
|
+
const client = getClient();
|
|
7510
|
+
const recentCutoff = new Date(Date.now() - RECENT_READ_LOOKBACK_MS).toISOString();
|
|
7511
|
+
const result = await client.execute({
|
|
7512
|
+
sql: `SELECT file_path, MAX(read_at) AS read_at
|
|
7513
|
+
FROM agent_file_reads
|
|
7514
|
+
WHERE agent_id = ? AND read_at >= ?
|
|
7515
|
+
GROUP BY file_path
|
|
7516
|
+
ORDER BY MAX(read_at) DESC
|
|
7517
|
+
LIMIT 10`,
|
|
7518
|
+
args: [agentId, recentCutoff]
|
|
7519
|
+
});
|
|
7520
|
+
const stale = [];
|
|
7521
|
+
for (const row of result.rows) {
|
|
7522
|
+
if (stale.length >= MAX_STALE_FILES) break;
|
|
7523
|
+
const record = row;
|
|
7524
|
+
const filePath = String(record.file_path ?? "");
|
|
7525
|
+
const readAt = String(record.read_at ?? "");
|
|
7526
|
+
if (!filePath || !readAt) continue;
|
|
7527
|
+
try {
|
|
7528
|
+
const gitSummary = execSync8(
|
|
7529
|
+
`git log -1 --oneline --after=${JSON.stringify(readAt)} --format="%h %an: %s" -- ${JSON.stringify(filePath)}`,
|
|
7530
|
+
{
|
|
7531
|
+
cwd,
|
|
7532
|
+
timeout: GIT_TIMEOUT_MS,
|
|
7533
|
+
encoding: "utf-8"
|
|
7534
|
+
}
|
|
7535
|
+
).trim();
|
|
7536
|
+
if (gitSummary) {
|
|
7537
|
+
stale.push(formatGitSummary(filePath, gitSummary));
|
|
7538
|
+
}
|
|
7539
|
+
} catch {
|
|
7540
|
+
}
|
|
7541
|
+
}
|
|
7542
|
+
return stale.slice(0, MAX_STALE_FILES);
|
|
7543
|
+
}
|
|
7544
|
+
async function clearSessionFileReads(sessionUuid) {
|
|
7545
|
+
if (!sessionUuid) return;
|
|
7546
|
+
const client = getClient();
|
|
7547
|
+
await client.execute({
|
|
7548
|
+
sql: "DELETE FROM agent_file_reads WHERE session_uuid = ?",
|
|
7549
|
+
args: [sessionUuid]
|
|
7550
|
+
});
|
|
7551
|
+
}
|
|
7552
|
+
var RECENT_READ_LOOKBACK_MS, MAX_STALE_FILES, GIT_TIMEOUT_MS;
|
|
7553
|
+
var init_git_staleness = __esm({
|
|
7554
|
+
"src/lib/git-staleness.ts"() {
|
|
7555
|
+
"use strict";
|
|
7556
|
+
init_database();
|
|
7557
|
+
RECENT_READ_LOOKBACK_MS = 24 * 60 * 60 * 1e3;
|
|
7558
|
+
MAX_STALE_FILES = 10;
|
|
7559
|
+
GIT_TIMEOUT_MS = 400;
|
|
7560
|
+
}
|
|
7561
|
+
});
|
|
7562
|
+
|
|
7433
7563
|
// src/lib/git-task-sweep.ts
|
|
7434
7564
|
var git_task_sweep_exports = {};
|
|
7435
7565
|
__export(git_task_sweep_exports, {
|
|
@@ -7439,7 +7569,7 @@ __export(git_task_sweep_exports, {
|
|
|
7439
7569
|
matchScore: () => matchScore,
|
|
7440
7570
|
sweepTasks: () => sweepTasks
|
|
7441
7571
|
});
|
|
7442
|
-
import { execSync as
|
|
7572
|
+
import { execSync as execSync9 } from "child_process";
|
|
7443
7573
|
function extractKeywords(text) {
|
|
7444
7574
|
return text.toLowerCase().replace(/[^a-z0-9\s-]/g, " ").split(/\s+/).filter((w) => w.length >= 3 && !STOP_WORDS.has(w));
|
|
7445
7575
|
}
|
|
@@ -7468,7 +7598,7 @@ function matchScore(task, commitMessage, changedFiles) {
|
|
|
7468
7598
|
function getRecentCommits(limit = DEFAULT_COMMIT_LIMIT) {
|
|
7469
7599
|
try {
|
|
7470
7600
|
const SEPARATOR = "<<SEP>>";
|
|
7471
|
-
const output =
|
|
7601
|
+
const output = execSync9(
|
|
7472
7602
|
`git log --format="%h${SEPARATOR}%s${SEPARATOR}%aI" --name-only -n ${limit} -z`,
|
|
7473
7603
|
{ encoding: "utf8", timeout: 1e4 }
|
|
7474
7604
|
);
|
|
@@ -7751,6 +7881,28 @@ function getActiveAgent() {
|
|
|
7751
7881
|
};
|
|
7752
7882
|
}
|
|
7753
7883
|
|
|
7884
|
+
// src/adapters/claude/session-key.ts
|
|
7885
|
+
init_session_key();
|
|
7886
|
+
|
|
7887
|
+
// src/lib/cache-warmth.ts
|
|
7888
|
+
import os3 from "os";
|
|
7889
|
+
import path4 from "path";
|
|
7890
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync4, unlinkSync as unlinkSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
7891
|
+
var CACHE_TTL_MS = 5 * 60 * 1e3;
|
|
7892
|
+
var CACHE_DIR2 = path4.join(
|
|
7893
|
+
process.env.EXE_OS_DIR ?? path4.join(os3.homedir(), ".exe-os"),
|
|
7894
|
+
"session-cache"
|
|
7895
|
+
);
|
|
7896
|
+
function getStatePath(sessionKey) {
|
|
7897
|
+
return path4.join(CACHE_DIR2, `cache-warmth-${sessionKey}.json`);
|
|
7898
|
+
}
|
|
7899
|
+
function clearCacheState(sessionKey) {
|
|
7900
|
+
try {
|
|
7901
|
+
unlinkSync3(getStatePath(sessionKey));
|
|
7902
|
+
} catch {
|
|
7903
|
+
}
|
|
7904
|
+
}
|
|
7905
|
+
|
|
7754
7906
|
// src/adapters/claude/hooks/session-end.ts
|
|
7755
7907
|
init_task_scope();
|
|
7756
7908
|
init_employees();
|
|
@@ -7803,6 +7955,11 @@ Orphaned tasks at session end: ${orphanResult.rows.map((r) => `"${String(r.title
|
|
|
7803
7955
|
vector: null
|
|
7804
7956
|
});
|
|
7805
7957
|
await flushBatch2();
|
|
7958
|
+
try {
|
|
7959
|
+
const { clearSessionFileReads: clearSessionFileReads2 } = await Promise.resolve().then(() => (init_git_staleness(), git_staleness_exports));
|
|
7960
|
+
await clearSessionFileReads2(data.session_id);
|
|
7961
|
+
} catch {
|
|
7962
|
+
}
|
|
7806
7963
|
if (!canCoordinate(agent.agentId, agent.agentRole)) {
|
|
7807
7964
|
const inProgress = orphanResult.rows.filter((r) => String(r.status) === "in_progress");
|
|
7808
7965
|
if (inProgress.length > 0) {
|
|
@@ -7891,6 +8048,7 @@ Orphaned tasks at session end: ${orphanResult.rows.map((r) => `"${String(r.title
|
|
|
7891
8048
|
}
|
|
7892
8049
|
}
|
|
7893
8050
|
clearActiveAgent();
|
|
8051
|
+
clearCacheState(getSessionKey());
|
|
7894
8052
|
} catch {
|
|
7895
8053
|
}
|
|
7896
8054
|
clearTimeout(timeout);
|