@askexenow/exe-os 0.9.6 → 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 +668 -37
- package/dist/bin/cli.js +1399 -607
- 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 +795 -155
- package/dist/bin/exe-call.js +209 -138
- package/dist/bin/exe-cloud.js +35 -12
- package/dist/bin/exe-dispatch.js +703 -72
- 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 +1064 -273
- package/dist/bin/exe-heartbeat.js +676 -45
- 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 +845 -152
- 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 +668 -37
- package/dist/bin/exe-team.js +635 -13
- package/dist/bin/git-sweep.js +731 -91
- 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 +735 -95
- 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 +1038 -247
- package/dist/hooks/bug-report-worker.js +902 -172
- package/dist/hooks/commit-complete.js +729 -89
- package/dist/hooks/error-recall.js +776 -93
- package/dist/hooks/exe-heartbeat-hook.js +85 -71
- package/dist/hooks/ingest-worker.js +851 -158
- 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 +685 -45
- package/dist/hooks/pre-compact.js +729 -89
- package/dist/hooks/pre-tool-use.js +883 -127
- package/dist/hooks/prompt-ingest-worker.js +758 -83
- package/dist/hooks/prompt-submit.js +1071 -321
- package/dist/hooks/response-ingest-worker.js +758 -83
- package/dist/hooks/session-end.js +732 -92
- package/dist/hooks/session-start.js +1042 -209
- package/dist/hooks/stop.js +691 -51
- package/dist/hooks/subagent-stop.js +685 -45
- package/dist/hooks/summary-worker.js +827 -134
- package/dist/index.js +1026 -234
- 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 +905 -164
- package/dist/lib/hybrid-search.js +771 -88
- package/dist/lib/identity.js +27 -7
- package/dist/lib/messaging.js +66 -30
- 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 +109 -73
- package/dist/lib/tmux-routing.js +98 -62
- package/dist/lib/token-spend.js +26 -6
- package/dist/mcp/server.js +1807 -472
- 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 +301 -166
- 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 +206 -40
- package/dist/mcp/tools/send-message.js +69 -33
- package/dist/mcp/tools/update-task.js +86 -50
- package/dist/runtime/index.js +731 -91
- package/dist/tui/App.js +864 -125
- 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;
|
|
@@ -3055,15 +3082,24 @@ function getDispatchedBy(sessionKey) {
|
|
|
3055
3082
|
function resolveExeSession() {
|
|
3056
3083
|
const mySession = getMySession();
|
|
3057
3084
|
if (!mySession) return null;
|
|
3085
|
+
const fromSessionName = extractRootExe(mySession);
|
|
3058
3086
|
try {
|
|
3059
3087
|
const key = getSessionKey();
|
|
3060
3088
|
const parentExe = getParentExe(key);
|
|
3061
3089
|
if (parentExe) {
|
|
3062
|
-
|
|
3090
|
+
const fromCache = extractRootExe(parentExe) ?? parentExe;
|
|
3091
|
+
if (fromSessionName && fromCache !== fromSessionName) {
|
|
3092
|
+
process.stderr.write(
|
|
3093
|
+
`[tmux-routing] WARN: cache says "${fromCache}" but session name says "${fromSessionName}". Trusting session name.
|
|
3094
|
+
`
|
|
3095
|
+
);
|
|
3096
|
+
return fromSessionName;
|
|
3097
|
+
}
|
|
3098
|
+
return fromCache;
|
|
3063
3099
|
}
|
|
3064
3100
|
} catch {
|
|
3065
3101
|
}
|
|
3066
|
-
return
|
|
3102
|
+
return fromSessionName ?? mySession;
|
|
3067
3103
|
}
|
|
3068
3104
|
function isEmployeeAlive(sessionName) {
|
|
3069
3105
|
return getTransport().isAlive(sessionName);
|
|
@@ -3221,7 +3257,7 @@ function sendIntercom(targetSession) {
|
|
|
3221
3257
|
try {
|
|
3222
3258
|
const rawAgent = targetSession.split("-")[0] ?? targetSession;
|
|
3223
3259
|
const agent = baseAgentName(rawAgent);
|
|
3224
|
-
const markerPath =
|
|
3260
|
+
const markerPath = path15.join(SESSION_CACHE, `current-task-${agent}.json`);
|
|
3225
3261
|
if (existsSync11(markerPath)) {
|
|
3226
3262
|
logIntercom(`SKIP \u2192 ${targetSession} (has in_progress task marker \u2014 will auto-chain)`);
|
|
3227
3263
|
return "debounced";
|
|
@@ -3231,7 +3267,7 @@ function sendIntercom(targetSession) {
|
|
|
3231
3267
|
try {
|
|
3232
3268
|
const rawAgent = targetSession.split("-")[0] ?? targetSession;
|
|
3233
3269
|
const agent = baseAgentName(rawAgent);
|
|
3234
|
-
const taskDir =
|
|
3270
|
+
const taskDir = path15.join(process.cwd(), "exe", agent);
|
|
3235
3271
|
if (existsSync11(taskDir)) {
|
|
3236
3272
|
const files = readdirSync3(taskDir).filter(
|
|
3237
3273
|
(f) => f.endsWith(".md") && f !== "DONE.txt"
|
|
@@ -3365,8 +3401,8 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3365
3401
|
const transport = getTransport();
|
|
3366
3402
|
const sessionName = employeeSessionName(employeeName, exeSession, opts?.instance);
|
|
3367
3403
|
const instanceLabel = opts?.instance != null && opts.instance > 0 ? `${employeeName}${opts.instance}` : employeeName;
|
|
3368
|
-
const logDir =
|
|
3369
|
-
const logFile =
|
|
3404
|
+
const logDir = path15.join(os8.homedir(), ".exe-os", "session-logs");
|
|
3405
|
+
const logFile = path15.join(logDir, `${instanceLabel}-${Date.now()}.log`);
|
|
3370
3406
|
if (!existsSync11(logDir)) {
|
|
3371
3407
|
mkdirSync6(logDir, { recursive: true });
|
|
3372
3408
|
}
|
|
@@ -3374,14 +3410,14 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3374
3410
|
let cleanupSuffix = "";
|
|
3375
3411
|
try {
|
|
3376
3412
|
const thisFile = fileURLToPath(import.meta.url);
|
|
3377
|
-
const cleanupScript =
|
|
3413
|
+
const cleanupScript = path15.join(path15.dirname(thisFile), "..", "bin", "exe-session-cleanup.js");
|
|
3378
3414
|
if (existsSync11(cleanupScript)) {
|
|
3379
3415
|
cleanupSuffix = `; ${process.execPath} "${cleanupScript}" "${employeeName}" "${exeSession}"`;
|
|
3380
3416
|
}
|
|
3381
3417
|
} catch {
|
|
3382
3418
|
}
|
|
3383
3419
|
try {
|
|
3384
|
-
const claudeJsonPath =
|
|
3420
|
+
const claudeJsonPath = path15.join(os8.homedir(), ".claude.json");
|
|
3385
3421
|
let claudeJson = {};
|
|
3386
3422
|
try {
|
|
3387
3423
|
claudeJson = JSON.parse(readFileSync10(claudeJsonPath, "utf8"));
|
|
@@ -3396,10 +3432,10 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3396
3432
|
} catch {
|
|
3397
3433
|
}
|
|
3398
3434
|
try {
|
|
3399
|
-
const settingsDir =
|
|
3435
|
+
const settingsDir = path15.join(os8.homedir(), ".claude", "projects");
|
|
3400
3436
|
const normalizedKey = (opts?.cwd ?? projectDir).replace(/\//g, "-").replace(/^-/, "");
|
|
3401
|
-
const projSettingsDir =
|
|
3402
|
-
const settingsPath =
|
|
3437
|
+
const projSettingsDir = path15.join(settingsDir, normalizedKey);
|
|
3438
|
+
const settingsPath = path15.join(projSettingsDir, "settings.json");
|
|
3403
3439
|
let settings = {};
|
|
3404
3440
|
try {
|
|
3405
3441
|
settings = JSON.parse(readFileSync10(settingsPath, "utf8"));
|
|
@@ -3446,8 +3482,8 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3446
3482
|
let behaviorsFlag = "";
|
|
3447
3483
|
let legacyFallbackWarned = false;
|
|
3448
3484
|
if (!useExeAgent && !useBinSymlink) {
|
|
3449
|
-
const identityPath =
|
|
3450
|
-
|
|
3485
|
+
const identityPath = path15.join(
|
|
3486
|
+
os8.homedir(),
|
|
3451
3487
|
".exe-os",
|
|
3452
3488
|
"identity",
|
|
3453
3489
|
`${employeeName}.md`
|
|
@@ -3462,7 +3498,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3462
3498
|
}
|
|
3463
3499
|
const behaviorsFile = exportBehaviorsSync(
|
|
3464
3500
|
employeeName,
|
|
3465
|
-
|
|
3501
|
+
path15.basename(spawnCwd),
|
|
3466
3502
|
sessionName
|
|
3467
3503
|
);
|
|
3468
3504
|
if (behaviorsFile) {
|
|
@@ -3477,9 +3513,9 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3477
3513
|
}
|
|
3478
3514
|
let sessionContextFlag = "";
|
|
3479
3515
|
try {
|
|
3480
|
-
const ctxDir =
|
|
3516
|
+
const ctxDir = path15.join(os8.homedir(), ".exe-os", "session-cache");
|
|
3481
3517
|
mkdirSync6(ctxDir, { recursive: true });
|
|
3482
|
-
const ctxFile =
|
|
3518
|
+
const ctxFile = path15.join(ctxDir, `session-context-${sessionName}.md`);
|
|
3483
3519
|
const ctxContent = [
|
|
3484
3520
|
`## Session Context`,
|
|
3485
3521
|
`You are running in tmux session: ${sessionName}.`,
|
|
@@ -3563,7 +3599,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3563
3599
|
transport.pipeLog(sessionName, logFile);
|
|
3564
3600
|
try {
|
|
3565
3601
|
const mySession = getMySession();
|
|
3566
|
-
const dispatchInfo =
|
|
3602
|
+
const dispatchInfo = path15.join(SESSION_CACHE, `dispatch-info-${sessionName}.json`);
|
|
3567
3603
|
writeFileSync7(dispatchInfo, JSON.stringify({
|
|
3568
3604
|
dispatchedBy: mySession,
|
|
3569
3605
|
rootExe: exeSession,
|
|
@@ -3637,15 +3673,15 @@ var init_tmux_routing = __esm({
|
|
|
3637
3673
|
init_intercom_queue();
|
|
3638
3674
|
init_plan_limits();
|
|
3639
3675
|
init_employees();
|
|
3640
|
-
SPAWN_LOCK_DIR =
|
|
3641
|
-
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");
|
|
3642
3678
|
BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
|
|
3643
3679
|
VALID_SESSION_NAME = /^[a-z]+\d*-[a-zA-Z0-9_]+$/;
|
|
3644
3680
|
VERIFY_PANE_LINES = 200;
|
|
3645
3681
|
INTERCOM_DEBOUNCE_MS = 3e4;
|
|
3646
3682
|
CODEX_DEBOUNCE_MS = 12e4;
|
|
3647
|
-
INTERCOM_LOG2 =
|
|
3648
|
-
DEBOUNCE_FILE =
|
|
3683
|
+
INTERCOM_LOG2 = path15.join(os8.homedir(), ".exe-os", "intercom.log");
|
|
3684
|
+
DEBOUNCE_FILE = path15.join(SESSION_CACHE, "intercom-debounce.json");
|
|
3649
3685
|
DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
|
|
3650
3686
|
BUSY_PATTERN = /[✻✽✶✳·].*…|Running…|• Working|• Ran |• Explored|• Called|esc to interrupt/;
|
|
3651
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;
|