@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/tasks.js
CHANGED
|
@@ -262,7 +262,7 @@ function isMultiInstance(agentName, employees) {
|
|
|
262
262
|
if (!emp) return false;
|
|
263
263
|
return MULTI_INSTANCE_ROLES.has(emp.role.toLowerCase());
|
|
264
264
|
}
|
|
265
|
-
var EMPLOYEES_PATH, DEFAULT_COORDINATOR_TEMPLATE_NAME, COORDINATOR_ROLE, MULTI_INSTANCE_ROLES;
|
|
265
|
+
var EMPLOYEES_PATH, DEFAULT_COORDINATOR_TEMPLATE_NAME, COORDINATOR_ROLE, MULTI_INSTANCE_ROLES, IDENTITY_DIR;
|
|
266
266
|
var init_employees = __esm({
|
|
267
267
|
"src/lib/employees.ts"() {
|
|
268
268
|
"use strict";
|
|
@@ -271,15 +271,40 @@ var init_employees = __esm({
|
|
|
271
271
|
DEFAULT_COORDINATOR_TEMPLATE_NAME = "exe";
|
|
272
272
|
COORDINATOR_ROLE = "COO";
|
|
273
273
|
MULTI_INSTANCE_ROLES = /* @__PURE__ */ new Set(["principal engineer", "content production specialist", "staff code reviewer"]);
|
|
274
|
+
IDENTITY_DIR = path2.join(EXE_AI_DIR, "identity");
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
// src/lib/database-adapter.ts
|
|
279
|
+
import os3 from "os";
|
|
280
|
+
import path3 from "path";
|
|
281
|
+
import { createRequire } from "module";
|
|
282
|
+
import { pathToFileURL } from "url";
|
|
283
|
+
var BOOLEAN_COLUMNS_BY_TABLE, BOOLEAN_COLUMN_NAMES;
|
|
284
|
+
var init_database_adapter = __esm({
|
|
285
|
+
"src/lib/database-adapter.ts"() {
|
|
286
|
+
"use strict";
|
|
287
|
+
BOOLEAN_COLUMNS_BY_TABLE = {
|
|
288
|
+
memories: /* @__PURE__ */ new Set(["has_error", "draft"]),
|
|
289
|
+
behaviors: /* @__PURE__ */ new Set(["active"]),
|
|
290
|
+
notifications: /* @__PURE__ */ new Set(["read"]),
|
|
291
|
+
users: /* @__PURE__ */ new Set(["has_personal_memory"])
|
|
292
|
+
};
|
|
293
|
+
BOOLEAN_COLUMN_NAMES = new Set(
|
|
294
|
+
Object.values(BOOLEAN_COLUMNS_BY_TABLE).flatMap((cols) => [...cols])
|
|
295
|
+
);
|
|
274
296
|
}
|
|
275
297
|
});
|
|
276
298
|
|
|
277
299
|
// src/lib/database.ts
|
|
278
300
|
import { createClient } from "@libsql/client";
|
|
279
301
|
function getClient() {
|
|
280
|
-
if (!
|
|
302
|
+
if (!_adapterClient) {
|
|
281
303
|
throw new Error("Database client not initialized. Call initDatabase() first.");
|
|
282
304
|
}
|
|
305
|
+
if (process.env.DATABASE_URL) {
|
|
306
|
+
return _adapterClient;
|
|
307
|
+
}
|
|
283
308
|
if (process.env.EXE_IS_DAEMON === "1") {
|
|
284
309
|
return _resilientClient;
|
|
285
310
|
}
|
|
@@ -288,21 +313,23 @@ function getClient() {
|
|
|
288
313
|
}
|
|
289
314
|
return _resilientClient;
|
|
290
315
|
}
|
|
291
|
-
var _resilientClient, _daemonClient;
|
|
316
|
+
var _resilientClient, _daemonClient, _adapterClient;
|
|
292
317
|
var init_database = __esm({
|
|
293
318
|
"src/lib/database.ts"() {
|
|
294
319
|
"use strict";
|
|
295
320
|
init_db_retry();
|
|
296
321
|
init_employees();
|
|
322
|
+
init_database_adapter();
|
|
297
323
|
_resilientClient = null;
|
|
298
324
|
_daemonClient = null;
|
|
325
|
+
_adapterClient = null;
|
|
299
326
|
}
|
|
300
327
|
});
|
|
301
328
|
|
|
302
329
|
// src/lib/notifications.ts
|
|
303
330
|
import crypto from "crypto";
|
|
304
|
-
import
|
|
305
|
-
import
|
|
331
|
+
import path4 from "path";
|
|
332
|
+
import os4 from "os";
|
|
306
333
|
import {
|
|
307
334
|
readFileSync as readFileSync3,
|
|
308
335
|
readdirSync,
|
|
@@ -408,10 +435,10 @@ var init_state_bus = __esm({
|
|
|
408
435
|
|
|
409
436
|
// src/lib/session-registry.ts
|
|
410
437
|
import { readFileSync as readFileSync4, writeFileSync as writeFileSync2, mkdirSync, existsSync as existsSync4 } from "fs";
|
|
411
|
-
import
|
|
412
|
-
import
|
|
438
|
+
import path5 from "path";
|
|
439
|
+
import os5 from "os";
|
|
413
440
|
function registerSession(entry) {
|
|
414
|
-
const dir =
|
|
441
|
+
const dir = path5.dirname(REGISTRY_PATH);
|
|
415
442
|
if (!existsSync4(dir)) {
|
|
416
443
|
mkdirSync(dir, { recursive: true });
|
|
417
444
|
}
|
|
@@ -436,7 +463,7 @@ var REGISTRY_PATH;
|
|
|
436
463
|
var init_session_registry = __esm({
|
|
437
464
|
"src/lib/session-registry.ts"() {
|
|
438
465
|
"use strict";
|
|
439
|
-
REGISTRY_PATH =
|
|
466
|
+
REGISTRY_PATH = path5.join(os5.homedir(), ".exe-os", "session-registry.json");
|
|
440
467
|
}
|
|
441
468
|
});
|
|
442
469
|
|
|
@@ -717,7 +744,7 @@ var init_runtime_table = __esm({
|
|
|
717
744
|
|
|
718
745
|
// src/lib/agent-config.ts
|
|
719
746
|
import { readFileSync as readFileSync5, writeFileSync as writeFileSync3, existsSync as existsSync5, mkdirSync as mkdirSync2 } from "fs";
|
|
720
|
-
import
|
|
747
|
+
import path6 from "path";
|
|
721
748
|
function loadAgentConfig() {
|
|
722
749
|
if (!existsSync5(AGENT_CONFIG_PATH)) return {};
|
|
723
750
|
try {
|
|
@@ -740,7 +767,7 @@ var init_agent_config = __esm({
|
|
|
740
767
|
"use strict";
|
|
741
768
|
init_config();
|
|
742
769
|
init_runtime_table();
|
|
743
|
-
AGENT_CONFIG_PATH =
|
|
770
|
+
AGENT_CONFIG_PATH = path6.join(EXE_AI_DIR, "agent-config.json");
|
|
744
771
|
DEFAULT_MODELS = {
|
|
745
772
|
claude: "claude-opus-4",
|
|
746
773
|
codex: RUNTIME_TABLE.codex?.defaultModel ?? "gpt-5.4",
|
|
@@ -759,10 +786,10 @@ __export(intercom_queue_exports, {
|
|
|
759
786
|
readQueue: () => readQueue
|
|
760
787
|
});
|
|
761
788
|
import { readFileSync as readFileSync6, writeFileSync as writeFileSync4, renameSync as renameSync3, existsSync as existsSync6, mkdirSync as mkdirSync3 } from "fs";
|
|
762
|
-
import
|
|
763
|
-
import
|
|
789
|
+
import path7 from "path";
|
|
790
|
+
import os6 from "os";
|
|
764
791
|
function ensureDir() {
|
|
765
|
-
const dir =
|
|
792
|
+
const dir = path7.dirname(QUEUE_PATH);
|
|
766
793
|
if (!existsSync6(dir)) mkdirSync3(dir, { recursive: true });
|
|
767
794
|
}
|
|
768
795
|
function readQueue() {
|
|
@@ -868,26 +895,26 @@ var QUEUE_PATH, MAX_RETRIES, TTL_MS, INTERCOM_LOG;
|
|
|
868
895
|
var init_intercom_queue = __esm({
|
|
869
896
|
"src/lib/intercom-queue.ts"() {
|
|
870
897
|
"use strict";
|
|
871
|
-
QUEUE_PATH =
|
|
898
|
+
QUEUE_PATH = path7.join(os6.homedir(), ".exe-os", "intercom-queue.json");
|
|
872
899
|
MAX_RETRIES = 5;
|
|
873
900
|
TTL_MS = 60 * 60 * 1e3;
|
|
874
|
-
INTERCOM_LOG =
|
|
901
|
+
INTERCOM_LOG = path7.join(os6.homedir(), ".exe-os", "intercom.log");
|
|
875
902
|
}
|
|
876
903
|
});
|
|
877
904
|
|
|
878
905
|
// src/lib/license.ts
|
|
879
906
|
import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, existsSync as existsSync7, mkdirSync as mkdirSync4 } from "fs";
|
|
880
907
|
import { randomUUID } from "crypto";
|
|
881
|
-
import
|
|
908
|
+
import path8 from "path";
|
|
882
909
|
import { jwtVerify, importSPKI } from "jose";
|
|
883
910
|
var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH, PLAN_LIMITS;
|
|
884
911
|
var init_license = __esm({
|
|
885
912
|
"src/lib/license.ts"() {
|
|
886
913
|
"use strict";
|
|
887
914
|
init_config();
|
|
888
|
-
LICENSE_PATH =
|
|
889
|
-
CACHE_PATH =
|
|
890
|
-
DEVICE_ID_PATH =
|
|
915
|
+
LICENSE_PATH = path8.join(EXE_AI_DIR, "license.key");
|
|
916
|
+
CACHE_PATH = path8.join(EXE_AI_DIR, "license-cache.json");
|
|
917
|
+
DEVICE_ID_PATH = path8.join(EXE_AI_DIR, "device-id");
|
|
891
918
|
PLAN_LIMITS = {
|
|
892
919
|
free: { devices: 1, employees: 1, memories: 5e3 },
|
|
893
920
|
pro: { devices: 3, employees: 5, memories: 1e5 },
|
|
@@ -900,7 +927,7 @@ var init_license = __esm({
|
|
|
900
927
|
|
|
901
928
|
// src/lib/plan-limits.ts
|
|
902
929
|
import { readFileSync as readFileSync8, existsSync as existsSync8 } from "fs";
|
|
903
|
-
import
|
|
930
|
+
import path9 from "path";
|
|
904
931
|
function getLicenseSync() {
|
|
905
932
|
try {
|
|
906
933
|
if (!existsSync8(CACHE_PATH2)) return freeLicense();
|
|
@@ -972,7 +999,7 @@ var init_plan_limits = __esm({
|
|
|
972
999
|
this.name = "PlanLimitError";
|
|
973
1000
|
}
|
|
974
1001
|
};
|
|
975
|
-
CACHE_PATH2 =
|
|
1002
|
+
CACHE_PATH2 = path9.join(EXE_AI_DIR, "license-cache.json");
|
|
976
1003
|
}
|
|
977
1004
|
});
|
|
978
1005
|
|
|
@@ -1321,12 +1348,12 @@ __export(tmux_routing_exports, {
|
|
|
1321
1348
|
});
|
|
1322
1349
|
import { execFileSync as execFileSync2, execSync as execSync4 } from "child_process";
|
|
1323
1350
|
import { readFileSync as readFileSync9, writeFileSync as writeFileSync6, mkdirSync as mkdirSync5, existsSync as existsSync9, appendFileSync, readdirSync as readdirSync2 } from "fs";
|
|
1324
|
-
import
|
|
1325
|
-
import
|
|
1351
|
+
import path10 from "path";
|
|
1352
|
+
import os7 from "os";
|
|
1326
1353
|
import { fileURLToPath } from "url";
|
|
1327
1354
|
import { unlinkSync as unlinkSync3 } from "fs";
|
|
1328
1355
|
function spawnLockPath(sessionName) {
|
|
1329
|
-
return
|
|
1356
|
+
return path10.join(SPAWN_LOCK_DIR, `${sessionName}.lock`);
|
|
1330
1357
|
}
|
|
1331
1358
|
function isProcessAlive(pid) {
|
|
1332
1359
|
try {
|
|
@@ -1363,8 +1390,8 @@ function releaseSpawnLock(sessionName) {
|
|
|
1363
1390
|
function resolveBehaviorsExporterScript() {
|
|
1364
1391
|
try {
|
|
1365
1392
|
const thisFile = fileURLToPath(import.meta.url);
|
|
1366
|
-
const scriptPath =
|
|
1367
|
-
|
|
1393
|
+
const scriptPath = path10.join(
|
|
1394
|
+
path10.dirname(thisFile),
|
|
1368
1395
|
"..",
|
|
1369
1396
|
"bin",
|
|
1370
1397
|
"exe-export-behaviors.js"
|
|
@@ -1439,7 +1466,7 @@ function registerParentExe(sessionKey, parentExe, dispatchedBy) {
|
|
|
1439
1466
|
mkdirSync5(SESSION_CACHE, { recursive: true });
|
|
1440
1467
|
}
|
|
1441
1468
|
const rootExe = extractRootExe(parentExe) ?? parentExe;
|
|
1442
|
-
const filePath =
|
|
1469
|
+
const filePath = path10.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`);
|
|
1443
1470
|
writeFileSync6(filePath, JSON.stringify({
|
|
1444
1471
|
parentExe: rootExe,
|
|
1445
1472
|
dispatchedBy: dispatchedBy || rootExe,
|
|
@@ -1448,7 +1475,7 @@ function registerParentExe(sessionKey, parentExe, dispatchedBy) {
|
|
|
1448
1475
|
}
|
|
1449
1476
|
function getParentExe(sessionKey) {
|
|
1450
1477
|
try {
|
|
1451
|
-
const data = JSON.parse(readFileSync9(
|
|
1478
|
+
const data = JSON.parse(readFileSync9(path10.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
|
|
1452
1479
|
return data.parentExe || null;
|
|
1453
1480
|
} catch {
|
|
1454
1481
|
return null;
|
|
@@ -1457,7 +1484,7 @@ function getParentExe(sessionKey) {
|
|
|
1457
1484
|
function getDispatchedBy(sessionKey) {
|
|
1458
1485
|
try {
|
|
1459
1486
|
const data = JSON.parse(readFileSync9(
|
|
1460
|
-
|
|
1487
|
+
path10.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`),
|
|
1461
1488
|
"utf8"
|
|
1462
1489
|
));
|
|
1463
1490
|
return data.dispatchedBy ?? data.parentExe ?? null;
|
|
@@ -1468,15 +1495,24 @@ function getDispatchedBy(sessionKey) {
|
|
|
1468
1495
|
function resolveExeSession() {
|
|
1469
1496
|
const mySession = getMySession();
|
|
1470
1497
|
if (!mySession) return null;
|
|
1498
|
+
const fromSessionName = extractRootExe(mySession);
|
|
1471
1499
|
try {
|
|
1472
1500
|
const key = getSessionKey();
|
|
1473
1501
|
const parentExe = getParentExe(key);
|
|
1474
1502
|
if (parentExe) {
|
|
1475
|
-
|
|
1503
|
+
const fromCache = extractRootExe(parentExe) ?? parentExe;
|
|
1504
|
+
if (fromSessionName && fromCache !== fromSessionName) {
|
|
1505
|
+
process.stderr.write(
|
|
1506
|
+
`[tmux-routing] WARN: cache says "${fromCache}" but session name says "${fromSessionName}". Trusting session name.
|
|
1507
|
+
`
|
|
1508
|
+
);
|
|
1509
|
+
return fromSessionName;
|
|
1510
|
+
}
|
|
1511
|
+
return fromCache;
|
|
1476
1512
|
}
|
|
1477
1513
|
} catch {
|
|
1478
1514
|
}
|
|
1479
|
-
return
|
|
1515
|
+
return fromSessionName ?? mySession;
|
|
1480
1516
|
}
|
|
1481
1517
|
function isEmployeeAlive(sessionName) {
|
|
1482
1518
|
return getTransport().isAlive(sessionName);
|
|
@@ -1634,7 +1670,7 @@ function sendIntercom(targetSession) {
|
|
|
1634
1670
|
try {
|
|
1635
1671
|
const rawAgent = targetSession.split("-")[0] ?? targetSession;
|
|
1636
1672
|
const agent = baseAgentName(rawAgent);
|
|
1637
|
-
const markerPath =
|
|
1673
|
+
const markerPath = path10.join(SESSION_CACHE, `current-task-${agent}.json`);
|
|
1638
1674
|
if (existsSync9(markerPath)) {
|
|
1639
1675
|
logIntercom(`SKIP \u2192 ${targetSession} (has in_progress task marker \u2014 will auto-chain)`);
|
|
1640
1676
|
return "debounced";
|
|
@@ -1644,7 +1680,7 @@ function sendIntercom(targetSession) {
|
|
|
1644
1680
|
try {
|
|
1645
1681
|
const rawAgent = targetSession.split("-")[0] ?? targetSession;
|
|
1646
1682
|
const agent = baseAgentName(rawAgent);
|
|
1647
|
-
const taskDir =
|
|
1683
|
+
const taskDir = path10.join(process.cwd(), "exe", agent);
|
|
1648
1684
|
if (existsSync9(taskDir)) {
|
|
1649
1685
|
const files = readdirSync2(taskDir).filter(
|
|
1650
1686
|
(f) => f.endsWith(".md") && f !== "DONE.txt"
|
|
@@ -1778,8 +1814,8 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
1778
1814
|
const transport = getTransport();
|
|
1779
1815
|
const sessionName = employeeSessionName(employeeName, exeSession, opts?.instance);
|
|
1780
1816
|
const instanceLabel = opts?.instance != null && opts.instance > 0 ? `${employeeName}${opts.instance}` : employeeName;
|
|
1781
|
-
const logDir =
|
|
1782
|
-
const logFile =
|
|
1817
|
+
const logDir = path10.join(os7.homedir(), ".exe-os", "session-logs");
|
|
1818
|
+
const logFile = path10.join(logDir, `${instanceLabel}-${Date.now()}.log`);
|
|
1783
1819
|
if (!existsSync9(logDir)) {
|
|
1784
1820
|
mkdirSync5(logDir, { recursive: true });
|
|
1785
1821
|
}
|
|
@@ -1787,14 +1823,14 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
1787
1823
|
let cleanupSuffix = "";
|
|
1788
1824
|
try {
|
|
1789
1825
|
const thisFile = fileURLToPath(import.meta.url);
|
|
1790
|
-
const cleanupScript =
|
|
1826
|
+
const cleanupScript = path10.join(path10.dirname(thisFile), "..", "bin", "exe-session-cleanup.js");
|
|
1791
1827
|
if (existsSync9(cleanupScript)) {
|
|
1792
1828
|
cleanupSuffix = `; ${process.execPath} "${cleanupScript}" "${employeeName}" "${exeSession}"`;
|
|
1793
1829
|
}
|
|
1794
1830
|
} catch {
|
|
1795
1831
|
}
|
|
1796
1832
|
try {
|
|
1797
|
-
const claudeJsonPath =
|
|
1833
|
+
const claudeJsonPath = path10.join(os7.homedir(), ".claude.json");
|
|
1798
1834
|
let claudeJson = {};
|
|
1799
1835
|
try {
|
|
1800
1836
|
claudeJson = JSON.parse(readFileSync9(claudeJsonPath, "utf8"));
|
|
@@ -1809,10 +1845,10 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
1809
1845
|
} catch {
|
|
1810
1846
|
}
|
|
1811
1847
|
try {
|
|
1812
|
-
const settingsDir =
|
|
1848
|
+
const settingsDir = path10.join(os7.homedir(), ".claude", "projects");
|
|
1813
1849
|
const normalizedKey = (opts?.cwd ?? projectDir).replace(/\//g, "-").replace(/^-/, "");
|
|
1814
|
-
const projSettingsDir =
|
|
1815
|
-
const settingsPath =
|
|
1850
|
+
const projSettingsDir = path10.join(settingsDir, normalizedKey);
|
|
1851
|
+
const settingsPath = path10.join(projSettingsDir, "settings.json");
|
|
1816
1852
|
let settings = {};
|
|
1817
1853
|
try {
|
|
1818
1854
|
settings = JSON.parse(readFileSync9(settingsPath, "utf8"));
|
|
@@ -1859,8 +1895,8 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
1859
1895
|
let behaviorsFlag = "";
|
|
1860
1896
|
let legacyFallbackWarned = false;
|
|
1861
1897
|
if (!useExeAgent && !useBinSymlink) {
|
|
1862
|
-
const identityPath =
|
|
1863
|
-
|
|
1898
|
+
const identityPath = path10.join(
|
|
1899
|
+
os7.homedir(),
|
|
1864
1900
|
".exe-os",
|
|
1865
1901
|
"identity",
|
|
1866
1902
|
`${employeeName}.md`
|
|
@@ -1875,7 +1911,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
1875
1911
|
}
|
|
1876
1912
|
const behaviorsFile = exportBehaviorsSync(
|
|
1877
1913
|
employeeName,
|
|
1878
|
-
|
|
1914
|
+
path10.basename(spawnCwd),
|
|
1879
1915
|
sessionName
|
|
1880
1916
|
);
|
|
1881
1917
|
if (behaviorsFile) {
|
|
@@ -1890,9 +1926,9 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
1890
1926
|
}
|
|
1891
1927
|
let sessionContextFlag = "";
|
|
1892
1928
|
try {
|
|
1893
|
-
const ctxDir =
|
|
1929
|
+
const ctxDir = path10.join(os7.homedir(), ".exe-os", "session-cache");
|
|
1894
1930
|
mkdirSync5(ctxDir, { recursive: true });
|
|
1895
|
-
const ctxFile =
|
|
1931
|
+
const ctxFile = path10.join(ctxDir, `session-context-${sessionName}.md`);
|
|
1896
1932
|
const ctxContent = [
|
|
1897
1933
|
`## Session Context`,
|
|
1898
1934
|
`You are running in tmux session: ${sessionName}.`,
|
|
@@ -1976,7 +2012,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
1976
2012
|
transport.pipeLog(sessionName, logFile);
|
|
1977
2013
|
try {
|
|
1978
2014
|
const mySession = getMySession();
|
|
1979
|
-
const dispatchInfo =
|
|
2015
|
+
const dispatchInfo = path10.join(SESSION_CACHE, `dispatch-info-${sessionName}.json`);
|
|
1980
2016
|
writeFileSync6(dispatchInfo, JSON.stringify({
|
|
1981
2017
|
dispatchedBy: mySession,
|
|
1982
2018
|
rootExe: exeSession,
|
|
@@ -2051,15 +2087,15 @@ var init_tmux_routing = __esm({
|
|
|
2051
2087
|
init_intercom_queue();
|
|
2052
2088
|
init_plan_limits();
|
|
2053
2089
|
init_employees();
|
|
2054
|
-
SPAWN_LOCK_DIR =
|
|
2055
|
-
SESSION_CACHE =
|
|
2090
|
+
SPAWN_LOCK_DIR = path10.join(os7.homedir(), ".exe-os", "spawn-locks");
|
|
2091
|
+
SESSION_CACHE = path10.join(os7.homedir(), ".exe-os", "session-cache");
|
|
2056
2092
|
BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
|
|
2057
2093
|
VALID_SESSION_NAME = /^[a-z]+\d*-[a-zA-Z0-9_]+$/;
|
|
2058
2094
|
VERIFY_PANE_LINES = 200;
|
|
2059
2095
|
INTERCOM_DEBOUNCE_MS = 3e4;
|
|
2060
2096
|
CODEX_DEBOUNCE_MS = 12e4;
|
|
2061
|
-
INTERCOM_LOG2 =
|
|
2062
|
-
DEBOUNCE_FILE =
|
|
2097
|
+
INTERCOM_LOG2 = path10.join(os7.homedir(), ".exe-os", "intercom.log");
|
|
2098
|
+
DEBOUNCE_FILE = path10.join(SESSION_CACHE, "intercom-debounce.json");
|
|
2063
2099
|
DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
|
|
2064
2100
|
BUSY_PATTERN = /[✻✽✶✳·].*…|Running…|• Working|• Ran |• Explored|• Called|esc to interrupt/;
|
|
2065
2101
|
}
|
|
@@ -2091,8 +2127,8 @@ var init_task_scope = __esm({
|
|
|
2091
2127
|
|
|
2092
2128
|
// src/lib/tasks-crud.ts
|
|
2093
2129
|
import crypto3 from "crypto";
|
|
2094
|
-
import
|
|
2095
|
-
import
|
|
2130
|
+
import path11 from "path";
|
|
2131
|
+
import os8 from "os";
|
|
2096
2132
|
import { execSync as execSync5 } from "child_process";
|
|
2097
2133
|
import { mkdir as mkdir3, writeFile as writeFile3, appendFile } from "fs/promises";
|
|
2098
2134
|
import { existsSync as existsSync10, readFileSync as readFileSync10 } from "fs";
|
|
@@ -2270,8 +2306,8 @@ ${laneWarning}` : laneWarning;
|
|
|
2270
2306
|
}
|
|
2271
2307
|
if (input.baseDir) {
|
|
2272
2308
|
try {
|
|
2273
|
-
await mkdir3(
|
|
2274
|
-
await mkdir3(
|
|
2309
|
+
await mkdir3(path11.join(input.baseDir, "exe", "output"), { recursive: true });
|
|
2310
|
+
await mkdir3(path11.join(input.baseDir, "exe", "research"), { recursive: true });
|
|
2275
2311
|
await ensureArchitectureDoc(input.baseDir, input.projectName);
|
|
2276
2312
|
await ensureGitignoreExe(input.baseDir);
|
|
2277
2313
|
} catch {
|
|
@@ -2307,9 +2343,9 @@ ${laneWarning}` : laneWarning;
|
|
|
2307
2343
|
});
|
|
2308
2344
|
if (input.baseDir) {
|
|
2309
2345
|
try {
|
|
2310
|
-
const EXE_OS_DIR =
|
|
2311
|
-
const mdPath =
|
|
2312
|
-
const mdDir =
|
|
2346
|
+
const EXE_OS_DIR = path11.join(os8.homedir(), ".exe-os");
|
|
2347
|
+
const mdPath = path11.join(EXE_OS_DIR, taskFile);
|
|
2348
|
+
const mdDir = path11.dirname(mdPath);
|
|
2313
2349
|
if (!existsSync10(mdDir)) await mkdir3(mdDir, { recursive: true });
|
|
2314
2350
|
const reviewer = input.reviewer ?? input.assignedBy;
|
|
2315
2351
|
const mdContent = `# ${input.title}
|
|
@@ -2610,7 +2646,7 @@ async function deleteTaskCore(taskId, _baseDir) {
|
|
|
2610
2646
|
return { taskFile, assignedTo, assignedBy, taskSlug };
|
|
2611
2647
|
}
|
|
2612
2648
|
async function ensureArchitectureDoc(baseDir, projectName) {
|
|
2613
|
-
const archPath =
|
|
2649
|
+
const archPath = path11.join(baseDir, "exe", "ARCHITECTURE.md");
|
|
2614
2650
|
try {
|
|
2615
2651
|
if (existsSync10(archPath)) return;
|
|
2616
2652
|
const template = [
|
|
@@ -2645,7 +2681,7 @@ async function ensureArchitectureDoc(baseDir, projectName) {
|
|
|
2645
2681
|
}
|
|
2646
2682
|
}
|
|
2647
2683
|
async function ensureGitignoreExe(baseDir) {
|
|
2648
|
-
const gitignorePath =
|
|
2684
|
+
const gitignorePath = path11.join(baseDir, ".gitignore");
|
|
2649
2685
|
try {
|
|
2650
2686
|
if (existsSync10(gitignorePath)) {
|
|
2651
2687
|
const content = readFileSync10(gitignorePath, "utf-8");
|
|
@@ -2679,13 +2715,13 @@ var init_tasks_crud = __esm({
|
|
|
2679
2715
|
});
|
|
2680
2716
|
|
|
2681
2717
|
// src/lib/tasks-review.ts
|
|
2682
|
-
import
|
|
2718
|
+
import path12 from "path";
|
|
2683
2719
|
import { existsSync as existsSync11, readdirSync as readdirSync3, unlinkSync as unlinkSync4 } from "fs";
|
|
2684
2720
|
async function countPendingReviews(sessionScope) {
|
|
2685
2721
|
const client = getClient();
|
|
2686
2722
|
if (sessionScope) {
|
|
2687
2723
|
const result2 = await client.execute({
|
|
2688
|
-
sql: "SELECT COUNT(*) as cnt FROM tasks WHERE status = 'needs_review' AND
|
|
2724
|
+
sql: "SELECT COUNT(*) as cnt FROM tasks WHERE status = 'needs_review' AND session_scope = ?",
|
|
2689
2725
|
args: [sessionScope]
|
|
2690
2726
|
});
|
|
2691
2727
|
return Number(result2.rows[0]?.cnt) || 0;
|
|
@@ -2861,11 +2897,11 @@ async function cleanupReviewFile(row, taskFile, _baseDir) {
|
|
|
2861
2897
|
);
|
|
2862
2898
|
}
|
|
2863
2899
|
try {
|
|
2864
|
-
const cacheDir =
|
|
2900
|
+
const cacheDir = path12.join(EXE_AI_DIR, "session-cache");
|
|
2865
2901
|
if (existsSync11(cacheDir)) {
|
|
2866
2902
|
for (const f of readdirSync3(cacheDir)) {
|
|
2867
2903
|
if (f.startsWith("review-notified-")) {
|
|
2868
|
-
unlinkSync4(
|
|
2904
|
+
unlinkSync4(path12.join(cacheDir, f));
|
|
2869
2905
|
}
|
|
2870
2906
|
}
|
|
2871
2907
|
}
|
|
@@ -2886,7 +2922,7 @@ var init_tasks_review = __esm({
|
|
|
2886
2922
|
});
|
|
2887
2923
|
|
|
2888
2924
|
// src/lib/tasks-chain.ts
|
|
2889
|
-
import
|
|
2925
|
+
import path13 from "path";
|
|
2890
2926
|
import { readFile as readFile3, writeFile as writeFile4 } from "fs/promises";
|
|
2891
2927
|
async function cascadeUnblock(taskId, baseDir, now) {
|
|
2892
2928
|
const client = getClient();
|
|
@@ -2903,7 +2939,7 @@ async function cascadeUnblock(taskId, baseDir, now) {
|
|
|
2903
2939
|
});
|
|
2904
2940
|
for (const ur of unblockedRows.rows) {
|
|
2905
2941
|
try {
|
|
2906
|
-
const ubFile =
|
|
2942
|
+
const ubFile = path13.join(baseDir, String(ur.task_file));
|
|
2907
2943
|
let ubContent = await readFile3(ubFile, "utf-8");
|
|
2908
2944
|
ubContent = ubContent.replace(/\*\*Status:\*\* blocked/, "**Status:** open");
|
|
2909
2945
|
ubContent = ubContent.replace(/\n\*\*Blocked by:\*\*.*\n/, "\n");
|
|
@@ -2972,7 +3008,7 @@ var init_tasks_chain = __esm({
|
|
|
2972
3008
|
|
|
2973
3009
|
// src/lib/project-name.ts
|
|
2974
3010
|
import { execSync as execSync6 } from "child_process";
|
|
2975
|
-
import
|
|
3011
|
+
import path14 from "path";
|
|
2976
3012
|
function getProjectName(cwd) {
|
|
2977
3013
|
const dir = cwd ?? process.cwd();
|
|
2978
3014
|
if (_cached2 && _cachedCwd === dir) return _cached2;
|
|
@@ -2985,7 +3021,7 @@ function getProjectName(cwd) {
|
|
|
2985
3021
|
timeout: 2e3,
|
|
2986
3022
|
stdio: ["pipe", "pipe", "pipe"]
|
|
2987
3023
|
}).trim();
|
|
2988
|
-
repoRoot =
|
|
3024
|
+
repoRoot = path14.dirname(gitCommonDir);
|
|
2989
3025
|
} catch {
|
|
2990
3026
|
repoRoot = execSync6("git rev-parse --show-toplevel", {
|
|
2991
3027
|
cwd: dir,
|
|
@@ -2994,11 +3030,11 @@ function getProjectName(cwd) {
|
|
|
2994
3030
|
stdio: ["pipe", "pipe", "pipe"]
|
|
2995
3031
|
}).trim();
|
|
2996
3032
|
}
|
|
2997
|
-
_cached2 =
|
|
3033
|
+
_cached2 = path14.basename(repoRoot);
|
|
2998
3034
|
_cachedCwd = dir;
|
|
2999
3035
|
return _cached2;
|
|
3000
3036
|
} catch {
|
|
3001
|
-
_cached2 =
|
|
3037
|
+
_cached2 = path14.basename(dir);
|
|
3002
3038
|
_cachedCwd = dir;
|
|
3003
3039
|
return _cached2;
|
|
3004
3040
|
}
|
|
@@ -3471,7 +3507,7 @@ __export(tasks_exports, {
|
|
|
3471
3507
|
updateTaskStatus: () => updateTaskStatus,
|
|
3472
3508
|
writeCheckpoint: () => writeCheckpoint
|
|
3473
3509
|
});
|
|
3474
|
-
import
|
|
3510
|
+
import path15 from "path";
|
|
3475
3511
|
import { writeFileSync as writeFileSync7, mkdirSync as mkdirSync6, unlinkSync as unlinkSync5 } from "fs";
|
|
3476
3512
|
async function createTask(input) {
|
|
3477
3513
|
const result = await createTaskCore(input);
|
|
@@ -3491,8 +3527,8 @@ async function updateTask(input) {
|
|
|
3491
3527
|
const { row, taskFile, now, taskId } = await updateTaskStatus(input);
|
|
3492
3528
|
try {
|
|
3493
3529
|
const agent = String(row.assigned_to);
|
|
3494
|
-
const cacheDir =
|
|
3495
|
-
const cachePath =
|
|
3530
|
+
const cacheDir = path15.join(EXE_AI_DIR, "session-cache");
|
|
3531
|
+
const cachePath = path15.join(cacheDir, `current-task-${agent}.json`);
|
|
3496
3532
|
if (input.status === "in_progress") {
|
|
3497
3533
|
mkdirSync6(cacheDir, { recursive: true });
|
|
3498
3534
|
writeFileSync7(cachePath, JSON.stringify({ taskId, title: String(row.title) }));
|