@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
|
@@ -154,7 +154,7 @@ function baseAgentName(name, employees) {
|
|
|
154
154
|
if (getEmployee(roster, base)) return base;
|
|
155
155
|
return name;
|
|
156
156
|
}
|
|
157
|
-
var EMPLOYEES_PATH, DEFAULT_COORDINATOR_TEMPLATE_NAME, COORDINATOR_ROLE;
|
|
157
|
+
var EMPLOYEES_PATH, DEFAULT_COORDINATOR_TEMPLATE_NAME, COORDINATOR_ROLE, IDENTITY_DIR;
|
|
158
158
|
var init_employees = __esm({
|
|
159
159
|
"src/lib/employees.ts"() {
|
|
160
160
|
"use strict";
|
|
@@ -162,15 +162,40 @@ var init_employees = __esm({
|
|
|
162
162
|
EMPLOYEES_PATH = path2.join(EXE_AI_DIR, "exe-employees.json");
|
|
163
163
|
DEFAULT_COORDINATOR_TEMPLATE_NAME = "exe";
|
|
164
164
|
COORDINATOR_ROLE = "COO";
|
|
165
|
+
IDENTITY_DIR = path2.join(EXE_AI_DIR, "identity");
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
// src/lib/database-adapter.ts
|
|
170
|
+
import os3 from "os";
|
|
171
|
+
import path3 from "path";
|
|
172
|
+
import { createRequire } from "module";
|
|
173
|
+
import { pathToFileURL } from "url";
|
|
174
|
+
var BOOLEAN_COLUMNS_BY_TABLE, BOOLEAN_COLUMN_NAMES;
|
|
175
|
+
var init_database_adapter = __esm({
|
|
176
|
+
"src/lib/database-adapter.ts"() {
|
|
177
|
+
"use strict";
|
|
178
|
+
BOOLEAN_COLUMNS_BY_TABLE = {
|
|
179
|
+
memories: /* @__PURE__ */ new Set(["has_error", "draft"]),
|
|
180
|
+
behaviors: /* @__PURE__ */ new Set(["active"]),
|
|
181
|
+
notifications: /* @__PURE__ */ new Set(["read"]),
|
|
182
|
+
users: /* @__PURE__ */ new Set(["has_personal_memory"])
|
|
183
|
+
};
|
|
184
|
+
BOOLEAN_COLUMN_NAMES = new Set(
|
|
185
|
+
Object.values(BOOLEAN_COLUMNS_BY_TABLE).flatMap((cols) => [...cols])
|
|
186
|
+
);
|
|
165
187
|
}
|
|
166
188
|
});
|
|
167
189
|
|
|
168
190
|
// src/lib/database.ts
|
|
169
191
|
import { createClient } from "@libsql/client";
|
|
170
192
|
function getClient() {
|
|
171
|
-
if (!
|
|
193
|
+
if (!_adapterClient) {
|
|
172
194
|
throw new Error("Database client not initialized. Call initDatabase() first.");
|
|
173
195
|
}
|
|
196
|
+
if (process.env.DATABASE_URL) {
|
|
197
|
+
return _adapterClient;
|
|
198
|
+
}
|
|
174
199
|
if (process.env.EXE_IS_DAEMON === "1") {
|
|
175
200
|
return _resilientClient;
|
|
176
201
|
}
|
|
@@ -179,25 +204,27 @@ function getClient() {
|
|
|
179
204
|
}
|
|
180
205
|
return _resilientClient;
|
|
181
206
|
}
|
|
182
|
-
var _resilientClient, _daemonClient;
|
|
207
|
+
var _resilientClient, _daemonClient, _adapterClient;
|
|
183
208
|
var init_database = __esm({
|
|
184
209
|
"src/lib/database.ts"() {
|
|
185
210
|
"use strict";
|
|
186
211
|
init_db_retry();
|
|
187
212
|
init_employees();
|
|
213
|
+
init_database_adapter();
|
|
188
214
|
_resilientClient = null;
|
|
189
215
|
_daemonClient = null;
|
|
216
|
+
_adapterClient = null;
|
|
190
217
|
}
|
|
191
218
|
});
|
|
192
219
|
|
|
193
220
|
// src/lib/session-registry.ts
|
|
194
|
-
import
|
|
195
|
-
import
|
|
221
|
+
import path4 from "path";
|
|
222
|
+
import os4 from "os";
|
|
196
223
|
var REGISTRY_PATH;
|
|
197
224
|
var init_session_registry = __esm({
|
|
198
225
|
"src/lib/session-registry.ts"() {
|
|
199
226
|
"use strict";
|
|
200
|
-
REGISTRY_PATH =
|
|
227
|
+
REGISTRY_PATH = path4.join(os4.homedir(), ".exe-os", "session-registry.json");
|
|
201
228
|
}
|
|
202
229
|
});
|
|
203
230
|
|
|
@@ -434,7 +461,7 @@ var init_runtime_table = __esm({
|
|
|
434
461
|
|
|
435
462
|
// src/lib/agent-config.ts
|
|
436
463
|
import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, existsSync as existsSync3, mkdirSync } from "fs";
|
|
437
|
-
import
|
|
464
|
+
import path5 from "path";
|
|
438
465
|
function loadAgentConfig() {
|
|
439
466
|
if (!existsSync3(AGENT_CONFIG_PATH)) return {};
|
|
440
467
|
try {
|
|
@@ -457,7 +484,7 @@ var init_agent_config = __esm({
|
|
|
457
484
|
"use strict";
|
|
458
485
|
init_config();
|
|
459
486
|
init_runtime_table();
|
|
460
|
-
AGENT_CONFIG_PATH =
|
|
487
|
+
AGENT_CONFIG_PATH = path5.join(EXE_AI_DIR, "agent-config.json");
|
|
461
488
|
DEFAULT_MODELS = {
|
|
462
489
|
claude: "claude-opus-4",
|
|
463
490
|
codex: RUNTIME_TABLE.codex?.defaultModel ?? "gpt-5.4",
|
|
@@ -468,10 +495,10 @@ var init_agent_config = __esm({
|
|
|
468
495
|
|
|
469
496
|
// src/lib/intercom-queue.ts
|
|
470
497
|
import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, renameSync as renameSync3, existsSync as existsSync4, mkdirSync as mkdirSync2 } from "fs";
|
|
471
|
-
import
|
|
472
|
-
import
|
|
498
|
+
import path6 from "path";
|
|
499
|
+
import os5 from "os";
|
|
473
500
|
function ensureDir() {
|
|
474
|
-
const dir =
|
|
501
|
+
const dir = path6.dirname(QUEUE_PATH);
|
|
475
502
|
if (!existsSync4(dir)) mkdirSync2(dir, { recursive: true });
|
|
476
503
|
}
|
|
477
504
|
function readQueue() {
|
|
@@ -509,31 +536,31 @@ var QUEUE_PATH, TTL_MS, INTERCOM_LOG;
|
|
|
509
536
|
var init_intercom_queue = __esm({
|
|
510
537
|
"src/lib/intercom-queue.ts"() {
|
|
511
538
|
"use strict";
|
|
512
|
-
QUEUE_PATH =
|
|
539
|
+
QUEUE_PATH = path6.join(os5.homedir(), ".exe-os", "intercom-queue.json");
|
|
513
540
|
TTL_MS = 60 * 60 * 1e3;
|
|
514
|
-
INTERCOM_LOG =
|
|
541
|
+
INTERCOM_LOG = path6.join(os5.homedir(), ".exe-os", "intercom.log");
|
|
515
542
|
}
|
|
516
543
|
});
|
|
517
544
|
|
|
518
545
|
// src/lib/license.ts
|
|
519
546
|
import { readFileSync as readFileSync5, writeFileSync as writeFileSync4, existsSync as existsSync5, mkdirSync as mkdirSync3 } from "fs";
|
|
520
547
|
import { randomUUID } from "crypto";
|
|
521
|
-
import
|
|
548
|
+
import path7 from "path";
|
|
522
549
|
import { jwtVerify, importSPKI } from "jose";
|
|
523
550
|
var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH;
|
|
524
551
|
var init_license = __esm({
|
|
525
552
|
"src/lib/license.ts"() {
|
|
526
553
|
"use strict";
|
|
527
554
|
init_config();
|
|
528
|
-
LICENSE_PATH =
|
|
529
|
-
CACHE_PATH =
|
|
530
|
-
DEVICE_ID_PATH =
|
|
555
|
+
LICENSE_PATH = path7.join(EXE_AI_DIR, "license.key");
|
|
556
|
+
CACHE_PATH = path7.join(EXE_AI_DIR, "license-cache.json");
|
|
557
|
+
DEVICE_ID_PATH = path7.join(EXE_AI_DIR, "device-id");
|
|
531
558
|
}
|
|
532
559
|
});
|
|
533
560
|
|
|
534
561
|
// src/lib/plan-limits.ts
|
|
535
562
|
import { readFileSync as readFileSync6, existsSync as existsSync6 } from "fs";
|
|
536
|
-
import
|
|
563
|
+
import path8 from "path";
|
|
537
564
|
var CACHE_PATH2;
|
|
538
565
|
var init_plan_limits = __esm({
|
|
539
566
|
"src/lib/plan-limits.ts"() {
|
|
@@ -542,15 +569,15 @@ var init_plan_limits = __esm({
|
|
|
542
569
|
init_employees();
|
|
543
570
|
init_license();
|
|
544
571
|
init_config();
|
|
545
|
-
CACHE_PATH2 =
|
|
572
|
+
CACHE_PATH2 = path8.join(EXE_AI_DIR, "license-cache.json");
|
|
546
573
|
}
|
|
547
574
|
});
|
|
548
575
|
|
|
549
576
|
// src/lib/tmux-routing.ts
|
|
550
577
|
import { execFileSync as execFileSync2, execSync as execSync4 } from "child_process";
|
|
551
578
|
import { readFileSync as readFileSync7, writeFileSync as writeFileSync5, mkdirSync as mkdirSync4, existsSync as existsSync7, appendFileSync, readdirSync } from "fs";
|
|
552
|
-
import
|
|
553
|
-
import
|
|
579
|
+
import path9 from "path";
|
|
580
|
+
import os6 from "os";
|
|
554
581
|
import { fileURLToPath } from "url";
|
|
555
582
|
function getMySession() {
|
|
556
583
|
return getTransport().getMySession();
|
|
@@ -590,7 +617,7 @@ function extractRootExe(name) {
|
|
|
590
617
|
}
|
|
591
618
|
function getParentExe(sessionKey) {
|
|
592
619
|
try {
|
|
593
|
-
const data = JSON.parse(readFileSync7(
|
|
620
|
+
const data = JSON.parse(readFileSync7(path9.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
|
|
594
621
|
return data.parentExe || null;
|
|
595
622
|
} catch {
|
|
596
623
|
return null;
|
|
@@ -599,15 +626,24 @@ function getParentExe(sessionKey) {
|
|
|
599
626
|
function resolveExeSession() {
|
|
600
627
|
const mySession = getMySession();
|
|
601
628
|
if (!mySession) return null;
|
|
629
|
+
const fromSessionName = extractRootExe(mySession);
|
|
602
630
|
try {
|
|
603
631
|
const key = getSessionKey();
|
|
604
632
|
const parentExe = getParentExe(key);
|
|
605
633
|
if (parentExe) {
|
|
606
|
-
|
|
634
|
+
const fromCache = extractRootExe(parentExe) ?? parentExe;
|
|
635
|
+
if (fromSessionName && fromCache !== fromSessionName) {
|
|
636
|
+
process.stderr.write(
|
|
637
|
+
`[tmux-routing] WARN: cache says "${fromCache}" but session name says "${fromSessionName}". Trusting session name.
|
|
638
|
+
`
|
|
639
|
+
);
|
|
640
|
+
return fromSessionName;
|
|
641
|
+
}
|
|
642
|
+
return fromCache;
|
|
607
643
|
}
|
|
608
644
|
} catch {
|
|
609
645
|
}
|
|
610
|
-
return
|
|
646
|
+
return fromSessionName ?? mySession;
|
|
611
647
|
}
|
|
612
648
|
function isEmployeeAlive(sessionName) {
|
|
613
649
|
return getTransport().isAlive(sessionName);
|
|
@@ -726,7 +762,7 @@ function sendIntercom(targetSession) {
|
|
|
726
762
|
try {
|
|
727
763
|
const rawAgent = targetSession.split("-")[0] ?? targetSession;
|
|
728
764
|
const agent = baseAgentName(rawAgent);
|
|
729
|
-
const markerPath =
|
|
765
|
+
const markerPath = path9.join(SESSION_CACHE, `current-task-${agent}.json`);
|
|
730
766
|
if (existsSync7(markerPath)) {
|
|
731
767
|
logIntercom(`SKIP \u2192 ${targetSession} (has in_progress task marker \u2014 will auto-chain)`);
|
|
732
768
|
return "debounced";
|
|
@@ -736,7 +772,7 @@ function sendIntercom(targetSession) {
|
|
|
736
772
|
try {
|
|
737
773
|
const rawAgent = targetSession.split("-")[0] ?? targetSession;
|
|
738
774
|
const agent = baseAgentName(rawAgent);
|
|
739
|
-
const taskDir =
|
|
775
|
+
const taskDir = path9.join(process.cwd(), "exe", agent);
|
|
740
776
|
if (existsSync7(taskDir)) {
|
|
741
777
|
const files = readdirSync(taskDir).filter(
|
|
742
778
|
(f) => f.endsWith(".md") && f !== "DONE.txt"
|
|
@@ -790,13 +826,13 @@ var init_tmux_routing = __esm({
|
|
|
790
826
|
init_intercom_queue();
|
|
791
827
|
init_plan_limits();
|
|
792
828
|
init_employees();
|
|
793
|
-
SPAWN_LOCK_DIR =
|
|
794
|
-
SESSION_CACHE =
|
|
829
|
+
SPAWN_LOCK_DIR = path9.join(os6.homedir(), ".exe-os", "spawn-locks");
|
|
830
|
+
SESSION_CACHE = path9.join(os6.homedir(), ".exe-os", "session-cache");
|
|
795
831
|
VALID_SESSION_NAME = /^[a-z]+\d*-[a-zA-Z0-9_]+$/;
|
|
796
832
|
INTERCOM_DEBOUNCE_MS = 3e4;
|
|
797
833
|
CODEX_DEBOUNCE_MS = 12e4;
|
|
798
|
-
INTERCOM_LOG2 =
|
|
799
|
-
DEBOUNCE_FILE =
|
|
834
|
+
INTERCOM_LOG2 = path9.join(os6.homedir(), ".exe-os", "intercom.log");
|
|
835
|
+
DEBOUNCE_FILE = path9.join(SESSION_CACHE, "intercom-debounce.json");
|
|
800
836
|
DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
|
|
801
837
|
BUSY_PATTERN = /[✻✽✶✳·].*…|Running…|• Working|• Ran |• Explored|• Called|esc to interrupt/;
|
|
802
838
|
}
|
|
@@ -953,8 +989,8 @@ init_session_key();
|
|
|
953
989
|
init_employees();
|
|
954
990
|
import { readFileSync as readFileSync8, writeFileSync as writeFileSync6, mkdirSync as mkdirSync5, unlinkSync as unlinkSync2, readdirSync as readdirSync2 } from "fs";
|
|
955
991
|
import { execSync as execSync5 } from "child_process";
|
|
956
|
-
import
|
|
957
|
-
var CACHE_DIR =
|
|
992
|
+
import path10 from "path";
|
|
993
|
+
var CACHE_DIR = path10.join(EXE_AI_DIR, "session-cache");
|
|
958
994
|
var STALE_MS = 24 * 60 * 60 * 1e3;
|
|
959
995
|
function isNameWithOptionalInstance(candidate, baseName) {
|
|
960
996
|
if (candidate === baseName) return true;
|
|
@@ -999,7 +1035,7 @@ function resolveActiveAgentFromTmuxSession(sessionName) {
|
|
|
999
1035
|
return null;
|
|
1000
1036
|
}
|
|
1001
1037
|
function getMarkerPath() {
|
|
1002
|
-
return
|
|
1038
|
+
return path10.join(CACHE_DIR, `active-agent-${getSessionKey()}.json`);
|
|
1003
1039
|
}
|
|
1004
1040
|
function getActiveAgent() {
|
|
1005
1041
|
try {
|
|
@@ -259,7 +259,7 @@ function baseAgentName(name, employees) {
|
|
|
259
259
|
if (getEmployee(roster, base)) return base;
|
|
260
260
|
return name;
|
|
261
261
|
}
|
|
262
|
-
var EMPLOYEES_PATH, DEFAULT_COORDINATOR_TEMPLATE_NAME, COORDINATOR_ROLE;
|
|
262
|
+
var EMPLOYEES_PATH, DEFAULT_COORDINATOR_TEMPLATE_NAME, COORDINATOR_ROLE, IDENTITY_DIR;
|
|
263
263
|
var init_employees = __esm({
|
|
264
264
|
"src/lib/employees.ts"() {
|
|
265
265
|
"use strict";
|
|
@@ -267,15 +267,40 @@ var init_employees = __esm({
|
|
|
267
267
|
EMPLOYEES_PATH = path2.join(EXE_AI_DIR, "exe-employees.json");
|
|
268
268
|
DEFAULT_COORDINATOR_TEMPLATE_NAME = "exe";
|
|
269
269
|
COORDINATOR_ROLE = "COO";
|
|
270
|
+
IDENTITY_DIR = path2.join(EXE_AI_DIR, "identity");
|
|
271
|
+
}
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
// src/lib/database-adapter.ts
|
|
275
|
+
import os3 from "os";
|
|
276
|
+
import path3 from "path";
|
|
277
|
+
import { createRequire } from "module";
|
|
278
|
+
import { pathToFileURL } from "url";
|
|
279
|
+
var BOOLEAN_COLUMNS_BY_TABLE, BOOLEAN_COLUMN_NAMES;
|
|
280
|
+
var init_database_adapter = __esm({
|
|
281
|
+
"src/lib/database-adapter.ts"() {
|
|
282
|
+
"use strict";
|
|
283
|
+
BOOLEAN_COLUMNS_BY_TABLE = {
|
|
284
|
+
memories: /* @__PURE__ */ new Set(["has_error", "draft"]),
|
|
285
|
+
behaviors: /* @__PURE__ */ new Set(["active"]),
|
|
286
|
+
notifications: /* @__PURE__ */ new Set(["read"]),
|
|
287
|
+
users: /* @__PURE__ */ new Set(["has_personal_memory"])
|
|
288
|
+
};
|
|
289
|
+
BOOLEAN_COLUMN_NAMES = new Set(
|
|
290
|
+
Object.values(BOOLEAN_COLUMNS_BY_TABLE).flatMap((cols) => [...cols])
|
|
291
|
+
);
|
|
270
292
|
}
|
|
271
293
|
});
|
|
272
294
|
|
|
273
295
|
// src/lib/database.ts
|
|
274
296
|
import { createClient } from "@libsql/client";
|
|
275
297
|
function getClient() {
|
|
276
|
-
if (!
|
|
298
|
+
if (!_adapterClient) {
|
|
277
299
|
throw new Error("Database client not initialized. Call initDatabase() first.");
|
|
278
300
|
}
|
|
301
|
+
if (process.env.DATABASE_URL) {
|
|
302
|
+
return _adapterClient;
|
|
303
|
+
}
|
|
279
304
|
if (process.env.EXE_IS_DAEMON === "1") {
|
|
280
305
|
return _resilientClient;
|
|
281
306
|
}
|
|
@@ -284,21 +309,23 @@ function getClient() {
|
|
|
284
309
|
}
|
|
285
310
|
return _resilientClient;
|
|
286
311
|
}
|
|
287
|
-
var _resilientClient, _daemonClient;
|
|
312
|
+
var _resilientClient, _daemonClient, _adapterClient;
|
|
288
313
|
var init_database = __esm({
|
|
289
314
|
"src/lib/database.ts"() {
|
|
290
315
|
"use strict";
|
|
291
316
|
init_db_retry();
|
|
292
317
|
init_employees();
|
|
318
|
+
init_database_adapter();
|
|
293
319
|
_resilientClient = null;
|
|
294
320
|
_daemonClient = null;
|
|
321
|
+
_adapterClient = null;
|
|
295
322
|
}
|
|
296
323
|
});
|
|
297
324
|
|
|
298
325
|
// src/lib/notifications.ts
|
|
299
326
|
import crypto from "crypto";
|
|
300
|
-
import
|
|
301
|
-
import
|
|
327
|
+
import path4 from "path";
|
|
328
|
+
import os4 from "os";
|
|
302
329
|
import {
|
|
303
330
|
readFileSync as readFileSync3,
|
|
304
331
|
readdirSync,
|
|
@@ -403,13 +430,13 @@ var init_state_bus = __esm({
|
|
|
403
430
|
});
|
|
404
431
|
|
|
405
432
|
// src/lib/session-registry.ts
|
|
406
|
-
import
|
|
407
|
-
import
|
|
433
|
+
import path5 from "path";
|
|
434
|
+
import os5 from "os";
|
|
408
435
|
var REGISTRY_PATH;
|
|
409
436
|
var init_session_registry = __esm({
|
|
410
437
|
"src/lib/session-registry.ts"() {
|
|
411
438
|
"use strict";
|
|
412
|
-
REGISTRY_PATH =
|
|
439
|
+
REGISTRY_PATH = path5.join(os5.homedir(), ".exe-os", "session-registry.json");
|
|
413
440
|
}
|
|
414
441
|
});
|
|
415
442
|
|
|
@@ -646,7 +673,7 @@ var init_runtime_table = __esm({
|
|
|
646
673
|
|
|
647
674
|
// src/lib/agent-config.ts
|
|
648
675
|
import { readFileSync as readFileSync4, writeFileSync as writeFileSync2, existsSync as existsSync4, mkdirSync } from "fs";
|
|
649
|
-
import
|
|
676
|
+
import path6 from "path";
|
|
650
677
|
function loadAgentConfig() {
|
|
651
678
|
if (!existsSync4(AGENT_CONFIG_PATH)) return {};
|
|
652
679
|
try {
|
|
@@ -669,7 +696,7 @@ var init_agent_config = __esm({
|
|
|
669
696
|
"use strict";
|
|
670
697
|
init_config();
|
|
671
698
|
init_runtime_table();
|
|
672
|
-
AGENT_CONFIG_PATH =
|
|
699
|
+
AGENT_CONFIG_PATH = path6.join(EXE_AI_DIR, "agent-config.json");
|
|
673
700
|
DEFAULT_MODELS = {
|
|
674
701
|
claude: "claude-opus-4",
|
|
675
702
|
codex: RUNTIME_TABLE.codex?.defaultModel ?? "gpt-5.4",
|
|
@@ -688,10 +715,10 @@ __export(intercom_queue_exports, {
|
|
|
688
715
|
readQueue: () => readQueue
|
|
689
716
|
});
|
|
690
717
|
import { readFileSync as readFileSync5, writeFileSync as writeFileSync3, renameSync as renameSync3, existsSync as existsSync5, mkdirSync as mkdirSync2 } from "fs";
|
|
691
|
-
import
|
|
692
|
-
import
|
|
718
|
+
import path7 from "path";
|
|
719
|
+
import os6 from "os";
|
|
693
720
|
function ensureDir() {
|
|
694
|
-
const dir =
|
|
721
|
+
const dir = path7.dirname(QUEUE_PATH);
|
|
695
722
|
if (!existsSync5(dir)) mkdirSync2(dir, { recursive: true });
|
|
696
723
|
}
|
|
697
724
|
function readQueue() {
|
|
@@ -797,32 +824,32 @@ var QUEUE_PATH, MAX_RETRIES, TTL_MS, INTERCOM_LOG;
|
|
|
797
824
|
var init_intercom_queue = __esm({
|
|
798
825
|
"src/lib/intercom-queue.ts"() {
|
|
799
826
|
"use strict";
|
|
800
|
-
QUEUE_PATH =
|
|
827
|
+
QUEUE_PATH = path7.join(os6.homedir(), ".exe-os", "intercom-queue.json");
|
|
801
828
|
MAX_RETRIES = 5;
|
|
802
829
|
TTL_MS = 60 * 60 * 1e3;
|
|
803
|
-
INTERCOM_LOG =
|
|
830
|
+
INTERCOM_LOG = path7.join(os6.homedir(), ".exe-os", "intercom.log");
|
|
804
831
|
}
|
|
805
832
|
});
|
|
806
833
|
|
|
807
834
|
// src/lib/license.ts
|
|
808
835
|
import { readFileSync as readFileSync6, writeFileSync as writeFileSync4, existsSync as existsSync6, mkdirSync as mkdirSync3 } from "fs";
|
|
809
836
|
import { randomUUID } from "crypto";
|
|
810
|
-
import
|
|
837
|
+
import path8 from "path";
|
|
811
838
|
import { jwtVerify, importSPKI } from "jose";
|
|
812
839
|
var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH;
|
|
813
840
|
var init_license = __esm({
|
|
814
841
|
"src/lib/license.ts"() {
|
|
815
842
|
"use strict";
|
|
816
843
|
init_config();
|
|
817
|
-
LICENSE_PATH =
|
|
818
|
-
CACHE_PATH =
|
|
819
|
-
DEVICE_ID_PATH =
|
|
844
|
+
LICENSE_PATH = path8.join(EXE_AI_DIR, "license.key");
|
|
845
|
+
CACHE_PATH = path8.join(EXE_AI_DIR, "license-cache.json");
|
|
846
|
+
DEVICE_ID_PATH = path8.join(EXE_AI_DIR, "device-id");
|
|
820
847
|
}
|
|
821
848
|
});
|
|
822
849
|
|
|
823
850
|
// src/lib/plan-limits.ts
|
|
824
851
|
import { readFileSync as readFileSync7, existsSync as existsSync7 } from "fs";
|
|
825
|
-
import
|
|
852
|
+
import path9 from "path";
|
|
826
853
|
var CACHE_PATH2;
|
|
827
854
|
var init_plan_limits = __esm({
|
|
828
855
|
"src/lib/plan-limits.ts"() {
|
|
@@ -831,15 +858,15 @@ var init_plan_limits = __esm({
|
|
|
831
858
|
init_employees();
|
|
832
859
|
init_license();
|
|
833
860
|
init_config();
|
|
834
|
-
CACHE_PATH2 =
|
|
861
|
+
CACHE_PATH2 = path9.join(EXE_AI_DIR, "license-cache.json");
|
|
835
862
|
}
|
|
836
863
|
});
|
|
837
864
|
|
|
838
865
|
// src/lib/tmux-routing.ts
|
|
839
866
|
import { execFileSync as execFileSync2, execSync as execSync4 } from "child_process";
|
|
840
867
|
import { readFileSync as readFileSync8, writeFileSync as writeFileSync5, mkdirSync as mkdirSync4, existsSync as existsSync8, appendFileSync, readdirSync as readdirSync2 } from "fs";
|
|
841
|
-
import
|
|
842
|
-
import
|
|
868
|
+
import path10 from "path";
|
|
869
|
+
import os7 from "os";
|
|
843
870
|
import { fileURLToPath } from "url";
|
|
844
871
|
function getMySession() {
|
|
845
872
|
return getTransport().getMySession();
|
|
@@ -852,7 +879,7 @@ function extractRootExe(name) {
|
|
|
852
879
|
}
|
|
853
880
|
function getParentExe(sessionKey) {
|
|
854
881
|
try {
|
|
855
|
-
const data = JSON.parse(readFileSync8(
|
|
882
|
+
const data = JSON.parse(readFileSync8(path10.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
|
|
856
883
|
return data.parentExe || null;
|
|
857
884
|
} catch {
|
|
858
885
|
return null;
|
|
@@ -861,7 +888,7 @@ function getParentExe(sessionKey) {
|
|
|
861
888
|
function getDispatchedBy(sessionKey) {
|
|
862
889
|
try {
|
|
863
890
|
const data = JSON.parse(readFileSync8(
|
|
864
|
-
|
|
891
|
+
path10.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`),
|
|
865
892
|
"utf8"
|
|
866
893
|
));
|
|
867
894
|
return data.dispatchedBy ?? data.parentExe ?? null;
|
|
@@ -872,15 +899,24 @@ function getDispatchedBy(sessionKey) {
|
|
|
872
899
|
function resolveExeSession() {
|
|
873
900
|
const mySession = getMySession();
|
|
874
901
|
if (!mySession) return null;
|
|
902
|
+
const fromSessionName = extractRootExe(mySession);
|
|
875
903
|
try {
|
|
876
904
|
const key = getSessionKey();
|
|
877
905
|
const parentExe = getParentExe(key);
|
|
878
906
|
if (parentExe) {
|
|
879
|
-
|
|
907
|
+
const fromCache = extractRootExe(parentExe) ?? parentExe;
|
|
908
|
+
if (fromSessionName && fromCache !== fromSessionName) {
|
|
909
|
+
process.stderr.write(
|
|
910
|
+
`[tmux-routing] WARN: cache says "${fromCache}" but session name says "${fromSessionName}". Trusting session name.
|
|
911
|
+
`
|
|
912
|
+
);
|
|
913
|
+
return fromSessionName;
|
|
914
|
+
}
|
|
915
|
+
return fromCache;
|
|
880
916
|
}
|
|
881
917
|
} catch {
|
|
882
918
|
}
|
|
883
|
-
return
|
|
919
|
+
return fromSessionName ?? mySession;
|
|
884
920
|
}
|
|
885
921
|
function readDebounceState() {
|
|
886
922
|
try {
|
|
@@ -996,7 +1032,7 @@ function sendIntercom(targetSession) {
|
|
|
996
1032
|
try {
|
|
997
1033
|
const rawAgent = targetSession.split("-")[0] ?? targetSession;
|
|
998
1034
|
const agent = baseAgentName(rawAgent);
|
|
999
|
-
const markerPath =
|
|
1035
|
+
const markerPath = path10.join(SESSION_CACHE, `current-task-${agent}.json`);
|
|
1000
1036
|
if (existsSync8(markerPath)) {
|
|
1001
1037
|
logIntercom(`SKIP \u2192 ${targetSession} (has in_progress task marker \u2014 will auto-chain)`);
|
|
1002
1038
|
return "debounced";
|
|
@@ -1006,7 +1042,7 @@ function sendIntercom(targetSession) {
|
|
|
1006
1042
|
try {
|
|
1007
1043
|
const rawAgent = targetSession.split("-")[0] ?? targetSession;
|
|
1008
1044
|
const agent = baseAgentName(rawAgent);
|
|
1009
|
-
const taskDir =
|
|
1045
|
+
const taskDir = path10.join(process.cwd(), "exe", agent);
|
|
1010
1046
|
if (existsSync8(taskDir)) {
|
|
1011
1047
|
const files = readdirSync2(taskDir).filter(
|
|
1012
1048
|
(f) => f.endsWith(".md") && f !== "DONE.txt"
|
|
@@ -1082,12 +1118,12 @@ var init_tmux_routing = __esm({
|
|
|
1082
1118
|
init_intercom_queue();
|
|
1083
1119
|
init_plan_limits();
|
|
1084
1120
|
init_employees();
|
|
1085
|
-
SPAWN_LOCK_DIR =
|
|
1086
|
-
SESSION_CACHE =
|
|
1121
|
+
SPAWN_LOCK_DIR = path10.join(os7.homedir(), ".exe-os", "spawn-locks");
|
|
1122
|
+
SESSION_CACHE = path10.join(os7.homedir(), ".exe-os", "session-cache");
|
|
1087
1123
|
INTERCOM_DEBOUNCE_MS = 3e4;
|
|
1088
1124
|
CODEX_DEBOUNCE_MS = 12e4;
|
|
1089
|
-
INTERCOM_LOG2 =
|
|
1090
|
-
DEBOUNCE_FILE =
|
|
1125
|
+
INTERCOM_LOG2 = path10.join(os7.homedir(), ".exe-os", "intercom.log");
|
|
1126
|
+
DEBOUNCE_FILE = path10.join(SESSION_CACHE, "intercom-debounce.json");
|
|
1091
1127
|
DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
|
|
1092
1128
|
BUSY_PATTERN = /[✻✽✶✳·].*…|Running…|• Working|• Ran |• Explored|• Called|esc to interrupt/;
|
|
1093
1129
|
}
|
|
@@ -1119,8 +1155,8 @@ var init_task_scope = __esm({
|
|
|
1119
1155
|
|
|
1120
1156
|
// src/lib/tasks-crud.ts
|
|
1121
1157
|
import crypto2 from "crypto";
|
|
1122
|
-
import
|
|
1123
|
-
import
|
|
1158
|
+
import path11 from "path";
|
|
1159
|
+
import os8 from "os";
|
|
1124
1160
|
import { execSync as execSync5 } from "child_process";
|
|
1125
1161
|
import { mkdir as mkdir3, writeFile as writeFile3, appendFile } from "fs/promises";
|
|
1126
1162
|
import { existsSync as existsSync9, readFileSync as readFileSync9 } from "fs";
|
|
@@ -1419,7 +1455,7 @@ var init_tasks_crud = __esm({
|
|
|
1419
1455
|
});
|
|
1420
1456
|
|
|
1421
1457
|
// src/lib/tasks-review.ts
|
|
1422
|
-
import
|
|
1458
|
+
import path12 from "path";
|
|
1423
1459
|
import { existsSync as existsSync10, readdirSync as readdirSync3, unlinkSync as unlinkSync3 } from "fs";
|
|
1424
1460
|
async function cleanupReviewFile(row, taskFile, _baseDir) {
|
|
1425
1461
|
if (String(row.assigned_by) !== "system" || !taskFile.includes("review-")) return;
|
|
@@ -1465,11 +1501,11 @@ async function cleanupReviewFile(row, taskFile, _baseDir) {
|
|
|
1465
1501
|
);
|
|
1466
1502
|
}
|
|
1467
1503
|
try {
|
|
1468
|
-
const cacheDir =
|
|
1504
|
+
const cacheDir = path12.join(EXE_AI_DIR, "session-cache");
|
|
1469
1505
|
if (existsSync10(cacheDir)) {
|
|
1470
1506
|
for (const f of readdirSync3(cacheDir)) {
|
|
1471
1507
|
if (f.startsWith("review-notified-")) {
|
|
1472
|
-
unlinkSync3(
|
|
1508
|
+
unlinkSync3(path12.join(cacheDir, f));
|
|
1473
1509
|
}
|
|
1474
1510
|
}
|
|
1475
1511
|
}
|
|
@@ -1490,7 +1526,7 @@ var init_tasks_review = __esm({
|
|
|
1490
1526
|
});
|
|
1491
1527
|
|
|
1492
1528
|
// src/lib/tasks-chain.ts
|
|
1493
|
-
import
|
|
1529
|
+
import path13 from "path";
|
|
1494
1530
|
import { readFile as readFile3, writeFile as writeFile4 } from "fs/promises";
|
|
1495
1531
|
async function cascadeUnblock(taskId, baseDir, now) {
|
|
1496
1532
|
const client = getClient();
|
|
@@ -1507,7 +1543,7 @@ async function cascadeUnblock(taskId, baseDir, now) {
|
|
|
1507
1543
|
});
|
|
1508
1544
|
for (const ur of unblockedRows.rows) {
|
|
1509
1545
|
try {
|
|
1510
|
-
const ubFile =
|
|
1546
|
+
const ubFile = path13.join(baseDir, String(ur.task_file));
|
|
1511
1547
|
let ubContent = await readFile3(ubFile, "utf-8");
|
|
1512
1548
|
ubContent = ubContent.replace(/\*\*Status:\*\* blocked/, "**Status:** open");
|
|
1513
1549
|
ubContent = ubContent.replace(/\n\*\*Blocked by:\*\*.*\n/, "\n");
|
|
@@ -1910,14 +1946,14 @@ var init_skill_learning = __esm({
|
|
|
1910
1946
|
});
|
|
1911
1947
|
|
|
1912
1948
|
// src/lib/tasks.ts
|
|
1913
|
-
import
|
|
1949
|
+
import path14 from "path";
|
|
1914
1950
|
import { writeFileSync as writeFileSync6, mkdirSync as mkdirSync5, unlinkSync as unlinkSync4 } from "fs";
|
|
1915
1951
|
async function updateTask(input) {
|
|
1916
1952
|
const { row, taskFile, now, taskId } = await updateTaskStatus(input);
|
|
1917
1953
|
try {
|
|
1918
1954
|
const agent = String(row.assigned_to);
|
|
1919
|
-
const cacheDir =
|
|
1920
|
-
const cachePath =
|
|
1955
|
+
const cacheDir = path14.join(EXE_AI_DIR, "session-cache");
|
|
1956
|
+
const cachePath = path14.join(cacheDir, `current-task-${agent}.json`);
|
|
1921
1957
|
if (input.status === "in_progress") {
|
|
1922
1958
|
mkdirSync5(cacheDir, { recursive: true });
|
|
1923
1959
|
writeFileSync6(cachePath, JSON.stringify({ taskId, title: String(row.title) }));
|
|
@@ -2074,7 +2110,7 @@ __export(active_agent_exports, {
|
|
|
2074
2110
|
});
|
|
2075
2111
|
import { readFileSync as readFileSync10, writeFileSync as writeFileSync7, mkdirSync as mkdirSync6, unlinkSync as unlinkSync5, readdirSync as readdirSync4 } from "fs";
|
|
2076
2112
|
import { execSync as execSync6 } from "child_process";
|
|
2077
|
-
import
|
|
2113
|
+
import path15 from "path";
|
|
2078
2114
|
function isNameWithOptionalInstance(candidate, baseName) {
|
|
2079
2115
|
if (candidate === baseName) return true;
|
|
2080
2116
|
if (!candidate.startsWith(baseName)) return false;
|
|
@@ -2118,7 +2154,7 @@ function resolveActiveAgentFromTmuxSession(sessionName) {
|
|
|
2118
2154
|
return null;
|
|
2119
2155
|
}
|
|
2120
2156
|
function getMarkerPath() {
|
|
2121
|
-
return
|
|
2157
|
+
return path15.join(CACHE_DIR, `active-agent-${getSessionKey()}.json`);
|
|
2122
2158
|
}
|
|
2123
2159
|
function writeActiveAgent(agentId, agentRole) {
|
|
2124
2160
|
try {
|
|
@@ -2187,14 +2223,14 @@ function getAllActiveAgents() {
|
|
|
2187
2223
|
const key = file.slice("active-agent-".length, -".json".length);
|
|
2188
2224
|
if (key === "undefined") continue;
|
|
2189
2225
|
try {
|
|
2190
|
-
const raw = readFileSync10(
|
|
2226
|
+
const raw = readFileSync10(path15.join(CACHE_DIR, file), "utf8");
|
|
2191
2227
|
const data = JSON.parse(raw);
|
|
2192
2228
|
if (!data.agentId) continue;
|
|
2193
2229
|
if (data.startedAt) {
|
|
2194
2230
|
const age = Date.now() - new Date(data.startedAt).getTime();
|
|
2195
2231
|
if (age > STALE_MS) {
|
|
2196
2232
|
try {
|
|
2197
|
-
unlinkSync5(
|
|
2233
|
+
unlinkSync5(path15.join(CACHE_DIR, file));
|
|
2198
2234
|
} catch {
|
|
2199
2235
|
}
|
|
2200
2236
|
continue;
|
|
@@ -2217,11 +2253,11 @@ function getAllActiveAgents() {
|
|
|
2217
2253
|
function cleanupSessionMarkers() {
|
|
2218
2254
|
const key = getSessionKey();
|
|
2219
2255
|
try {
|
|
2220
|
-
unlinkSync5(
|
|
2256
|
+
unlinkSync5(path15.join(CACHE_DIR, `active-agent-${key}.json`));
|
|
2221
2257
|
} catch {
|
|
2222
2258
|
}
|
|
2223
2259
|
try {
|
|
2224
|
-
unlinkSync5(
|
|
2260
|
+
unlinkSync5(path15.join(CACHE_DIR, "active-agent-undefined.json"));
|
|
2225
2261
|
} catch {
|
|
2226
2262
|
}
|
|
2227
2263
|
}
|
|
@@ -2232,7 +2268,7 @@ var init_active_agent = __esm({
|
|
|
2232
2268
|
init_config();
|
|
2233
2269
|
init_session_key();
|
|
2234
2270
|
init_employees();
|
|
2235
|
-
CACHE_DIR =
|
|
2271
|
+
CACHE_DIR = path15.join(EXE_AI_DIR, "session-cache");
|
|
2236
2272
|
STALE_MS = 24 * 60 * 60 * 1e3;
|
|
2237
2273
|
}
|
|
2238
2274
|
});
|