@askexenow/exe-os 0.9.7 → 0.9.8
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 +754 -79
- package/dist/bin/backfill-responses.js +752 -77
- package/dist/bin/backfill-vectors.js +752 -77
- package/dist/bin/cleanup-stale-review-tasks.js +657 -35
- package/dist/bin/cli.js +1388 -605
- package/dist/bin/exe-agent-config.js +123 -95
- package/dist/bin/exe-agent.js +41 -25
- package/dist/bin/exe-assign.js +732 -57
- package/dist/bin/exe-boot.js +784 -153
- package/dist/bin/exe-call.js +209 -138
- package/dist/bin/exe-cloud.js +35 -12
- package/dist/bin/exe-dispatch.js +692 -70
- package/dist/bin/exe-doctor.js +648 -26
- package/dist/bin/exe-export-behaviors.js +650 -20
- package/dist/bin/exe-forget.js +635 -13
- package/dist/bin/exe-gateway.js +1053 -271
- package/dist/bin/exe-heartbeat.js +665 -43
- package/dist/bin/exe-kill.js +646 -16
- package/dist/bin/exe-launch-agent.js +887 -97
- package/dist/bin/exe-link.js +658 -43
- package/dist/bin/exe-new-employee.js +378 -177
- package/dist/bin/exe-pending-messages.js +656 -34
- package/dist/bin/exe-pending-notifications.js +635 -13
- package/dist/bin/exe-pending-reviews.js +659 -37
- package/dist/bin/exe-rename.js +645 -30
- package/dist/bin/exe-review.js +635 -13
- package/dist/bin/exe-search.js +771 -88
- package/dist/bin/exe-session-cleanup.js +834 -150
- package/dist/bin/exe-settings.js +127 -91
- package/dist/bin/exe-start-codex.js +729 -94
- package/dist/bin/exe-start-opencode.js +717 -82
- package/dist/bin/exe-status.js +657 -35
- package/dist/bin/exe-team.js +635 -13
- package/dist/bin/git-sweep.js +720 -89
- package/dist/bin/graph-backfill.js +643 -13
- package/dist/bin/graph-export.js +646 -16
- package/dist/bin/install.js +596 -193
- package/dist/bin/scan-tasks.js +724 -93
- package/dist/bin/setup.js +1038 -210
- package/dist/bin/shard-migrate.js +645 -15
- package/dist/bin/wiki-sync.js +646 -16
- package/dist/gateway/index.js +1027 -245
- package/dist/hooks/bug-report-worker.js +891 -170
- package/dist/hooks/commit-complete.js +718 -87
- package/dist/hooks/error-recall.js +776 -93
- package/dist/hooks/exe-heartbeat-hook.js +85 -71
- package/dist/hooks/ingest-worker.js +840 -156
- package/dist/hooks/ingest.js +90 -73
- package/dist/hooks/instructions-loaded.js +669 -38
- package/dist/hooks/notification.js +661 -30
- package/dist/hooks/post-compact.js +674 -43
- package/dist/hooks/pre-compact.js +718 -87
- package/dist/hooks/pre-tool-use.js +872 -125
- package/dist/hooks/prompt-ingest-worker.js +758 -83
- package/dist/hooks/prompt-submit.js +1060 -319
- package/dist/hooks/response-ingest-worker.js +758 -83
- package/dist/hooks/session-end.js +721 -90
- package/dist/hooks/session-start.js +1031 -207
- package/dist/hooks/stop.js +680 -49
- package/dist/hooks/subagent-stop.js +674 -43
- package/dist/hooks/summary-worker.js +816 -132
- package/dist/index.js +1015 -232
- package/dist/lib/cloud-sync.js +663 -48
- package/dist/lib/consolidation.js +26 -3
- package/dist/lib/database.js +626 -18
- package/dist/lib/db.js +2261 -0
- package/dist/lib/device-registry.js +640 -25
- package/dist/lib/embedder.js +96 -43
- package/dist/lib/employee-templates.js +16 -0
- package/dist/lib/employees.js +259 -83
- package/dist/lib/exe-daemon-client.js +101 -63
- package/dist/lib/exe-daemon.js +894 -162
- package/dist/lib/hybrid-search.js +771 -88
- package/dist/lib/identity.js +27 -7
- package/dist/lib/messaging.js +55 -28
- package/dist/lib/reminders.js +21 -1
- package/dist/lib/schedules.js +636 -14
- package/dist/lib/skill-learning.js +21 -1
- package/dist/lib/store.js +643 -13
- package/dist/lib/task-router.js +82 -71
- package/dist/lib/tasks.js +98 -71
- package/dist/lib/tmux-routing.js +87 -60
- package/dist/lib/token-spend.js +26 -6
- package/dist/mcp/server.js +1784 -458
- package/dist/mcp/tools/complete-reminder.js +21 -1
- package/dist/mcp/tools/create-reminder.js +21 -1
- package/dist/mcp/tools/create-task.js +290 -164
- package/dist/mcp/tools/deactivate-behavior.js +24 -4
- package/dist/mcp/tools/list-reminders.js +21 -1
- package/dist/mcp/tools/list-tasks.js +195 -38
- package/dist/mcp/tools/send-message.js +58 -31
- package/dist/mcp/tools/update-task.js +75 -48
- package/dist/runtime/index.js +720 -89
- package/dist/tui/App.js +853 -123
- package/package.json +3 -2
package/dist/lib/tmux-routing.js
CHANGED
|
@@ -731,7 +731,7 @@ function isMultiInstance(agentName, employees) {
|
|
|
731
731
|
if (!emp) return false;
|
|
732
732
|
return MULTI_INSTANCE_ROLES.has(emp.role.toLowerCase());
|
|
733
733
|
}
|
|
734
|
-
var EMPLOYEES_PATH, DEFAULT_COORDINATOR_TEMPLATE_NAME, COORDINATOR_ROLE, MULTI_INSTANCE_ROLES;
|
|
734
|
+
var EMPLOYEES_PATH, DEFAULT_COORDINATOR_TEMPLATE_NAME, COORDINATOR_ROLE, MULTI_INSTANCE_ROLES, IDENTITY_DIR;
|
|
735
735
|
var init_employees = __esm({
|
|
736
736
|
"src/lib/employees.ts"() {
|
|
737
737
|
"use strict";
|
|
@@ -740,15 +740,40 @@ var init_employees = __esm({
|
|
|
740
740
|
DEFAULT_COORDINATOR_TEMPLATE_NAME = "exe";
|
|
741
741
|
COORDINATOR_ROLE = "COO";
|
|
742
742
|
MULTI_INSTANCE_ROLES = /* @__PURE__ */ new Set(["principal engineer", "content production specialist", "staff code reviewer"]);
|
|
743
|
+
IDENTITY_DIR = path5.join(EXE_AI_DIR, "identity");
|
|
744
|
+
}
|
|
745
|
+
});
|
|
746
|
+
|
|
747
|
+
// src/lib/database-adapter.ts
|
|
748
|
+
import os5 from "os";
|
|
749
|
+
import path6 from "path";
|
|
750
|
+
import { createRequire } from "module";
|
|
751
|
+
import { pathToFileURL } from "url";
|
|
752
|
+
var BOOLEAN_COLUMNS_BY_TABLE, BOOLEAN_COLUMN_NAMES;
|
|
753
|
+
var init_database_adapter = __esm({
|
|
754
|
+
"src/lib/database-adapter.ts"() {
|
|
755
|
+
"use strict";
|
|
756
|
+
BOOLEAN_COLUMNS_BY_TABLE = {
|
|
757
|
+
memories: /* @__PURE__ */ new Set(["has_error", "draft"]),
|
|
758
|
+
behaviors: /* @__PURE__ */ new Set(["active"]),
|
|
759
|
+
notifications: /* @__PURE__ */ new Set(["read"]),
|
|
760
|
+
users: /* @__PURE__ */ new Set(["has_personal_memory"])
|
|
761
|
+
};
|
|
762
|
+
BOOLEAN_COLUMN_NAMES = new Set(
|
|
763
|
+
Object.values(BOOLEAN_COLUMNS_BY_TABLE).flatMap((cols) => [...cols])
|
|
764
|
+
);
|
|
743
765
|
}
|
|
744
766
|
});
|
|
745
767
|
|
|
746
768
|
// src/lib/database.ts
|
|
747
769
|
import { createClient } from "@libsql/client";
|
|
748
770
|
function getClient() {
|
|
749
|
-
if (!
|
|
771
|
+
if (!_adapterClient) {
|
|
750
772
|
throw new Error("Database client not initialized. Call initDatabase() first.");
|
|
751
773
|
}
|
|
774
|
+
if (process.env.DATABASE_URL) {
|
|
775
|
+
return _adapterClient;
|
|
776
|
+
}
|
|
752
777
|
if (process.env.EXE_IS_DAEMON === "1") {
|
|
753
778
|
return _resilientClient;
|
|
754
779
|
}
|
|
@@ -757,30 +782,32 @@ function getClient() {
|
|
|
757
782
|
}
|
|
758
783
|
return _resilientClient;
|
|
759
784
|
}
|
|
760
|
-
var _resilientClient, _daemonClient;
|
|
785
|
+
var _resilientClient, _daemonClient, _adapterClient;
|
|
761
786
|
var init_database = __esm({
|
|
762
787
|
"src/lib/database.ts"() {
|
|
763
788
|
"use strict";
|
|
764
789
|
init_db_retry();
|
|
765
790
|
init_employees();
|
|
791
|
+
init_database_adapter();
|
|
766
792
|
_resilientClient = null;
|
|
767
793
|
_daemonClient = null;
|
|
794
|
+
_adapterClient = null;
|
|
768
795
|
}
|
|
769
796
|
});
|
|
770
797
|
|
|
771
798
|
// src/lib/license.ts
|
|
772
799
|
import { readFileSync as readFileSync6, writeFileSync as writeFileSync5, existsSync as existsSync6, mkdirSync as mkdirSync4 } from "fs";
|
|
773
800
|
import { randomUUID } from "crypto";
|
|
774
|
-
import
|
|
801
|
+
import path7 from "path";
|
|
775
802
|
import { jwtVerify, importSPKI } from "jose";
|
|
776
803
|
var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH, PLAN_LIMITS;
|
|
777
804
|
var init_license = __esm({
|
|
778
805
|
"src/lib/license.ts"() {
|
|
779
806
|
"use strict";
|
|
780
807
|
init_config();
|
|
781
|
-
LICENSE_PATH =
|
|
782
|
-
CACHE_PATH =
|
|
783
|
-
DEVICE_ID_PATH =
|
|
808
|
+
LICENSE_PATH = path7.join(EXE_AI_DIR, "license.key");
|
|
809
|
+
CACHE_PATH = path7.join(EXE_AI_DIR, "license-cache.json");
|
|
810
|
+
DEVICE_ID_PATH = path7.join(EXE_AI_DIR, "device-id");
|
|
784
811
|
PLAN_LIMITS = {
|
|
785
812
|
free: { devices: 1, employees: 1, memories: 5e3 },
|
|
786
813
|
pro: { devices: 3, employees: 5, memories: 1e5 },
|
|
@@ -793,7 +820,7 @@ var init_license = __esm({
|
|
|
793
820
|
|
|
794
821
|
// src/lib/plan-limits.ts
|
|
795
822
|
import { readFileSync as readFileSync7, existsSync as existsSync7 } from "fs";
|
|
796
|
-
import
|
|
823
|
+
import path8 from "path";
|
|
797
824
|
function getLicenseSync() {
|
|
798
825
|
try {
|
|
799
826
|
if (!existsSync7(CACHE_PATH2)) return freeLicense();
|
|
@@ -865,14 +892,14 @@ var init_plan_limits = __esm({
|
|
|
865
892
|
this.name = "PlanLimitError";
|
|
866
893
|
}
|
|
867
894
|
};
|
|
868
|
-
CACHE_PATH2 =
|
|
895
|
+
CACHE_PATH2 = path8.join(EXE_AI_DIR, "license-cache.json");
|
|
869
896
|
}
|
|
870
897
|
});
|
|
871
898
|
|
|
872
899
|
// src/lib/notifications.ts
|
|
873
900
|
import crypto from "crypto";
|
|
874
|
-
import
|
|
875
|
-
import
|
|
901
|
+
import path9 from "path";
|
|
902
|
+
import os6 from "os";
|
|
876
903
|
import {
|
|
877
904
|
readFileSync as readFileSync8,
|
|
878
905
|
readdirSync,
|
|
@@ -1036,8 +1063,8 @@ var init_state_bus = __esm({
|
|
|
1036
1063
|
|
|
1037
1064
|
// src/lib/tasks-crud.ts
|
|
1038
1065
|
import crypto3 from "crypto";
|
|
1039
|
-
import
|
|
1040
|
-
import
|
|
1066
|
+
import path10 from "path";
|
|
1067
|
+
import os7 from "os";
|
|
1041
1068
|
import { execSync as execSync4 } from "child_process";
|
|
1042
1069
|
import { mkdir as mkdir3, writeFile as writeFile3, appendFile } from "fs/promises";
|
|
1043
1070
|
import { existsSync as existsSync9, readFileSync as readFileSync9 } from "fs";
|
|
@@ -1215,8 +1242,8 @@ ${laneWarning}` : laneWarning;
|
|
|
1215
1242
|
}
|
|
1216
1243
|
if (input.baseDir) {
|
|
1217
1244
|
try {
|
|
1218
|
-
await mkdir3(
|
|
1219
|
-
await mkdir3(
|
|
1245
|
+
await mkdir3(path10.join(input.baseDir, "exe", "output"), { recursive: true });
|
|
1246
|
+
await mkdir3(path10.join(input.baseDir, "exe", "research"), { recursive: true });
|
|
1220
1247
|
await ensureArchitectureDoc(input.baseDir, input.projectName);
|
|
1221
1248
|
await ensureGitignoreExe(input.baseDir);
|
|
1222
1249
|
} catch {
|
|
@@ -1252,9 +1279,9 @@ ${laneWarning}` : laneWarning;
|
|
|
1252
1279
|
});
|
|
1253
1280
|
if (input.baseDir) {
|
|
1254
1281
|
try {
|
|
1255
|
-
const EXE_OS_DIR =
|
|
1256
|
-
const mdPath =
|
|
1257
|
-
const mdDir =
|
|
1282
|
+
const EXE_OS_DIR = path10.join(os7.homedir(), ".exe-os");
|
|
1283
|
+
const mdPath = path10.join(EXE_OS_DIR, taskFile);
|
|
1284
|
+
const mdDir = path10.dirname(mdPath);
|
|
1258
1285
|
if (!existsSync9(mdDir)) await mkdir3(mdDir, { recursive: true });
|
|
1259
1286
|
const reviewer = input.reviewer ?? input.assignedBy;
|
|
1260
1287
|
const mdContent = `# ${input.title}
|
|
@@ -1555,7 +1582,7 @@ async function deleteTaskCore(taskId, _baseDir) {
|
|
|
1555
1582
|
return { taskFile, assignedTo, assignedBy, taskSlug };
|
|
1556
1583
|
}
|
|
1557
1584
|
async function ensureArchitectureDoc(baseDir, projectName) {
|
|
1558
|
-
const archPath =
|
|
1585
|
+
const archPath = path10.join(baseDir, "exe", "ARCHITECTURE.md");
|
|
1559
1586
|
try {
|
|
1560
1587
|
if (existsSync9(archPath)) return;
|
|
1561
1588
|
const template = [
|
|
@@ -1590,7 +1617,7 @@ async function ensureArchitectureDoc(baseDir, projectName) {
|
|
|
1590
1617
|
}
|
|
1591
1618
|
}
|
|
1592
1619
|
async function ensureGitignoreExe(baseDir) {
|
|
1593
|
-
const gitignorePath =
|
|
1620
|
+
const gitignorePath = path10.join(baseDir, ".gitignore");
|
|
1594
1621
|
try {
|
|
1595
1622
|
if (existsSync9(gitignorePath)) {
|
|
1596
1623
|
const content = readFileSync9(gitignorePath, "utf-8");
|
|
@@ -1624,13 +1651,13 @@ var init_tasks_crud = __esm({
|
|
|
1624
1651
|
});
|
|
1625
1652
|
|
|
1626
1653
|
// src/lib/tasks-review.ts
|
|
1627
|
-
import
|
|
1654
|
+
import path11 from "path";
|
|
1628
1655
|
import { existsSync as existsSync10, readdirSync as readdirSync2, unlinkSync as unlinkSync3 } from "fs";
|
|
1629
1656
|
async function countPendingReviews(sessionScope) {
|
|
1630
1657
|
const client = getClient();
|
|
1631
1658
|
if (sessionScope) {
|
|
1632
1659
|
const result2 = await client.execute({
|
|
1633
|
-
sql: "SELECT COUNT(*) as cnt FROM tasks WHERE status = 'needs_review' AND
|
|
1660
|
+
sql: "SELECT COUNT(*) as cnt FROM tasks WHERE status = 'needs_review' AND session_scope = ?",
|
|
1634
1661
|
args: [sessionScope]
|
|
1635
1662
|
});
|
|
1636
1663
|
return Number(result2.rows[0]?.cnt) || 0;
|
|
@@ -1806,11 +1833,11 @@ async function cleanupReviewFile(row, taskFile, _baseDir) {
|
|
|
1806
1833
|
);
|
|
1807
1834
|
}
|
|
1808
1835
|
try {
|
|
1809
|
-
const cacheDir =
|
|
1836
|
+
const cacheDir = path11.join(EXE_AI_DIR, "session-cache");
|
|
1810
1837
|
if (existsSync10(cacheDir)) {
|
|
1811
1838
|
for (const f of readdirSync2(cacheDir)) {
|
|
1812
1839
|
if (f.startsWith("review-notified-")) {
|
|
1813
|
-
unlinkSync3(
|
|
1840
|
+
unlinkSync3(path11.join(cacheDir, f));
|
|
1814
1841
|
}
|
|
1815
1842
|
}
|
|
1816
1843
|
}
|
|
@@ -1831,7 +1858,7 @@ var init_tasks_review = __esm({
|
|
|
1831
1858
|
});
|
|
1832
1859
|
|
|
1833
1860
|
// src/lib/tasks-chain.ts
|
|
1834
|
-
import
|
|
1861
|
+
import path12 from "path";
|
|
1835
1862
|
import { readFile as readFile3, writeFile as writeFile4 } from "fs/promises";
|
|
1836
1863
|
async function cascadeUnblock(taskId, baseDir, now) {
|
|
1837
1864
|
const client = getClient();
|
|
@@ -1848,7 +1875,7 @@ async function cascadeUnblock(taskId, baseDir, now) {
|
|
|
1848
1875
|
});
|
|
1849
1876
|
for (const ur of unblockedRows.rows) {
|
|
1850
1877
|
try {
|
|
1851
|
-
const ubFile =
|
|
1878
|
+
const ubFile = path12.join(baseDir, String(ur.task_file));
|
|
1852
1879
|
let ubContent = await readFile3(ubFile, "utf-8");
|
|
1853
1880
|
ubContent = ubContent.replace(/\*\*Status:\*\* blocked/, "**Status:** open");
|
|
1854
1881
|
ubContent = ubContent.replace(/\n\*\*Blocked by:\*\*.*\n/, "\n");
|
|
@@ -1917,7 +1944,7 @@ var init_tasks_chain = __esm({
|
|
|
1917
1944
|
|
|
1918
1945
|
// src/lib/project-name.ts
|
|
1919
1946
|
import { execSync as execSync5 } from "child_process";
|
|
1920
|
-
import
|
|
1947
|
+
import path13 from "path";
|
|
1921
1948
|
function getProjectName(cwd) {
|
|
1922
1949
|
const dir = cwd ?? process.cwd();
|
|
1923
1950
|
if (_cached2 && _cachedCwd === dir) return _cached2;
|
|
@@ -1930,7 +1957,7 @@ function getProjectName(cwd) {
|
|
|
1930
1957
|
timeout: 2e3,
|
|
1931
1958
|
stdio: ["pipe", "pipe", "pipe"]
|
|
1932
1959
|
}).trim();
|
|
1933
|
-
repoRoot =
|
|
1960
|
+
repoRoot = path13.dirname(gitCommonDir);
|
|
1934
1961
|
} catch {
|
|
1935
1962
|
repoRoot = execSync5("git rev-parse --show-toplevel", {
|
|
1936
1963
|
cwd: dir,
|
|
@@ -1939,11 +1966,11 @@ function getProjectName(cwd) {
|
|
|
1939
1966
|
stdio: ["pipe", "pipe", "pipe"]
|
|
1940
1967
|
}).trim();
|
|
1941
1968
|
}
|
|
1942
|
-
_cached2 =
|
|
1969
|
+
_cached2 = path13.basename(repoRoot);
|
|
1943
1970
|
_cachedCwd = dir;
|
|
1944
1971
|
return _cached2;
|
|
1945
1972
|
} catch {
|
|
1946
|
-
_cached2 =
|
|
1973
|
+
_cached2 = path13.basename(dir);
|
|
1947
1974
|
_cachedCwd = dir;
|
|
1948
1975
|
return _cached2;
|
|
1949
1976
|
}
|
|
@@ -2416,7 +2443,7 @@ __export(tasks_exports, {
|
|
|
2416
2443
|
updateTaskStatus: () => updateTaskStatus,
|
|
2417
2444
|
writeCheckpoint: () => writeCheckpoint
|
|
2418
2445
|
});
|
|
2419
|
-
import
|
|
2446
|
+
import path14 from "path";
|
|
2420
2447
|
import { writeFileSync as writeFileSync6, mkdirSync as mkdirSync5, unlinkSync as unlinkSync4 } from "fs";
|
|
2421
2448
|
async function createTask(input) {
|
|
2422
2449
|
const result = await createTaskCore(input);
|
|
@@ -2436,8 +2463,8 @@ async function updateTask(input) {
|
|
|
2436
2463
|
const { row, taskFile, now, taskId } = await updateTaskStatus(input);
|
|
2437
2464
|
try {
|
|
2438
2465
|
const agent = String(row.assigned_to);
|
|
2439
|
-
const cacheDir =
|
|
2440
|
-
const cachePath =
|
|
2466
|
+
const cacheDir = path14.join(EXE_AI_DIR, "session-cache");
|
|
2467
|
+
const cachePath = path14.join(cacheDir, `current-task-${agent}.json`);
|
|
2441
2468
|
if (input.status === "in_progress") {
|
|
2442
2469
|
mkdirSync5(cacheDir, { recursive: true });
|
|
2443
2470
|
writeFileSync6(cachePath, JSON.stringify({ taskId, title: String(row.title) }));
|
|
@@ -2908,12 +2935,12 @@ __export(tmux_routing_exports, {
|
|
|
2908
2935
|
});
|
|
2909
2936
|
import { execFileSync as execFileSync2, execSync as execSync6 } from "child_process";
|
|
2910
2937
|
import { readFileSync as readFileSync10, writeFileSync as writeFileSync7, mkdirSync as mkdirSync6, existsSync as existsSync11, appendFileSync, readdirSync as readdirSync3 } from "fs";
|
|
2911
|
-
import
|
|
2912
|
-
import
|
|
2938
|
+
import path15 from "path";
|
|
2939
|
+
import os8 from "os";
|
|
2913
2940
|
import { fileURLToPath } from "url";
|
|
2914
2941
|
import { unlinkSync as unlinkSync5 } from "fs";
|
|
2915
2942
|
function spawnLockPath(sessionName) {
|
|
2916
|
-
return
|
|
2943
|
+
return path15.join(SPAWN_LOCK_DIR, `${sessionName}.lock`);
|
|
2917
2944
|
}
|
|
2918
2945
|
function isProcessAlive(pid) {
|
|
2919
2946
|
try {
|
|
@@ -2950,8 +2977,8 @@ function releaseSpawnLock(sessionName) {
|
|
|
2950
2977
|
function resolveBehaviorsExporterScript() {
|
|
2951
2978
|
try {
|
|
2952
2979
|
const thisFile = fileURLToPath(import.meta.url);
|
|
2953
|
-
const scriptPath =
|
|
2954
|
-
|
|
2980
|
+
const scriptPath = path15.join(
|
|
2981
|
+
path15.dirname(thisFile),
|
|
2955
2982
|
"..",
|
|
2956
2983
|
"bin",
|
|
2957
2984
|
"exe-export-behaviors.js"
|
|
@@ -3026,7 +3053,7 @@ function registerParentExe(sessionKey, parentExe, dispatchedBy) {
|
|
|
3026
3053
|
mkdirSync6(SESSION_CACHE, { recursive: true });
|
|
3027
3054
|
}
|
|
3028
3055
|
const rootExe = extractRootExe(parentExe) ?? parentExe;
|
|
3029
|
-
const filePath =
|
|
3056
|
+
const filePath = path15.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`);
|
|
3030
3057
|
writeFileSync7(filePath, JSON.stringify({
|
|
3031
3058
|
parentExe: rootExe,
|
|
3032
3059
|
dispatchedBy: dispatchedBy || rootExe,
|
|
@@ -3035,7 +3062,7 @@ function registerParentExe(sessionKey, parentExe, dispatchedBy) {
|
|
|
3035
3062
|
}
|
|
3036
3063
|
function getParentExe(sessionKey) {
|
|
3037
3064
|
try {
|
|
3038
|
-
const data = JSON.parse(readFileSync10(
|
|
3065
|
+
const data = JSON.parse(readFileSync10(path15.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
|
|
3039
3066
|
return data.parentExe || null;
|
|
3040
3067
|
} catch {
|
|
3041
3068
|
return null;
|
|
@@ -3044,7 +3071,7 @@ function getParentExe(sessionKey) {
|
|
|
3044
3071
|
function getDispatchedBy(sessionKey) {
|
|
3045
3072
|
try {
|
|
3046
3073
|
const data = JSON.parse(readFileSync10(
|
|
3047
|
-
|
|
3074
|
+
path15.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`),
|
|
3048
3075
|
"utf8"
|
|
3049
3076
|
));
|
|
3050
3077
|
return data.dispatchedBy ?? data.parentExe ?? null;
|
|
@@ -3230,7 +3257,7 @@ function sendIntercom(targetSession) {
|
|
|
3230
3257
|
try {
|
|
3231
3258
|
const rawAgent = targetSession.split("-")[0] ?? targetSession;
|
|
3232
3259
|
const agent = baseAgentName(rawAgent);
|
|
3233
|
-
const markerPath =
|
|
3260
|
+
const markerPath = path15.join(SESSION_CACHE, `current-task-${agent}.json`);
|
|
3234
3261
|
if (existsSync11(markerPath)) {
|
|
3235
3262
|
logIntercom(`SKIP \u2192 ${targetSession} (has in_progress task marker \u2014 will auto-chain)`);
|
|
3236
3263
|
return "debounced";
|
|
@@ -3240,7 +3267,7 @@ function sendIntercom(targetSession) {
|
|
|
3240
3267
|
try {
|
|
3241
3268
|
const rawAgent = targetSession.split("-")[0] ?? targetSession;
|
|
3242
3269
|
const agent = baseAgentName(rawAgent);
|
|
3243
|
-
const taskDir =
|
|
3270
|
+
const taskDir = path15.join(process.cwd(), "exe", agent);
|
|
3244
3271
|
if (existsSync11(taskDir)) {
|
|
3245
3272
|
const files = readdirSync3(taskDir).filter(
|
|
3246
3273
|
(f) => f.endsWith(".md") && f !== "DONE.txt"
|
|
@@ -3374,8 +3401,8 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3374
3401
|
const transport = getTransport();
|
|
3375
3402
|
const sessionName = employeeSessionName(employeeName, exeSession, opts?.instance);
|
|
3376
3403
|
const instanceLabel = opts?.instance != null && opts.instance > 0 ? `${employeeName}${opts.instance}` : employeeName;
|
|
3377
|
-
const logDir =
|
|
3378
|
-
const logFile =
|
|
3404
|
+
const logDir = path15.join(os8.homedir(), ".exe-os", "session-logs");
|
|
3405
|
+
const logFile = path15.join(logDir, `${instanceLabel}-${Date.now()}.log`);
|
|
3379
3406
|
if (!existsSync11(logDir)) {
|
|
3380
3407
|
mkdirSync6(logDir, { recursive: true });
|
|
3381
3408
|
}
|
|
@@ -3383,14 +3410,14 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3383
3410
|
let cleanupSuffix = "";
|
|
3384
3411
|
try {
|
|
3385
3412
|
const thisFile = fileURLToPath(import.meta.url);
|
|
3386
|
-
const cleanupScript =
|
|
3413
|
+
const cleanupScript = path15.join(path15.dirname(thisFile), "..", "bin", "exe-session-cleanup.js");
|
|
3387
3414
|
if (existsSync11(cleanupScript)) {
|
|
3388
3415
|
cleanupSuffix = `; ${process.execPath} "${cleanupScript}" "${employeeName}" "${exeSession}"`;
|
|
3389
3416
|
}
|
|
3390
3417
|
} catch {
|
|
3391
3418
|
}
|
|
3392
3419
|
try {
|
|
3393
|
-
const claudeJsonPath =
|
|
3420
|
+
const claudeJsonPath = path15.join(os8.homedir(), ".claude.json");
|
|
3394
3421
|
let claudeJson = {};
|
|
3395
3422
|
try {
|
|
3396
3423
|
claudeJson = JSON.parse(readFileSync10(claudeJsonPath, "utf8"));
|
|
@@ -3405,10 +3432,10 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3405
3432
|
} catch {
|
|
3406
3433
|
}
|
|
3407
3434
|
try {
|
|
3408
|
-
const settingsDir =
|
|
3435
|
+
const settingsDir = path15.join(os8.homedir(), ".claude", "projects");
|
|
3409
3436
|
const normalizedKey = (opts?.cwd ?? projectDir).replace(/\//g, "-").replace(/^-/, "");
|
|
3410
|
-
const projSettingsDir =
|
|
3411
|
-
const settingsPath =
|
|
3437
|
+
const projSettingsDir = path15.join(settingsDir, normalizedKey);
|
|
3438
|
+
const settingsPath = path15.join(projSettingsDir, "settings.json");
|
|
3412
3439
|
let settings = {};
|
|
3413
3440
|
try {
|
|
3414
3441
|
settings = JSON.parse(readFileSync10(settingsPath, "utf8"));
|
|
@@ -3455,8 +3482,8 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3455
3482
|
let behaviorsFlag = "";
|
|
3456
3483
|
let legacyFallbackWarned = false;
|
|
3457
3484
|
if (!useExeAgent && !useBinSymlink) {
|
|
3458
|
-
const identityPath =
|
|
3459
|
-
|
|
3485
|
+
const identityPath = path15.join(
|
|
3486
|
+
os8.homedir(),
|
|
3460
3487
|
".exe-os",
|
|
3461
3488
|
"identity",
|
|
3462
3489
|
`${employeeName}.md`
|
|
@@ -3471,7 +3498,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3471
3498
|
}
|
|
3472
3499
|
const behaviorsFile = exportBehaviorsSync(
|
|
3473
3500
|
employeeName,
|
|
3474
|
-
|
|
3501
|
+
path15.basename(spawnCwd),
|
|
3475
3502
|
sessionName
|
|
3476
3503
|
);
|
|
3477
3504
|
if (behaviorsFile) {
|
|
@@ -3486,9 +3513,9 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3486
3513
|
}
|
|
3487
3514
|
let sessionContextFlag = "";
|
|
3488
3515
|
try {
|
|
3489
|
-
const ctxDir =
|
|
3516
|
+
const ctxDir = path15.join(os8.homedir(), ".exe-os", "session-cache");
|
|
3490
3517
|
mkdirSync6(ctxDir, { recursive: true });
|
|
3491
|
-
const ctxFile =
|
|
3518
|
+
const ctxFile = path15.join(ctxDir, `session-context-${sessionName}.md`);
|
|
3492
3519
|
const ctxContent = [
|
|
3493
3520
|
`## Session Context`,
|
|
3494
3521
|
`You are running in tmux session: ${sessionName}.`,
|
|
@@ -3572,7 +3599,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3572
3599
|
transport.pipeLog(sessionName, logFile);
|
|
3573
3600
|
try {
|
|
3574
3601
|
const mySession = getMySession();
|
|
3575
|
-
const dispatchInfo =
|
|
3602
|
+
const dispatchInfo = path15.join(SESSION_CACHE, `dispatch-info-${sessionName}.json`);
|
|
3576
3603
|
writeFileSync7(dispatchInfo, JSON.stringify({
|
|
3577
3604
|
dispatchedBy: mySession,
|
|
3578
3605
|
rootExe: exeSession,
|
|
@@ -3646,15 +3673,15 @@ var init_tmux_routing = __esm({
|
|
|
3646
3673
|
init_intercom_queue();
|
|
3647
3674
|
init_plan_limits();
|
|
3648
3675
|
init_employees();
|
|
3649
|
-
SPAWN_LOCK_DIR =
|
|
3650
|
-
SESSION_CACHE =
|
|
3676
|
+
SPAWN_LOCK_DIR = path15.join(os8.homedir(), ".exe-os", "spawn-locks");
|
|
3677
|
+
SESSION_CACHE = path15.join(os8.homedir(), ".exe-os", "session-cache");
|
|
3651
3678
|
BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
|
|
3652
3679
|
VALID_SESSION_NAME = /^[a-z]+\d*-[a-zA-Z0-9_]+$/;
|
|
3653
3680
|
VERIFY_PANE_LINES = 200;
|
|
3654
3681
|
INTERCOM_DEBOUNCE_MS = 3e4;
|
|
3655
3682
|
CODEX_DEBOUNCE_MS = 12e4;
|
|
3656
|
-
INTERCOM_LOG2 =
|
|
3657
|
-
DEBOUNCE_FILE =
|
|
3683
|
+
INTERCOM_LOG2 = path15.join(os8.homedir(), ".exe-os", "intercom.log");
|
|
3684
|
+
DEBOUNCE_FILE = path15.join(SESSION_CACHE, "intercom-debounce.json");
|
|
3658
3685
|
DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
|
|
3659
3686
|
BUSY_PATTERN = /[✻✽✶✳·].*…|Running…|• Working|• Ran |• Explored|• Called|esc to interrupt/;
|
|
3660
3687
|
}
|
package/dist/lib/token-spend.js
CHANGED
|
@@ -98,8 +98,8 @@ var init_config = __esm({
|
|
|
98
98
|
import { readdir } from "fs/promises";
|
|
99
99
|
import { createReadStream } from "fs";
|
|
100
100
|
import { createInterface } from "readline";
|
|
101
|
-
import
|
|
102
|
-
import
|
|
101
|
+
import path4 from "path";
|
|
102
|
+
import os4 from "os";
|
|
103
103
|
|
|
104
104
|
// src/lib/database.ts
|
|
105
105
|
import { createClient } from "@libsql/client";
|
|
@@ -112,14 +112,34 @@ import { execSync } from "child_process";
|
|
|
112
112
|
import path2 from "path";
|
|
113
113
|
import os2 from "os";
|
|
114
114
|
var EMPLOYEES_PATH = path2.join(EXE_AI_DIR, "exe-employees.json");
|
|
115
|
+
var IDENTITY_DIR = path2.join(EXE_AI_DIR, "identity");
|
|
116
|
+
|
|
117
|
+
// src/lib/database-adapter.ts
|
|
118
|
+
import os3 from "os";
|
|
119
|
+
import path3 from "path";
|
|
120
|
+
import { createRequire } from "module";
|
|
121
|
+
import { pathToFileURL } from "url";
|
|
122
|
+
var BOOLEAN_COLUMNS_BY_TABLE = {
|
|
123
|
+
memories: /* @__PURE__ */ new Set(["has_error", "draft"]),
|
|
124
|
+
behaviors: /* @__PURE__ */ new Set(["active"]),
|
|
125
|
+
notifications: /* @__PURE__ */ new Set(["read"]),
|
|
126
|
+
users: /* @__PURE__ */ new Set(["has_personal_memory"])
|
|
127
|
+
};
|
|
128
|
+
var BOOLEAN_COLUMN_NAMES = new Set(
|
|
129
|
+
Object.values(BOOLEAN_COLUMNS_BY_TABLE).flatMap((cols) => [...cols])
|
|
130
|
+
);
|
|
115
131
|
|
|
116
132
|
// src/lib/database.ts
|
|
117
133
|
var _resilientClient = null;
|
|
118
134
|
var _daemonClient = null;
|
|
135
|
+
var _adapterClient = null;
|
|
119
136
|
function getClient() {
|
|
120
|
-
if (!
|
|
137
|
+
if (!_adapterClient) {
|
|
121
138
|
throw new Error("Database client not initialized. Call initDatabase() first.");
|
|
122
139
|
}
|
|
140
|
+
if (process.env.DATABASE_URL) {
|
|
141
|
+
return _adapterClient;
|
|
142
|
+
}
|
|
123
143
|
if (process.env.EXE_IS_DAEMON === "1") {
|
|
124
144
|
return _resilientClient;
|
|
125
145
|
}
|
|
@@ -177,18 +197,18 @@ async function getAgentSpend(period = "7d") {
|
|
|
177
197
|
for (const row of result.rows) {
|
|
178
198
|
sessionAgent.set(row.session_uuid, row.agent_id);
|
|
179
199
|
}
|
|
180
|
-
const claudeDir =
|
|
200
|
+
const claudeDir = path4.join(os4.homedir(), ".claude", "projects");
|
|
181
201
|
let projectDirs = [];
|
|
182
202
|
try {
|
|
183
203
|
const entries = await readdir(claudeDir);
|
|
184
|
-
projectDirs = entries.map((e) =>
|
|
204
|
+
projectDirs = entries.map((e) => path4.join(claudeDir, e));
|
|
185
205
|
} catch {
|
|
186
206
|
return [];
|
|
187
207
|
}
|
|
188
208
|
const agentTotals = /* @__PURE__ */ new Map();
|
|
189
209
|
for (const [sessionUuid, agentId] of sessionAgent) {
|
|
190
210
|
for (const dir of projectDirs) {
|
|
191
|
-
const jsonlPath =
|
|
211
|
+
const jsonlPath = path4.join(dir, `${sessionUuid}.jsonl`);
|
|
192
212
|
try {
|
|
193
213
|
const usage = await extractSessionUsage(jsonlPath);
|
|
194
214
|
if (usage.input === 0 && usage.output === 0) continue;
|