@askexenow/exe-os 0.9.8 → 0.9.9
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 +222 -49
- package/dist/bin/backfill-responses.js +221 -48
- package/dist/bin/backfill-vectors.js +225 -52
- package/dist/bin/cleanup-stale-review-tasks.js +150 -28
- package/dist/bin/cli.js +1295 -856
- package/dist/bin/exe-agent-config.js +36 -8
- package/dist/bin/exe-agent.js +14 -4
- package/dist/bin/exe-assign.js +221 -48
- package/dist/bin/exe-boot.js +778 -427
- package/dist/bin/exe-call.js +41 -13
- package/dist/bin/exe-cloud.js +163 -58
- package/dist/bin/exe-dispatch.js +276 -139
- package/dist/bin/exe-doctor.js +145 -27
- package/dist/bin/exe-export-behaviors.js +141 -23
- package/dist/bin/exe-forget.js +137 -19
- package/dist/bin/exe-gateway.js +677 -388
- package/dist/bin/exe-heartbeat.js +227 -108
- package/dist/bin/exe-kill.js +138 -20
- package/dist/bin/exe-launch-agent.js +172 -39
- package/dist/bin/exe-link.js +291 -100
- package/dist/bin/exe-new-employee.js +214 -106
- package/dist/bin/exe-pending-messages.js +395 -33
- package/dist/bin/exe-pending-notifications.js +684 -99
- package/dist/bin/exe-pending-reviews.js +420 -74
- package/dist/bin/exe-rename.js +147 -49
- package/dist/bin/exe-review.js +138 -20
- package/dist/bin/exe-search.js +240 -69
- package/dist/bin/exe-session-cleanup.js +440 -250
- package/dist/bin/exe-settings.js +61 -17
- package/dist/bin/exe-start-codex.js +158 -39
- package/dist/bin/exe-start-opencode.js +157 -38
- package/dist/bin/exe-status.js +151 -29
- package/dist/bin/exe-team.js +138 -20
- package/dist/bin/git-sweep.js +404 -212
- package/dist/bin/graph-backfill.js +137 -19
- package/dist/bin/graph-export.js +140 -22
- package/dist/bin/install.js +90 -61
- package/dist/bin/scan-tasks.js +412 -220
- package/dist/bin/setup.js +564 -293
- package/dist/bin/shard-migrate.js +139 -21
- package/dist/bin/update.js +138 -49
- package/dist/bin/wiki-sync.js +137 -19
- package/dist/gateway/index.js +533 -320
- package/dist/hooks/bug-report-worker.js +344 -193
- package/dist/hooks/codex-stop-task-finalizer.js +4678 -0
- package/dist/hooks/commit-complete.js +402 -210
- package/dist/hooks/error-recall.js +245 -74
- package/dist/hooks/exe-heartbeat-hook.js +16 -6
- package/dist/hooks/ingest-worker.js +3423 -3157
- package/dist/hooks/ingest.js +832 -97
- package/dist/hooks/instructions-loaded.js +227 -54
- package/dist/hooks/notification.js +216 -43
- package/dist/hooks/post-compact.js +239 -62
- package/dist/hooks/pre-compact.js +408 -216
- package/dist/hooks/pre-tool-use.js +268 -90
- package/dist/hooks/prompt-ingest-worker.js +352 -102
- package/dist/hooks/prompt-submit.js +541 -328
- package/dist/hooks/response-ingest-worker.js +372 -122
- package/dist/hooks/session-end.js +443 -240
- package/dist/hooks/session-start.js +313 -127
- package/dist/hooks/stop.js +293 -98
- package/dist/hooks/subagent-stop.js +239 -62
- package/dist/hooks/summary-worker.js +568 -236
- package/dist/index.js +538 -324
- package/dist/lib/agent-config.js +28 -6
- package/dist/lib/cloud-sync.js +284 -105
- package/dist/lib/config.js +30 -10
- package/dist/lib/consolidation.js +16 -6
- package/dist/lib/database.js +123 -25
- package/dist/lib/db-daemon-client.js +73 -19
- package/dist/lib/db.js +123 -25
- package/dist/lib/device-registry.js +133 -35
- package/dist/lib/embedder.js +107 -32
- package/dist/lib/employee-templates.js +14 -4
- package/dist/lib/employees.js +41 -13
- package/dist/lib/exe-daemon-client.js +88 -22
- package/dist/lib/exe-daemon.js +935 -587
- package/dist/lib/hybrid-search.js +240 -69
- package/dist/lib/identity.js +18 -8
- package/dist/lib/license.js +133 -48
- package/dist/lib/messaging.js +116 -56
- package/dist/lib/reminders.js +14 -4
- package/dist/lib/schedules.js +137 -19
- package/dist/lib/skill-learning.js +33 -6
- package/dist/lib/store.js +137 -19
- package/dist/lib/task-router.js +14 -4
- package/dist/lib/tasks.js +280 -234
- package/dist/lib/tmux-routing.js +172 -125
- package/dist/lib/token-spend.js +26 -8
- package/dist/mcp/server.js +1326 -609
- package/dist/mcp/tools/complete-reminder.js +14 -4
- package/dist/mcp/tools/create-reminder.js +14 -4
- package/dist/mcp/tools/create-task.js +306 -248
- package/dist/mcp/tools/deactivate-behavior.js +16 -6
- package/dist/mcp/tools/list-reminders.js +14 -4
- package/dist/mcp/tools/list-tasks.js +123 -107
- package/dist/mcp/tools/send-message.js +75 -29
- package/dist/mcp/tools/update-task.js +1848 -199
- package/dist/runtime/index.js +441 -248
- package/dist/tui/App.js +761 -424
- package/package.json +1 -1
package/dist/bin/exe-gateway.js
CHANGED
|
@@ -392,6 +392,44 @@ var init_db_retry = __esm({
|
|
|
392
392
|
}
|
|
393
393
|
});
|
|
394
394
|
|
|
395
|
+
// src/lib/secure-files.ts
|
|
396
|
+
import { chmodSync, existsSync, mkdirSync } from "fs";
|
|
397
|
+
import { chmod, mkdir } from "fs/promises";
|
|
398
|
+
async function ensurePrivateDir(dirPath) {
|
|
399
|
+
await mkdir(dirPath, { recursive: true, mode: PRIVATE_DIR_MODE });
|
|
400
|
+
try {
|
|
401
|
+
await chmod(dirPath, PRIVATE_DIR_MODE);
|
|
402
|
+
} catch {
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
function ensurePrivateDirSync(dirPath) {
|
|
406
|
+
mkdirSync(dirPath, { recursive: true, mode: PRIVATE_DIR_MODE });
|
|
407
|
+
try {
|
|
408
|
+
chmodSync(dirPath, PRIVATE_DIR_MODE);
|
|
409
|
+
} catch {
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
async function enforcePrivateFile(filePath) {
|
|
413
|
+
try {
|
|
414
|
+
await chmod(filePath, PRIVATE_FILE_MODE);
|
|
415
|
+
} catch {
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
function enforcePrivateFileSync(filePath) {
|
|
419
|
+
try {
|
|
420
|
+
if (existsSync(filePath)) chmodSync(filePath, PRIVATE_FILE_MODE);
|
|
421
|
+
} catch {
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
var PRIVATE_DIR_MODE, PRIVATE_FILE_MODE;
|
|
425
|
+
var init_secure_files = __esm({
|
|
426
|
+
"src/lib/secure-files.ts"() {
|
|
427
|
+
"use strict";
|
|
428
|
+
PRIVATE_DIR_MODE = 448;
|
|
429
|
+
PRIVATE_FILE_MODE = 384;
|
|
430
|
+
}
|
|
431
|
+
});
|
|
432
|
+
|
|
395
433
|
// src/lib/config.ts
|
|
396
434
|
var config_exports = {};
|
|
397
435
|
__export(config_exports, {
|
|
@@ -408,8 +446,8 @@ __export(config_exports, {
|
|
|
408
446
|
migrateConfig: () => migrateConfig,
|
|
409
447
|
saveConfig: () => saveConfig
|
|
410
448
|
});
|
|
411
|
-
import { readFile, writeFile
|
|
412
|
-
import { readFileSync, existsSync, renameSync } from "fs";
|
|
449
|
+
import { readFile, writeFile } from "fs/promises";
|
|
450
|
+
import { readFileSync, existsSync as existsSync2, renameSync } from "fs";
|
|
413
451
|
import path from "path";
|
|
414
452
|
import os from "os";
|
|
415
453
|
function resolveDataDir() {
|
|
@@ -417,7 +455,7 @@ function resolveDataDir() {
|
|
|
417
455
|
if (process.env.EXE_MEM_DIR) return process.env.EXE_MEM_DIR;
|
|
418
456
|
const newDir = path.join(os.homedir(), ".exe-os");
|
|
419
457
|
const legacyDir = path.join(os.homedir(), ".exe-mem");
|
|
420
|
-
if (!
|
|
458
|
+
if (!existsSync2(newDir) && existsSync2(legacyDir)) {
|
|
421
459
|
try {
|
|
422
460
|
renameSync(legacyDir, newDir);
|
|
423
461
|
process.stderr.write(`[exe-os] Migrated data directory: ~/.exe-mem \u2192 ~/.exe-os
|
|
@@ -480,9 +518,9 @@ function normalizeAutoUpdate(raw) {
|
|
|
480
518
|
}
|
|
481
519
|
async function loadConfig() {
|
|
482
520
|
const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
|
|
483
|
-
await
|
|
521
|
+
await ensurePrivateDir(dir);
|
|
484
522
|
const configPath = path.join(dir, "config.json");
|
|
485
|
-
if (!
|
|
523
|
+
if (!existsSync2(configPath)) {
|
|
486
524
|
return { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db") };
|
|
487
525
|
}
|
|
488
526
|
const raw = await readFile(configPath, "utf-8");
|
|
@@ -495,6 +533,7 @@ async function loadConfig() {
|
|
|
495
533
|
`);
|
|
496
534
|
try {
|
|
497
535
|
await writeFile(configPath, JSON.stringify(migratedCfg, null, 2) + "\n");
|
|
536
|
+
await enforcePrivateFile(configPath);
|
|
498
537
|
} catch {
|
|
499
538
|
}
|
|
500
539
|
}
|
|
@@ -513,7 +552,7 @@ async function loadConfig() {
|
|
|
513
552
|
function loadConfigSync() {
|
|
514
553
|
const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
|
|
515
554
|
const configPath = path.join(dir, "config.json");
|
|
516
|
-
if (!
|
|
555
|
+
if (!existsSync2(configPath)) {
|
|
517
556
|
return { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db") };
|
|
518
557
|
}
|
|
519
558
|
try {
|
|
@@ -531,12 +570,10 @@ function loadConfigSync() {
|
|
|
531
570
|
}
|
|
532
571
|
async function saveConfig(config2) {
|
|
533
572
|
const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
|
|
534
|
-
await
|
|
573
|
+
await ensurePrivateDir(dir);
|
|
535
574
|
const configPath = path.join(dir, "config.json");
|
|
536
575
|
await writeFile(configPath, JSON.stringify(config2, null, 2) + "\n");
|
|
537
|
-
|
|
538
|
-
await chmod(configPath, 384);
|
|
539
|
-
}
|
|
576
|
+
await enforcePrivateFile(configPath);
|
|
540
577
|
}
|
|
541
578
|
async function loadConfigFrom(configPath) {
|
|
542
579
|
const raw = await readFile(configPath, "utf-8");
|
|
@@ -556,6 +593,7 @@ var EXE_AI_DIR, DB_PATH, MODELS_DIR, CONFIG_PATH, LEGACY_LANCE_PATH, CURRENT_CON
|
|
|
556
593
|
var init_config = __esm({
|
|
557
594
|
"src/lib/config.ts"() {
|
|
558
595
|
"use strict";
|
|
596
|
+
init_secure_files();
|
|
559
597
|
EXE_AI_DIR = resolveDataDir();
|
|
560
598
|
DB_PATH = path.join(EXE_AI_DIR, "memories.db");
|
|
561
599
|
MODELS_DIR = path.join(EXE_AI_DIR, "models");
|
|
@@ -672,10 +710,10 @@ __export(agent_config_exports, {
|
|
|
672
710
|
saveAgentConfig: () => saveAgentConfig,
|
|
673
711
|
setAgentRuntime: () => setAgentRuntime
|
|
674
712
|
});
|
|
675
|
-
import { readFileSync as readFileSync2, writeFileSync, existsSync as
|
|
713
|
+
import { readFileSync as readFileSync2, writeFileSync, existsSync as existsSync3 } from "fs";
|
|
676
714
|
import path2 from "path";
|
|
677
715
|
function loadAgentConfig() {
|
|
678
|
-
if (!
|
|
716
|
+
if (!existsSync3(AGENT_CONFIG_PATH)) return {};
|
|
679
717
|
try {
|
|
680
718
|
return JSON.parse(readFileSync2(AGENT_CONFIG_PATH, "utf-8"));
|
|
681
719
|
} catch {
|
|
@@ -684,8 +722,9 @@ function loadAgentConfig() {
|
|
|
684
722
|
}
|
|
685
723
|
function saveAgentConfig(config2) {
|
|
686
724
|
const dir = path2.dirname(AGENT_CONFIG_PATH);
|
|
687
|
-
|
|
725
|
+
ensurePrivateDirSync(dir);
|
|
688
726
|
writeFileSync(AGENT_CONFIG_PATH, JSON.stringify(config2, null, 2) + "\n", "utf-8");
|
|
727
|
+
enforcePrivateFileSync(AGENT_CONFIG_PATH);
|
|
689
728
|
}
|
|
690
729
|
function getAgentRuntime(agentId) {
|
|
691
730
|
const config2 = loadAgentConfig();
|
|
@@ -725,6 +764,7 @@ var init_agent_config = __esm({
|
|
|
725
764
|
"use strict";
|
|
726
765
|
init_config();
|
|
727
766
|
init_runtime_table();
|
|
767
|
+
init_secure_files();
|
|
728
768
|
AGENT_CONFIG_PATH = path2.join(EXE_AI_DIR, "agent-config.json");
|
|
729
769
|
KNOWN_RUNTIMES = {
|
|
730
770
|
claude: ["claude-opus-4", "claude-sonnet-4", "claude-haiku-4.5"],
|
|
@@ -772,7 +812,7 @@ __export(employees_exports, {
|
|
|
772
812
|
validateEmployeeName: () => validateEmployeeName
|
|
773
813
|
});
|
|
774
814
|
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
775
|
-
import { existsSync as
|
|
815
|
+
import { existsSync as existsSync4, symlinkSync, readlinkSync, readFileSync as readFileSync3, renameSync as renameSync2, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
|
|
776
816
|
import { execSync } from "child_process";
|
|
777
817
|
import path3 from "path";
|
|
778
818
|
import os2 from "os";
|
|
@@ -811,7 +851,7 @@ function validateEmployeeName(name) {
|
|
|
811
851
|
return { valid: true };
|
|
812
852
|
}
|
|
813
853
|
async function loadEmployees(employeesPath = EMPLOYEES_PATH) {
|
|
814
|
-
if (!
|
|
854
|
+
if (!existsSync4(employeesPath)) {
|
|
815
855
|
return [];
|
|
816
856
|
}
|
|
817
857
|
const raw = await readFile2(employeesPath, "utf-8");
|
|
@@ -826,7 +866,7 @@ async function saveEmployees(employees, employeesPath = EMPLOYEES_PATH) {
|
|
|
826
866
|
await writeFile2(employeesPath, JSON.stringify(employees, null, 2) + "\n", "utf-8");
|
|
827
867
|
}
|
|
828
868
|
function loadEmployeesSync(employeesPath = EMPLOYEES_PATH) {
|
|
829
|
-
if (!
|
|
869
|
+
if (!existsSync4(employeesPath)) return [];
|
|
830
870
|
try {
|
|
831
871
|
return JSON.parse(readFileSync3(employeesPath, "utf-8"));
|
|
832
872
|
} catch {
|
|
@@ -874,7 +914,7 @@ function appendToCoordinatorTeam(employee) {
|
|
|
874
914
|
const coordinator = getCoordinatorEmployee(loadEmployeesSync());
|
|
875
915
|
if (!coordinator) return;
|
|
876
916
|
const idPath = path3.join(IDENTITY_DIR, `${coordinator.name}.md`);
|
|
877
|
-
if (!
|
|
917
|
+
if (!existsSync4(idPath)) return;
|
|
878
918
|
const content = readFileSync3(idPath, "utf-8");
|
|
879
919
|
if (content.includes(`**${capitalize(employee.name)}`)) return;
|
|
880
920
|
const teamMatch = content.match(TEAM_SECTION_RE);
|
|
@@ -928,9 +968,9 @@ async function normalizeRosterCase(rosterPath) {
|
|
|
928
968
|
const identityDir = path3.join(os2.homedir(), ".exe-os", "identity");
|
|
929
969
|
const oldPath = path3.join(identityDir, `${oldName}.md`);
|
|
930
970
|
const newPath = path3.join(identityDir, `${emp.name}.md`);
|
|
931
|
-
if (
|
|
971
|
+
if (existsSync4(oldPath) && !existsSync4(newPath)) {
|
|
932
972
|
renameSync2(oldPath, newPath);
|
|
933
|
-
} else if (
|
|
973
|
+
} else if (existsSync4(oldPath) && oldPath !== newPath) {
|
|
934
974
|
const content = readFileSync3(oldPath, "utf-8");
|
|
935
975
|
writeFileSync2(newPath, content, "utf-8");
|
|
936
976
|
if (oldPath.toLowerCase() !== newPath.toLowerCase()) {
|
|
@@ -973,7 +1013,7 @@ function registerBinSymlinks(name) {
|
|
|
973
1013
|
for (const suffix of ["", "-opencode"]) {
|
|
974
1014
|
const linkName = `${name}${suffix}`;
|
|
975
1015
|
const linkPath = path3.join(binDir, linkName);
|
|
976
|
-
if (
|
|
1016
|
+
if (existsSync4(linkPath)) {
|
|
977
1017
|
skipped.push(linkName);
|
|
978
1018
|
continue;
|
|
979
1019
|
}
|
|
@@ -1926,6 +1966,7 @@ async function ensureSchema() {
|
|
|
1926
1966
|
project TEXT NOT NULL,
|
|
1927
1967
|
summary TEXT NOT NULL,
|
|
1928
1968
|
task_file TEXT,
|
|
1969
|
+
session_scope TEXT,
|
|
1929
1970
|
read INTEGER NOT NULL DEFAULT 0,
|
|
1930
1971
|
created_at TEXT NOT NULL
|
|
1931
1972
|
);
|
|
@@ -1934,7 +1975,7 @@ async function ensureSchema() {
|
|
|
1934
1975
|
ON notifications(read);
|
|
1935
1976
|
|
|
1936
1977
|
CREATE INDEX IF NOT EXISTS idx_notifications_agent
|
|
1937
|
-
ON notifications(agent_id);
|
|
1978
|
+
ON notifications(agent_id, session_scope);
|
|
1938
1979
|
|
|
1939
1980
|
CREATE INDEX IF NOT EXISTS idx_notifications_task_file
|
|
1940
1981
|
ON notifications(task_file);
|
|
@@ -1972,6 +2013,7 @@ async function ensureSchema() {
|
|
|
1972
2013
|
target_agent TEXT NOT NULL,
|
|
1973
2014
|
target_project TEXT,
|
|
1974
2015
|
target_device TEXT NOT NULL DEFAULT 'local',
|
|
2016
|
+
session_scope TEXT,
|
|
1975
2017
|
content TEXT NOT NULL,
|
|
1976
2018
|
priority TEXT DEFAULT 'normal',
|
|
1977
2019
|
status TEXT DEFAULT 'pending',
|
|
@@ -1985,10 +2027,31 @@ async function ensureSchema() {
|
|
|
1985
2027
|
);
|
|
1986
2028
|
|
|
1987
2029
|
CREATE INDEX IF NOT EXISTS idx_messages_target
|
|
1988
|
-
ON messages(target_agent, status);
|
|
2030
|
+
ON messages(target_agent, session_scope, status);
|
|
1989
2031
|
|
|
1990
2032
|
CREATE INDEX IF NOT EXISTS idx_messages_conversation_order
|
|
1991
|
-
ON messages(target_agent, from_agent, server_seq);
|
|
2033
|
+
ON messages(target_agent, session_scope, from_agent, server_seq);
|
|
2034
|
+
`);
|
|
2035
|
+
try {
|
|
2036
|
+
await client.execute({
|
|
2037
|
+
sql: `ALTER TABLE notifications ADD COLUMN session_scope TEXT`,
|
|
2038
|
+
args: []
|
|
2039
|
+
});
|
|
2040
|
+
} catch {
|
|
2041
|
+
}
|
|
2042
|
+
try {
|
|
2043
|
+
await client.execute({
|
|
2044
|
+
sql: `ALTER TABLE messages ADD COLUMN session_scope TEXT`,
|
|
2045
|
+
args: []
|
|
2046
|
+
});
|
|
2047
|
+
} catch {
|
|
2048
|
+
}
|
|
2049
|
+
await client.executeMultiple(`
|
|
2050
|
+
CREATE INDEX IF NOT EXISTS idx_notifications_agent_scope_read
|
|
2051
|
+
ON notifications(agent_id, session_scope, read, created_at);
|
|
2052
|
+
|
|
2053
|
+
CREATE INDEX IF NOT EXISTS idx_messages_target_scope_status
|
|
2054
|
+
ON messages(target_agent, session_scope, status, created_at);
|
|
1992
2055
|
`);
|
|
1993
2056
|
try {
|
|
1994
2057
|
await client.execute({
|
|
@@ -2572,6 +2635,13 @@ async function ensureSchema() {
|
|
|
2572
2635
|
} catch {
|
|
2573
2636
|
}
|
|
2574
2637
|
}
|
|
2638
|
+
try {
|
|
2639
|
+
await client.execute({
|
|
2640
|
+
sql: `UPDATE tasks SET status = 'closed' WHERE status = 'done' AND result IS NOT NULL`,
|
|
2641
|
+
args: []
|
|
2642
|
+
});
|
|
2643
|
+
} catch {
|
|
2644
|
+
}
|
|
2575
2645
|
}
|
|
2576
2646
|
async function disposeDatabase() {
|
|
2577
2647
|
if (_walCheckpointTimer) {
|
|
@@ -2618,13 +2688,50 @@ var init_memory = __esm({
|
|
|
2618
2688
|
}
|
|
2619
2689
|
});
|
|
2620
2690
|
|
|
2691
|
+
// src/lib/daemon-auth.ts
|
|
2692
|
+
import crypto from "crypto";
|
|
2693
|
+
import path5 from "path";
|
|
2694
|
+
import { existsSync as existsSync5, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "fs";
|
|
2695
|
+
function normalizeToken(token) {
|
|
2696
|
+
if (!token) return null;
|
|
2697
|
+
const trimmed = token.trim();
|
|
2698
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
2699
|
+
}
|
|
2700
|
+
function readDaemonToken() {
|
|
2701
|
+
try {
|
|
2702
|
+
if (!existsSync5(DAEMON_TOKEN_PATH)) return null;
|
|
2703
|
+
return normalizeToken(readFileSync4(DAEMON_TOKEN_PATH, "utf8"));
|
|
2704
|
+
} catch {
|
|
2705
|
+
return null;
|
|
2706
|
+
}
|
|
2707
|
+
}
|
|
2708
|
+
function ensureDaemonToken(seed) {
|
|
2709
|
+
const existing = readDaemonToken();
|
|
2710
|
+
if (existing) return existing;
|
|
2711
|
+
const token = normalizeToken(seed) ?? crypto.randomBytes(32).toString("hex");
|
|
2712
|
+
ensurePrivateDirSync(EXE_AI_DIR);
|
|
2713
|
+
writeFileSync3(DAEMON_TOKEN_PATH, `${token}
|
|
2714
|
+
`, "utf8");
|
|
2715
|
+
enforcePrivateFileSync(DAEMON_TOKEN_PATH);
|
|
2716
|
+
return token;
|
|
2717
|
+
}
|
|
2718
|
+
var DAEMON_TOKEN_PATH;
|
|
2719
|
+
var init_daemon_auth = __esm({
|
|
2720
|
+
"src/lib/daemon-auth.ts"() {
|
|
2721
|
+
"use strict";
|
|
2722
|
+
init_config();
|
|
2723
|
+
init_secure_files();
|
|
2724
|
+
DAEMON_TOKEN_PATH = path5.join(EXE_AI_DIR, "exed.token");
|
|
2725
|
+
}
|
|
2726
|
+
});
|
|
2727
|
+
|
|
2621
2728
|
// src/lib/exe-daemon-client.ts
|
|
2622
2729
|
import net from "net";
|
|
2623
2730
|
import os4 from "os";
|
|
2624
2731
|
import { spawn } from "child_process";
|
|
2625
2732
|
import { randomUUID } from "crypto";
|
|
2626
|
-
import { existsSync as
|
|
2627
|
-
import
|
|
2733
|
+
import { existsSync as existsSync6, unlinkSync as unlinkSync2, readFileSync as readFileSync5, openSync, closeSync, statSync } from "fs";
|
|
2734
|
+
import path6 from "path";
|
|
2628
2735
|
import { fileURLToPath } from "url";
|
|
2629
2736
|
function handleData(chunk) {
|
|
2630
2737
|
_buffer += chunk.toString();
|
|
@@ -2652,9 +2759,9 @@ function handleData(chunk) {
|
|
|
2652
2759
|
}
|
|
2653
2760
|
}
|
|
2654
2761
|
function cleanupStaleFiles() {
|
|
2655
|
-
if (
|
|
2762
|
+
if (existsSync6(PID_PATH)) {
|
|
2656
2763
|
try {
|
|
2657
|
-
const pid = parseInt(
|
|
2764
|
+
const pid = parseInt(readFileSync5(PID_PATH, "utf8").trim(), 10);
|
|
2658
2765
|
if (pid > 0) {
|
|
2659
2766
|
try {
|
|
2660
2767
|
process.kill(pid, 0);
|
|
@@ -2675,11 +2782,11 @@ function cleanupStaleFiles() {
|
|
|
2675
2782
|
}
|
|
2676
2783
|
}
|
|
2677
2784
|
function findPackageRoot() {
|
|
2678
|
-
let dir =
|
|
2679
|
-
const { root } =
|
|
2785
|
+
let dir = path6.dirname(fileURLToPath(import.meta.url));
|
|
2786
|
+
const { root } = path6.parse(dir);
|
|
2680
2787
|
while (dir !== root) {
|
|
2681
|
-
if (
|
|
2682
|
-
dir =
|
|
2788
|
+
if (existsSync6(path6.join(dir, "package.json"))) return dir;
|
|
2789
|
+
dir = path6.dirname(dir);
|
|
2683
2790
|
}
|
|
2684
2791
|
return null;
|
|
2685
2792
|
}
|
|
@@ -2705,16 +2812,17 @@ function spawnDaemon() {
|
|
|
2705
2812
|
process.stderr.write("[exed-client] WARN: cannot find package root\n");
|
|
2706
2813
|
return;
|
|
2707
2814
|
}
|
|
2708
|
-
const daemonPath =
|
|
2709
|
-
if (!
|
|
2815
|
+
const daemonPath = path6.join(pkgRoot, "dist", "lib", "exe-daemon.js");
|
|
2816
|
+
if (!existsSync6(daemonPath)) {
|
|
2710
2817
|
process.stderr.write(`[exed-client] WARN: daemon script not found at ${daemonPath}
|
|
2711
2818
|
`);
|
|
2712
2819
|
return;
|
|
2713
2820
|
}
|
|
2714
2821
|
const resolvedPath = daemonPath;
|
|
2822
|
+
const daemonToken = ensureDaemonToken(process.env[DAEMON_TOKEN_ENV] ?? null);
|
|
2715
2823
|
process.stderr.write(`[exed-client] Spawning daemon: ${resolvedPath}
|
|
2716
2824
|
`);
|
|
2717
|
-
const logPath =
|
|
2825
|
+
const logPath = path6.join(path6.dirname(SOCKET_PATH), "exed.log");
|
|
2718
2826
|
let stderrFd = "ignore";
|
|
2719
2827
|
try {
|
|
2720
2828
|
stderrFd = openSync(logPath, "a");
|
|
@@ -2732,7 +2840,8 @@ function spawnDaemon() {
|
|
|
2732
2840
|
TMUX_PANE: void 0,
|
|
2733
2841
|
// Prevents resolveExeSession() from scoping to one session
|
|
2734
2842
|
EXE_DAEMON_SOCK: SOCKET_PATH,
|
|
2735
|
-
EXE_DAEMON_PID: PID_PATH
|
|
2843
|
+
EXE_DAEMON_PID: PID_PATH,
|
|
2844
|
+
[DAEMON_TOKEN_ENV]: daemonToken
|
|
2736
2845
|
}
|
|
2737
2846
|
});
|
|
2738
2847
|
child.unref();
|
|
@@ -2842,13 +2951,14 @@ function sendDaemonRequest(payload, timeoutMs = REQUEST_TIMEOUT_MS) {
|
|
|
2842
2951
|
return;
|
|
2843
2952
|
}
|
|
2844
2953
|
const id = randomUUID();
|
|
2954
|
+
const token = process.env[DAEMON_TOKEN_ENV] ?? readDaemonToken();
|
|
2845
2955
|
const timer = setTimeout(() => {
|
|
2846
2956
|
_pending.delete(id);
|
|
2847
2957
|
resolve({ error: "Request timeout" });
|
|
2848
2958
|
}, timeoutMs);
|
|
2849
2959
|
_pending.set(id, { resolve, timer });
|
|
2850
2960
|
try {
|
|
2851
|
-
_socket.write(JSON.stringify({ id, ...payload }) + "\n");
|
|
2961
|
+
_socket.write(JSON.stringify({ id, token, ...payload }) + "\n");
|
|
2852
2962
|
} catch {
|
|
2853
2963
|
clearTimeout(timer);
|
|
2854
2964
|
_pending.delete(id);
|
|
@@ -2877,9 +2987,9 @@ function killAndRespawnDaemon() {
|
|
|
2877
2987
|
}
|
|
2878
2988
|
try {
|
|
2879
2989
|
process.stderr.write("[exed-client] Killing daemon for restart...\n");
|
|
2880
|
-
if (
|
|
2990
|
+
if (existsSync6(PID_PATH)) {
|
|
2881
2991
|
try {
|
|
2882
|
-
const pid = parseInt(
|
|
2992
|
+
const pid = parseInt(readFileSync5(PID_PATH, "utf8").trim(), 10);
|
|
2883
2993
|
if (pid > 0) {
|
|
2884
2994
|
try {
|
|
2885
2995
|
process.kill(pid, "SIGKILL");
|
|
@@ -2996,17 +3106,19 @@ function disconnectClient() {
|
|
|
2996
3106
|
entry.resolve({ error: "Client disconnected" });
|
|
2997
3107
|
}
|
|
2998
3108
|
}
|
|
2999
|
-
var SOCKET_PATH, PID_PATH, SPAWN_LOCK_PATH, SPAWN_LOCK_STALE_MS, CONNECT_TIMEOUT_MS, REQUEST_TIMEOUT_MS, _socket, _connected, _buffer, _requestCount, _consecutiveFailures, HEALTH_CHECK_INTERVAL, MAX_RETRIES_BEFORE_RESTART, RETRY_DELAYS_MS, MIN_DAEMON_AGE_MS, _pending, MAX_BUFFER;
|
|
3109
|
+
var SOCKET_PATH, PID_PATH, SPAWN_LOCK_PATH, SPAWN_LOCK_STALE_MS, CONNECT_TIMEOUT_MS, REQUEST_TIMEOUT_MS, DAEMON_TOKEN_ENV, _socket, _connected, _buffer, _requestCount, _consecutiveFailures, HEALTH_CHECK_INTERVAL, MAX_RETRIES_BEFORE_RESTART, RETRY_DELAYS_MS, MIN_DAEMON_AGE_MS, _pending, MAX_BUFFER;
|
|
3000
3110
|
var init_exe_daemon_client = __esm({
|
|
3001
3111
|
"src/lib/exe-daemon-client.ts"() {
|
|
3002
3112
|
"use strict";
|
|
3003
3113
|
init_config();
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3114
|
+
init_daemon_auth();
|
|
3115
|
+
SOCKET_PATH = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ?? path6.join(EXE_AI_DIR, "exed.sock");
|
|
3116
|
+
PID_PATH = process.env.EXE_DAEMON_PID ?? process.env.EXE_EMBED_PID ?? path6.join(EXE_AI_DIR, "exed.pid");
|
|
3117
|
+
SPAWN_LOCK_PATH = path6.join(EXE_AI_DIR, "exed-spawn.lock");
|
|
3007
3118
|
SPAWN_LOCK_STALE_MS = 3e4;
|
|
3008
3119
|
CONNECT_TIMEOUT_MS = 15e3;
|
|
3009
3120
|
REQUEST_TIMEOUT_MS = 3e4;
|
|
3121
|
+
DAEMON_TOKEN_ENV = "EXE_DAEMON_TOKEN";
|
|
3010
3122
|
_socket = null;
|
|
3011
3123
|
_connected = false;
|
|
3012
3124
|
_buffer = "";
|
|
@@ -3058,10 +3170,10 @@ async function disposeEmbedder() {
|
|
|
3058
3170
|
async function embedDirect(text) {
|
|
3059
3171
|
const llamaCpp = await import("node-llama-cpp");
|
|
3060
3172
|
const { MODELS_DIR: MODELS_DIR2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
3061
|
-
const { existsSync:
|
|
3062
|
-
const
|
|
3063
|
-
const modelPath =
|
|
3064
|
-
if (!
|
|
3173
|
+
const { existsSync: existsSync19 } = await import("fs");
|
|
3174
|
+
const path23 = await import("path");
|
|
3175
|
+
const modelPath = path23.join(MODELS_DIR2, "jina-embeddings-v5-small-q4_k_m.gguf");
|
|
3176
|
+
if (!existsSync19(modelPath)) {
|
|
3065
3177
|
throw new Error(`Embedding model not found at ${modelPath}. Run '/exe-setup' to download it.`);
|
|
3066
3178
|
}
|
|
3067
3179
|
const llama = await llamaCpp.getLlama();
|
|
@@ -3091,14 +3203,14 @@ var init_embedder = __esm({
|
|
|
3091
3203
|
|
|
3092
3204
|
// src/lib/keychain.ts
|
|
3093
3205
|
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
|
|
3094
|
-
import { existsSync as
|
|
3095
|
-
import
|
|
3206
|
+
import { existsSync as existsSync7 } from "fs";
|
|
3207
|
+
import path7 from "path";
|
|
3096
3208
|
import os5 from "os";
|
|
3097
3209
|
function getKeyDir() {
|
|
3098
|
-
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ??
|
|
3210
|
+
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path7.join(os5.homedir(), ".exe-os");
|
|
3099
3211
|
}
|
|
3100
3212
|
function getKeyPath() {
|
|
3101
|
-
return
|
|
3213
|
+
return path7.join(getKeyDir(), "master.key");
|
|
3102
3214
|
}
|
|
3103
3215
|
async function tryKeytar() {
|
|
3104
3216
|
try {
|
|
@@ -3119,7 +3231,7 @@ async function getMasterKey() {
|
|
|
3119
3231
|
}
|
|
3120
3232
|
}
|
|
3121
3233
|
const keyPath = getKeyPath();
|
|
3122
|
-
if (!
|
|
3234
|
+
if (!existsSync7(keyPath)) {
|
|
3123
3235
|
process.stderr.write(
|
|
3124
3236
|
`[keychain] Key not found at ${keyPath} (HOME=${os5.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
|
|
3125
3237
|
`
|
|
@@ -3151,6 +3263,7 @@ var shard_manager_exports = {};
|
|
|
3151
3263
|
__export(shard_manager_exports, {
|
|
3152
3264
|
disposeShards: () => disposeShards,
|
|
3153
3265
|
ensureShardSchema: () => ensureShardSchema,
|
|
3266
|
+
getOpenShardCount: () => getOpenShardCount,
|
|
3154
3267
|
getReadyShardClient: () => getReadyShardClient,
|
|
3155
3268
|
getShardClient: () => getShardClient,
|
|
3156
3269
|
getShardsDir: () => getShardsDir,
|
|
@@ -3159,15 +3272,18 @@ __export(shard_manager_exports, {
|
|
|
3159
3272
|
listShards: () => listShards,
|
|
3160
3273
|
shardExists: () => shardExists
|
|
3161
3274
|
});
|
|
3162
|
-
import
|
|
3163
|
-
import { existsSync as
|
|
3275
|
+
import path8 from "path";
|
|
3276
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync2, readdirSync } from "fs";
|
|
3164
3277
|
import { createClient as createClient2 } from "@libsql/client";
|
|
3165
3278
|
function initShardManager(encryptionKey) {
|
|
3166
3279
|
_encryptionKey = encryptionKey;
|
|
3167
|
-
if (!
|
|
3280
|
+
if (!existsSync8(SHARDS_DIR)) {
|
|
3168
3281
|
mkdirSync2(SHARDS_DIR, { recursive: true });
|
|
3169
3282
|
}
|
|
3170
3283
|
_shardingEnabled = true;
|
|
3284
|
+
if (_evictionTimer) clearInterval(_evictionTimer);
|
|
3285
|
+
_evictionTimer = setInterval(evictIdleShards, EVICTION_INTERVAL_MS);
|
|
3286
|
+
_evictionTimer.unref();
|
|
3171
3287
|
}
|
|
3172
3288
|
function isShardingEnabled() {
|
|
3173
3289
|
return _shardingEnabled;
|
|
@@ -3184,21 +3300,28 @@ function getShardClient(projectName) {
|
|
|
3184
3300
|
throw new Error(`Invalid project name for shard: "${projectName}"`);
|
|
3185
3301
|
}
|
|
3186
3302
|
const cached = _shards.get(safeName);
|
|
3187
|
-
if (cached)
|
|
3188
|
-
|
|
3303
|
+
if (cached) {
|
|
3304
|
+
_shardLastAccess.set(safeName, Date.now());
|
|
3305
|
+
return cached;
|
|
3306
|
+
}
|
|
3307
|
+
while (_shards.size >= MAX_OPEN_SHARDS) {
|
|
3308
|
+
evictLRU();
|
|
3309
|
+
}
|
|
3310
|
+
const dbPath = path8.join(SHARDS_DIR, `${safeName}.db`);
|
|
3189
3311
|
const client = createClient2({
|
|
3190
3312
|
url: `file:${dbPath}`,
|
|
3191
3313
|
encryptionKey: _encryptionKey
|
|
3192
3314
|
});
|
|
3193
3315
|
_shards.set(safeName, client);
|
|
3316
|
+
_shardLastAccess.set(safeName, Date.now());
|
|
3194
3317
|
return client;
|
|
3195
3318
|
}
|
|
3196
3319
|
function shardExists(projectName) {
|
|
3197
3320
|
const safeName = projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
3198
|
-
return
|
|
3321
|
+
return existsSync8(path8.join(SHARDS_DIR, `${safeName}.db`));
|
|
3199
3322
|
}
|
|
3200
3323
|
function listShards() {
|
|
3201
|
-
if (!
|
|
3324
|
+
if (!existsSync8(SHARDS_DIR)) return [];
|
|
3202
3325
|
return readdirSync(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
|
|
3203
3326
|
}
|
|
3204
3327
|
async function ensureShardSchema(client) {
|
|
@@ -3250,6 +3373,8 @@ async function ensureShardSchema(client) {
|
|
|
3250
3373
|
for (const col of [
|
|
3251
3374
|
"ALTER TABLE memories ADD COLUMN task_id TEXT",
|
|
3252
3375
|
"ALTER TABLE memories ADD COLUMN consolidated INTEGER NOT NULL DEFAULT 0",
|
|
3376
|
+
"ALTER TABLE memories ADD COLUMN author_device_id TEXT",
|
|
3377
|
+
"ALTER TABLE memories ADD COLUMN scope TEXT NOT NULL DEFAULT 'business'",
|
|
3253
3378
|
"ALTER TABLE memories ADD COLUMN importance INTEGER DEFAULT 5",
|
|
3254
3379
|
"ALTER TABLE memories ADD COLUMN status TEXT DEFAULT 'active'",
|
|
3255
3380
|
"ALTER TABLE memories ADD COLUMN wiki_synced INTEGER DEFAULT 0",
|
|
@@ -3387,21 +3512,69 @@ async function getReadyShardClient(projectName) {
|
|
|
3387
3512
|
await ensureShardSchema(client);
|
|
3388
3513
|
return client;
|
|
3389
3514
|
}
|
|
3515
|
+
function evictLRU() {
|
|
3516
|
+
let oldest = null;
|
|
3517
|
+
let oldestTime = Infinity;
|
|
3518
|
+
for (const [name, time] of _shardLastAccess) {
|
|
3519
|
+
if (time < oldestTime) {
|
|
3520
|
+
oldestTime = time;
|
|
3521
|
+
oldest = name;
|
|
3522
|
+
}
|
|
3523
|
+
}
|
|
3524
|
+
if (oldest) {
|
|
3525
|
+
const client = _shards.get(oldest);
|
|
3526
|
+
if (client) {
|
|
3527
|
+
client.close();
|
|
3528
|
+
}
|
|
3529
|
+
_shards.delete(oldest);
|
|
3530
|
+
_shardLastAccess.delete(oldest);
|
|
3531
|
+
}
|
|
3532
|
+
}
|
|
3533
|
+
function evictIdleShards() {
|
|
3534
|
+
const now = Date.now();
|
|
3535
|
+
const toEvict = [];
|
|
3536
|
+
for (const [name, lastAccess] of _shardLastAccess) {
|
|
3537
|
+
if (now - lastAccess > SHARD_IDLE_MS) {
|
|
3538
|
+
toEvict.push(name);
|
|
3539
|
+
}
|
|
3540
|
+
}
|
|
3541
|
+
for (const name of toEvict) {
|
|
3542
|
+
const client = _shards.get(name);
|
|
3543
|
+
if (client) {
|
|
3544
|
+
client.close();
|
|
3545
|
+
}
|
|
3546
|
+
_shards.delete(name);
|
|
3547
|
+
_shardLastAccess.delete(name);
|
|
3548
|
+
}
|
|
3549
|
+
}
|
|
3550
|
+
function getOpenShardCount() {
|
|
3551
|
+
return _shards.size;
|
|
3552
|
+
}
|
|
3390
3553
|
function disposeShards() {
|
|
3554
|
+
if (_evictionTimer) {
|
|
3555
|
+
clearInterval(_evictionTimer);
|
|
3556
|
+
_evictionTimer = null;
|
|
3557
|
+
}
|
|
3391
3558
|
for (const [, client] of _shards) {
|
|
3392
3559
|
client.close();
|
|
3393
3560
|
}
|
|
3394
3561
|
_shards.clear();
|
|
3562
|
+
_shardLastAccess.clear();
|
|
3395
3563
|
_shardingEnabled = false;
|
|
3396
3564
|
_encryptionKey = null;
|
|
3397
3565
|
}
|
|
3398
|
-
var SHARDS_DIR, _shards, _encryptionKey, _shardingEnabled;
|
|
3566
|
+
var SHARDS_DIR, SHARD_IDLE_MS, MAX_OPEN_SHARDS, EVICTION_INTERVAL_MS, _shards, _shardLastAccess, _evictionTimer, _encryptionKey, _shardingEnabled;
|
|
3399
3567
|
var init_shard_manager = __esm({
|
|
3400
3568
|
"src/lib/shard-manager.ts"() {
|
|
3401
3569
|
"use strict";
|
|
3402
3570
|
init_config();
|
|
3403
|
-
SHARDS_DIR =
|
|
3571
|
+
SHARDS_DIR = path8.join(EXE_AI_DIR, "shards");
|
|
3572
|
+
SHARD_IDLE_MS = 5 * 60 * 1e3;
|
|
3573
|
+
MAX_OPEN_SHARDS = 10;
|
|
3574
|
+
EVICTION_INTERVAL_MS = 60 * 1e3;
|
|
3404
3575
|
_shards = /* @__PURE__ */ new Map();
|
|
3576
|
+
_shardLastAccess = /* @__PURE__ */ new Map();
|
|
3577
|
+
_evictionTimer = null;
|
|
3405
3578
|
_encryptionKey = null;
|
|
3406
3579
|
_shardingEnabled = false;
|
|
3407
3580
|
}
|
|
@@ -4173,8 +4346,8 @@ __export(wiki_client_exports, {
|
|
|
4173
4346
|
listDocuments: () => listDocuments,
|
|
4174
4347
|
listWorkspaces: () => listWorkspaces
|
|
4175
4348
|
});
|
|
4176
|
-
async function wikiFetch(config2,
|
|
4177
|
-
const url = `${config2.baseUrl}/api/v1${
|
|
4349
|
+
async function wikiFetch(config2, path23, method = "GET", body) {
|
|
4350
|
+
const url = `${config2.baseUrl}/api/v1${path23}`;
|
|
4178
4351
|
const headers = {
|
|
4179
4352
|
Authorization: `Bearer ${config2.apiKey}`,
|
|
4180
4353
|
"Content-Type": "application/json"
|
|
@@ -4207,7 +4380,7 @@ async function wikiFetch(config2, path22, method = "GET", body) {
|
|
|
4207
4380
|
}
|
|
4208
4381
|
}
|
|
4209
4382
|
if (!response.ok) {
|
|
4210
|
-
throw new Error(`Wiki API ${method} ${
|
|
4383
|
+
throw new Error(`Wiki API ${method} ${path23}: ${response.status} ${response.statusText}`);
|
|
4211
4384
|
}
|
|
4212
4385
|
return response.json();
|
|
4213
4386
|
} finally {
|
|
@@ -4500,13 +4673,13 @@ __export(graph_rag_exports, {
|
|
|
4500
4673
|
resolveAlias: () => resolveAlias,
|
|
4501
4674
|
storeExtraction: () => storeExtraction
|
|
4502
4675
|
});
|
|
4503
|
-
import
|
|
4676
|
+
import crypto2 from "crypto";
|
|
4504
4677
|
function normalizeEntityName(name) {
|
|
4505
4678
|
return name.replace(/\s*\([^)]*\)\s*/g, "").trim().toLowerCase();
|
|
4506
4679
|
}
|
|
4507
4680
|
function entityId(name, type) {
|
|
4508
4681
|
const normalized = normalizeEntityName(name);
|
|
4509
|
-
return
|
|
4682
|
+
return crypto2.createHash("sha256").update(`${normalized}::${type.toLowerCase()}`).digest("hex").slice(0, 16);
|
|
4510
4683
|
}
|
|
4511
4684
|
async function resolveAlias(client, name) {
|
|
4512
4685
|
const normalized = normalizeEntityName(name);
|
|
@@ -4756,7 +4929,7 @@ async function storeExtraction(client, extraction, memoryId, timestamp) {
|
|
|
4756
4929
|
const targetAlias = await resolveAlias(client, r.target);
|
|
4757
4930
|
const sourceId = sourceAlias ?? entityId(r.source, r.sourceType);
|
|
4758
4931
|
const targetId = targetAlias ?? entityId(r.target, r.targetType);
|
|
4759
|
-
const relId =
|
|
4932
|
+
const relId = crypto2.randomUUID().slice(0, 16);
|
|
4760
4933
|
try {
|
|
4761
4934
|
await client.execute({
|
|
4762
4935
|
sql: `INSERT OR IGNORE INTO entities (id, name, type, first_seen, last_seen)
|
|
@@ -4819,7 +4992,7 @@ async function storeExtraction(client, extraction, memoryId, timestamp) {
|
|
|
4819
4992
|
}
|
|
4820
4993
|
}
|
|
4821
4994
|
for (const h of extraction.hyperedges) {
|
|
4822
|
-
const hId =
|
|
4995
|
+
const hId = crypto2.randomUUID().slice(0, 16);
|
|
4823
4996
|
try {
|
|
4824
4997
|
await client.execute({
|
|
4825
4998
|
sql: `INSERT OR IGNORE INTO hyperedges (id, label, relation, confidence, timestamp)
|
|
@@ -4883,7 +5056,7 @@ async function extractBatch(client, batchSize = 50, model = "claude-haiku-4-5-20
|
|
|
4883
5056
|
totalEntities += stored.entitiesStored;
|
|
4884
5057
|
totalRelationships += stored.relationshipsStored;
|
|
4885
5058
|
}
|
|
4886
|
-
const contentHash =
|
|
5059
|
+
const contentHash = crypto2.createHash("sha256").update(rawContent).digest("hex").slice(0, 32);
|
|
4887
5060
|
await client.execute({
|
|
4888
5061
|
sql: "UPDATE memories SET graph_extracted = 1, content_hash = ?, graph_extracted_hash = ? WHERE id = ?",
|
|
4889
5062
|
args: [contentHash, contentHash, memoryId]
|
|
@@ -5236,9 +5409,12 @@ __export(license_exports, {
|
|
|
5236
5409
|
stopLicenseRevalidation: () => stopLicenseRevalidation,
|
|
5237
5410
|
validateLicense: () => validateLicense
|
|
5238
5411
|
});
|
|
5239
|
-
import { readFileSync as
|
|
5412
|
+
import { readFileSync as readFileSync6, writeFileSync as writeFileSync4, existsSync as existsSync9, mkdirSync as mkdirSync3 } from "fs";
|
|
5240
5413
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
5241
|
-
import
|
|
5414
|
+
import { createRequire as createRequire2 } from "module";
|
|
5415
|
+
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
5416
|
+
import os6 from "os";
|
|
5417
|
+
import path9 from "path";
|
|
5242
5418
|
import { jwtVerify, importSPKI } from "jose";
|
|
5243
5419
|
async function fetchRetry(url, init) {
|
|
5244
5420
|
try {
|
|
@@ -5249,37 +5425,37 @@ async function fetchRetry(url, init) {
|
|
|
5249
5425
|
}
|
|
5250
5426
|
}
|
|
5251
5427
|
function loadDeviceId() {
|
|
5252
|
-
const deviceJsonPath =
|
|
5428
|
+
const deviceJsonPath = path9.join(EXE_AI_DIR, "device.json");
|
|
5253
5429
|
try {
|
|
5254
|
-
if (
|
|
5255
|
-
const data = JSON.parse(
|
|
5430
|
+
if (existsSync9(deviceJsonPath)) {
|
|
5431
|
+
const data = JSON.parse(readFileSync6(deviceJsonPath, "utf8"));
|
|
5256
5432
|
if (data.deviceId) return data.deviceId;
|
|
5257
5433
|
}
|
|
5258
5434
|
} catch {
|
|
5259
5435
|
}
|
|
5260
5436
|
try {
|
|
5261
|
-
if (
|
|
5262
|
-
const id2 =
|
|
5437
|
+
if (existsSync9(DEVICE_ID_PATH)) {
|
|
5438
|
+
const id2 = readFileSync6(DEVICE_ID_PATH, "utf8").trim();
|
|
5263
5439
|
if (id2) return id2;
|
|
5264
5440
|
}
|
|
5265
5441
|
} catch {
|
|
5266
5442
|
}
|
|
5267
5443
|
const id = randomUUID3();
|
|
5268
5444
|
mkdirSync3(EXE_AI_DIR, { recursive: true });
|
|
5269
|
-
|
|
5445
|
+
writeFileSync4(DEVICE_ID_PATH, id, "utf8");
|
|
5270
5446
|
return id;
|
|
5271
5447
|
}
|
|
5272
5448
|
function loadLicense() {
|
|
5273
5449
|
try {
|
|
5274
|
-
if (!
|
|
5275
|
-
return
|
|
5450
|
+
if (!existsSync9(LICENSE_PATH)) return null;
|
|
5451
|
+
return readFileSync6(LICENSE_PATH, "utf8").trim();
|
|
5276
5452
|
} catch {
|
|
5277
5453
|
return null;
|
|
5278
5454
|
}
|
|
5279
5455
|
}
|
|
5280
5456
|
function saveLicense(apiKey) {
|
|
5281
5457
|
mkdirSync3(EXE_AI_DIR, { recursive: true });
|
|
5282
|
-
|
|
5458
|
+
writeFileSync4(LICENSE_PATH, apiKey.trim(), { encoding: "utf8", mode: 384 });
|
|
5283
5459
|
}
|
|
5284
5460
|
async function verifyLicenseJwt(token) {
|
|
5285
5461
|
try {
|
|
@@ -5305,8 +5481,8 @@ async function verifyLicenseJwt(token) {
|
|
|
5305
5481
|
}
|
|
5306
5482
|
async function getCachedLicense() {
|
|
5307
5483
|
try {
|
|
5308
|
-
if (!
|
|
5309
|
-
const raw = JSON.parse(
|
|
5484
|
+
if (!existsSync9(CACHE_PATH)) return null;
|
|
5485
|
+
const raw = JSON.parse(readFileSync6(CACHE_PATH, "utf8"));
|
|
5310
5486
|
if (!raw.token || typeof raw.token !== "string") return null;
|
|
5311
5487
|
return await verifyLicenseJwt(raw.token);
|
|
5312
5488
|
} catch {
|
|
@@ -5315,8 +5491,8 @@ async function getCachedLicense() {
|
|
|
5315
5491
|
}
|
|
5316
5492
|
function readCachedToken() {
|
|
5317
5493
|
try {
|
|
5318
|
-
if (!
|
|
5319
|
-
const raw = JSON.parse(
|
|
5494
|
+
if (!existsSync9(CACHE_PATH)) return null;
|
|
5495
|
+
const raw = JSON.parse(readFileSync6(CACHE_PATH, "utf8"));
|
|
5320
5496
|
return typeof raw.token === "string" ? raw.token : null;
|
|
5321
5497
|
} catch {
|
|
5322
5498
|
return null;
|
|
@@ -5350,56 +5526,130 @@ function getRawCachedPlan() {
|
|
|
5350
5526
|
}
|
|
5351
5527
|
function cacheResponse(token) {
|
|
5352
5528
|
try {
|
|
5353
|
-
|
|
5529
|
+
writeFileSync4(CACHE_PATH, JSON.stringify({ token }), "utf8");
|
|
5354
5530
|
} catch {
|
|
5355
5531
|
}
|
|
5356
5532
|
}
|
|
5357
|
-
|
|
5358
|
-
|
|
5533
|
+
function loadPrismaForLicense() {
|
|
5534
|
+
if (_prismaFailed) return null;
|
|
5535
|
+
const dbUrl = process.env.DATABASE_URL;
|
|
5536
|
+
if (!dbUrl) {
|
|
5537
|
+
const exeDbRoot = process.env.EXE_DB_ROOT ?? path9.join(os6.homedir(), "exe-db");
|
|
5538
|
+
if (!existsSync9(path9.join(exeDbRoot, "package.json"))) {
|
|
5539
|
+
_prismaFailed = true;
|
|
5540
|
+
return null;
|
|
5541
|
+
}
|
|
5542
|
+
}
|
|
5543
|
+
if (!_prismaPromise) {
|
|
5544
|
+
_prismaPromise = (async () => {
|
|
5545
|
+
const explicitPath = process.env.EXE_OS_PRISMA_CLIENT_PATH;
|
|
5546
|
+
if (explicitPath) {
|
|
5547
|
+
const mod2 = await import(pathToFileURL2(explicitPath).href);
|
|
5548
|
+
const Ctor2 = mod2.PrismaClient ?? mod2.default?.PrismaClient;
|
|
5549
|
+
if (!Ctor2) throw new Error(`No PrismaClient at ${explicitPath}`);
|
|
5550
|
+
return new Ctor2();
|
|
5551
|
+
}
|
|
5552
|
+
const exeDbRoot = process.env.EXE_DB_ROOT ?? path9.join(os6.homedir(), "exe-db");
|
|
5553
|
+
const req = createRequire2(path9.join(exeDbRoot, "package.json"));
|
|
5554
|
+
const entry = req.resolve("@prisma/client");
|
|
5555
|
+
const mod = await import(pathToFileURL2(entry).href);
|
|
5556
|
+
const Ctor = mod.PrismaClient ?? mod.default?.PrismaClient;
|
|
5557
|
+
if (!Ctor) throw new Error(`No PrismaClient in ${entry}`);
|
|
5558
|
+
return new Ctor();
|
|
5559
|
+
})().catch((err) => {
|
|
5560
|
+
_prismaFailed = true;
|
|
5561
|
+
_prismaPromise = null;
|
|
5562
|
+
throw err;
|
|
5563
|
+
});
|
|
5564
|
+
}
|
|
5565
|
+
return _prismaPromise;
|
|
5566
|
+
}
|
|
5567
|
+
async function validateViaPostgres(apiKey) {
|
|
5568
|
+
const loader = loadPrismaForLicense();
|
|
5569
|
+
if (!loader) return null;
|
|
5570
|
+
try {
|
|
5571
|
+
const prisma = await loader;
|
|
5572
|
+
const rows = await prisma.$queryRawUnsafe(
|
|
5573
|
+
`SELECT plan, email, status, device_limit, employee_limit, memory_limit, expires_at
|
|
5574
|
+
FROM billing.licenses WHERE key = $1 LIMIT 1`,
|
|
5575
|
+
apiKey
|
|
5576
|
+
);
|
|
5577
|
+
if (!rows || rows.length === 0) return null;
|
|
5578
|
+
const row = rows[0];
|
|
5579
|
+
if (row.status !== "active") return null;
|
|
5580
|
+
if (row.expires_at && new Date(row.expires_at) < /* @__PURE__ */ new Date()) return null;
|
|
5581
|
+
const plan = row.plan;
|
|
5582
|
+
const limits = PLAN_LIMITS[plan] ?? PLAN_LIMITS.free;
|
|
5583
|
+
return {
|
|
5584
|
+
valid: true,
|
|
5585
|
+
plan,
|
|
5586
|
+
email: row.email,
|
|
5587
|
+
expiresAt: row.expires_at ? new Date(row.expires_at).toISOString() : null,
|
|
5588
|
+
deviceLimit: row.device_limit ?? limits.devices,
|
|
5589
|
+
employeeLimit: row.employee_limit ?? limits.employees,
|
|
5590
|
+
memoryLimit: row.memory_limit ?? limits.memories
|
|
5591
|
+
};
|
|
5592
|
+
} catch {
|
|
5593
|
+
return null;
|
|
5594
|
+
}
|
|
5595
|
+
}
|
|
5596
|
+
async function validateViaCFWorker(apiKey, deviceId) {
|
|
5359
5597
|
try {
|
|
5360
5598
|
const res = await fetchRetry(`${API_BASE}/auth/activate`, {
|
|
5361
5599
|
method: "POST",
|
|
5362
5600
|
headers: { "Content-Type": "application/json" },
|
|
5363
|
-
body: JSON.stringify({ apiKey, deviceId
|
|
5601
|
+
body: JSON.stringify({ apiKey, deviceId }),
|
|
5364
5602
|
signal: AbortSignal.timeout(1e4)
|
|
5365
5603
|
});
|
|
5366
|
-
if (res.ok)
|
|
5367
|
-
|
|
5368
|
-
|
|
5369
|
-
|
|
5370
|
-
|
|
5371
|
-
|
|
5372
|
-
|
|
5373
|
-
|
|
5374
|
-
|
|
5375
|
-
|
|
5376
|
-
|
|
5377
|
-
|
|
5378
|
-
|
|
5379
|
-
|
|
5380
|
-
|
|
5381
|
-
|
|
5382
|
-
|
|
5383
|
-
|
|
5384
|
-
|
|
5385
|
-
|
|
5386
|
-
|
|
5387
|
-
|
|
5388
|
-
|
|
5389
|
-
|
|
5604
|
+
if (!res.ok) return null;
|
|
5605
|
+
const data = await res.json();
|
|
5606
|
+
if (data.error === "device_limit_exceeded") return null;
|
|
5607
|
+
if (!data.valid) return null;
|
|
5608
|
+
if (data.token) {
|
|
5609
|
+
cacheResponse(data.token);
|
|
5610
|
+
const verified = await verifyLicenseJwt(data.token);
|
|
5611
|
+
if (verified) return verified;
|
|
5612
|
+
}
|
|
5613
|
+
const limits = PLAN_LIMITS[data.plan] ?? PLAN_LIMITS.free;
|
|
5614
|
+
return {
|
|
5615
|
+
valid: data.valid,
|
|
5616
|
+
plan: data.plan,
|
|
5617
|
+
email: data.email,
|
|
5618
|
+
expiresAt: data.expiresAt,
|
|
5619
|
+
deviceLimit: limits.devices,
|
|
5620
|
+
employeeLimit: limits.employees,
|
|
5621
|
+
memoryLimit: limits.memories
|
|
5622
|
+
};
|
|
5623
|
+
} catch {
|
|
5624
|
+
return null;
|
|
5625
|
+
}
|
|
5626
|
+
}
|
|
5627
|
+
async function validateLicense(apiKey, deviceId) {
|
|
5628
|
+
const did = deviceId ?? loadDeviceId();
|
|
5629
|
+
const pgResult = await validateViaPostgres(apiKey);
|
|
5630
|
+
if (pgResult) {
|
|
5631
|
+
try {
|
|
5632
|
+
writeFileSync4(CACHE_PATH, JSON.stringify({ pgLicense: pgResult, ts: Date.now() }), "utf8");
|
|
5633
|
+
} catch {
|
|
5634
|
+
}
|
|
5635
|
+
return pgResult;
|
|
5636
|
+
}
|
|
5637
|
+
const cfResult = await validateViaCFWorker(apiKey, did);
|
|
5638
|
+
if (cfResult) return cfResult;
|
|
5639
|
+
const cached = await getCachedLicense();
|
|
5640
|
+
if (cached) return cached;
|
|
5641
|
+
try {
|
|
5642
|
+
if (existsSync9(CACHE_PATH)) {
|
|
5643
|
+
const raw = JSON.parse(readFileSync6(CACHE_PATH, "utf8"));
|
|
5644
|
+
if (raw.pgLicense && raw.ts && Date.now() - raw.ts < 7 * 24 * 60 * 60 * 1e3) {
|
|
5645
|
+
return raw.pgLicense;
|
|
5646
|
+
}
|
|
5390
5647
|
}
|
|
5391
|
-
const cached = await getCachedLicense();
|
|
5392
|
-
if (cached) return cached;
|
|
5393
|
-
const raw = getRawCachedPlan();
|
|
5394
|
-
if (raw) return raw;
|
|
5395
|
-
return { ...FREE_LICENSE, valid: false, plan: "free" };
|
|
5396
5648
|
} catch {
|
|
5397
|
-
const cached = await getCachedLicense();
|
|
5398
|
-
if (cached) return cached;
|
|
5399
|
-
const rawFallback = getRawCachedPlan();
|
|
5400
|
-
if (rawFallback) return rawFallback;
|
|
5401
|
-
return { ...FREE_LICENSE, valid: false, error: "offline" };
|
|
5402
5649
|
}
|
|
5650
|
+
const rawFallback = getRawCachedPlan();
|
|
5651
|
+
if (rawFallback) return rawFallback;
|
|
5652
|
+
return { ...FREE_LICENSE, valid: false };
|
|
5403
5653
|
}
|
|
5404
5654
|
function getCacheAgeMs() {
|
|
5405
5655
|
try {
|
|
@@ -5414,9 +5664,9 @@ async function checkLicense() {
|
|
|
5414
5664
|
let key = loadLicense();
|
|
5415
5665
|
if (!key) {
|
|
5416
5666
|
try {
|
|
5417
|
-
const configPath =
|
|
5418
|
-
if (
|
|
5419
|
-
const raw = JSON.parse(
|
|
5667
|
+
const configPath = path9.join(EXE_AI_DIR, "config.json");
|
|
5668
|
+
if (existsSync9(configPath)) {
|
|
5669
|
+
const raw = JSON.parse(readFileSync6(configPath, "utf8"));
|
|
5420
5670
|
const cloud = raw.cloud;
|
|
5421
5671
|
if (cloud?.apiKey) {
|
|
5422
5672
|
key = cloud.apiKey;
|
|
@@ -5570,14 +5820,14 @@ function stopLicenseRevalidation() {
|
|
|
5570
5820
|
_revalTimer = null;
|
|
5571
5821
|
}
|
|
5572
5822
|
}
|
|
5573
|
-
var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH, API_BASE, RETRY_DELAY_MS, LICENSE_PUBLIC_KEY_PEM, LICENSE_JWT_ALG, PLAN_LIMITS, FREE_LICENSE, CACHE_MAX_AGE_MS, _revalTimer;
|
|
5823
|
+
var LICENSE_PATH, CACHE_PATH, DEVICE_ID_PATH, API_BASE, RETRY_DELAY_MS, LICENSE_PUBLIC_KEY_PEM, LICENSE_JWT_ALG, PLAN_LIMITS, FREE_LICENSE, _prismaPromise, _prismaFailed, CACHE_MAX_AGE_MS, _revalTimer;
|
|
5574
5824
|
var init_license = __esm({
|
|
5575
5825
|
"src/lib/license.ts"() {
|
|
5576
5826
|
"use strict";
|
|
5577
5827
|
init_config();
|
|
5578
|
-
LICENSE_PATH =
|
|
5579
|
-
CACHE_PATH =
|
|
5580
|
-
DEVICE_ID_PATH =
|
|
5828
|
+
LICENSE_PATH = path9.join(EXE_AI_DIR, "license.key");
|
|
5829
|
+
CACHE_PATH = path9.join(EXE_AI_DIR, "license-cache.json");
|
|
5830
|
+
DEVICE_ID_PATH = path9.join(EXE_AI_DIR, "device-id");
|
|
5581
5831
|
API_BASE = "https://askexe.com/cloud";
|
|
5582
5832
|
RETRY_DELAY_MS = 500;
|
|
5583
5833
|
LICENSE_PUBLIC_KEY_PEM = `-----BEGIN PUBLIC KEY-----
|
|
@@ -5601,6 +5851,8 @@ MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeHztAMOpR/ZMh+rWuOASjEZ54CGY
|
|
|
5601
5851
|
employeeLimit: 1,
|
|
5602
5852
|
memoryLimit: 5e3
|
|
5603
5853
|
};
|
|
5854
|
+
_prismaPromise = null;
|
|
5855
|
+
_prismaFailed = false;
|
|
5604
5856
|
CACHE_MAX_AGE_MS = 36e5;
|
|
5605
5857
|
_revalTimer = null;
|
|
5606
5858
|
}
|
|
@@ -6475,16 +6727,16 @@ __export(imessage_exports, {
|
|
|
6475
6727
|
});
|
|
6476
6728
|
import { execFile } from "child_process";
|
|
6477
6729
|
import { promisify } from "util";
|
|
6478
|
-
import
|
|
6479
|
-
import
|
|
6730
|
+
import os7 from "os";
|
|
6731
|
+
import path10 from "path";
|
|
6480
6732
|
var execFileAsync, POLL_INTERVAL_MS, MESSAGES_DB_PATH, IMessageAdapter;
|
|
6481
6733
|
var init_imessage = __esm({
|
|
6482
6734
|
"src/gateway/adapters/imessage.ts"() {
|
|
6483
6735
|
"use strict";
|
|
6484
6736
|
execFileAsync = promisify(execFile);
|
|
6485
6737
|
POLL_INTERVAL_MS = 5e3;
|
|
6486
|
-
MESSAGES_DB_PATH =
|
|
6487
|
-
process.env.HOME ??
|
|
6738
|
+
MESSAGES_DB_PATH = path10.join(
|
|
6739
|
+
process.env.HOME ?? os7.homedir(),
|
|
6488
6740
|
"Library/Messages/chat.db"
|
|
6489
6741
|
);
|
|
6490
6742
|
IMessageAdapter = class {
|
|
@@ -6797,9 +7049,9 @@ __export(webhook_exports, {
|
|
|
6797
7049
|
WebhookAdapter: () => WebhookAdapter
|
|
6798
7050
|
});
|
|
6799
7051
|
import { randomUUID as randomUUID7 } from "crypto";
|
|
6800
|
-
function resolvePath(obj,
|
|
7052
|
+
function resolvePath(obj, path23) {
|
|
6801
7053
|
let current = obj;
|
|
6802
|
-
for (const segment of
|
|
7054
|
+
for (const segment of path23.split(".")) {
|
|
6803
7055
|
if (current == null || typeof current !== "object") return void 0;
|
|
6804
7056
|
current = current[segment];
|
|
6805
7057
|
}
|
|
@@ -6902,13 +7154,13 @@ __export(whatsapp_accounts_exports, {
|
|
|
6902
7154
|
getDefaultAccount: () => getDefaultAccount,
|
|
6903
7155
|
loadAccounts: () => loadAccounts
|
|
6904
7156
|
});
|
|
6905
|
-
import { readFileSync as
|
|
7157
|
+
import { readFileSync as readFileSync7 } from "fs";
|
|
6906
7158
|
import { join as join2 } from "path";
|
|
6907
7159
|
import { homedir as homedir2 } from "os";
|
|
6908
7160
|
function loadAccounts() {
|
|
6909
7161
|
if (cachedAccounts !== null) return cachedAccounts;
|
|
6910
7162
|
try {
|
|
6911
|
-
const raw =
|
|
7163
|
+
const raw = readFileSync7(CONFIG_PATH2, "utf8");
|
|
6912
7164
|
const parsed = JSON.parse(raw);
|
|
6913
7165
|
if (!Array.isArray(parsed)) {
|
|
6914
7166
|
console.warn("[whatsapp] Config is not an array, ignoring");
|
|
@@ -6948,12 +7200,12 @@ var init_whatsapp_accounts = __esm({
|
|
|
6948
7200
|
});
|
|
6949
7201
|
|
|
6950
7202
|
// src/lib/session-registry.ts
|
|
6951
|
-
import { readFileSync as
|
|
6952
|
-
import
|
|
6953
|
-
import
|
|
7203
|
+
import { readFileSync as readFileSync8, writeFileSync as writeFileSync5, mkdirSync as mkdirSync5, existsSync as existsSync10 } from "fs";
|
|
7204
|
+
import path11 from "path";
|
|
7205
|
+
import os8 from "os";
|
|
6954
7206
|
function registerSession(entry) {
|
|
6955
|
-
const dir =
|
|
6956
|
-
if (!
|
|
7207
|
+
const dir = path11.dirname(REGISTRY_PATH);
|
|
7208
|
+
if (!existsSync10(dir)) {
|
|
6957
7209
|
mkdirSync5(dir, { recursive: true });
|
|
6958
7210
|
}
|
|
6959
7211
|
const sessions = listSessions();
|
|
@@ -6963,11 +7215,11 @@ function registerSession(entry) {
|
|
|
6963
7215
|
} else {
|
|
6964
7216
|
sessions.push(entry);
|
|
6965
7217
|
}
|
|
6966
|
-
|
|
7218
|
+
writeFileSync5(REGISTRY_PATH, JSON.stringify(sessions, null, 2));
|
|
6967
7219
|
}
|
|
6968
7220
|
function listSessions() {
|
|
6969
7221
|
try {
|
|
6970
|
-
const raw =
|
|
7222
|
+
const raw = readFileSync8(REGISTRY_PATH, "utf8");
|
|
6971
7223
|
return JSON.parse(raw);
|
|
6972
7224
|
} catch {
|
|
6973
7225
|
return [];
|
|
@@ -6977,7 +7229,7 @@ var REGISTRY_PATH;
|
|
|
6977
7229
|
var init_session_registry = __esm({
|
|
6978
7230
|
"src/lib/session-registry.ts"() {
|
|
6979
7231
|
"use strict";
|
|
6980
|
-
REGISTRY_PATH =
|
|
7232
|
+
REGISTRY_PATH = path11.join(os8.homedir(), ".exe-os", "session-registry.json");
|
|
6981
7233
|
}
|
|
6982
7234
|
});
|
|
6983
7235
|
|
|
@@ -7238,17 +7490,17 @@ __export(intercom_queue_exports, {
|
|
|
7238
7490
|
queueIntercom: () => queueIntercom,
|
|
7239
7491
|
readQueue: () => readQueue
|
|
7240
7492
|
});
|
|
7241
|
-
import { readFileSync as
|
|
7242
|
-
import
|
|
7243
|
-
import
|
|
7493
|
+
import { readFileSync as readFileSync9, writeFileSync as writeFileSync6, renameSync as renameSync3, existsSync as existsSync11, mkdirSync as mkdirSync6 } from "fs";
|
|
7494
|
+
import path12 from "path";
|
|
7495
|
+
import os9 from "os";
|
|
7244
7496
|
function ensureDir() {
|
|
7245
|
-
const dir =
|
|
7246
|
-
if (!
|
|
7497
|
+
const dir = path12.dirname(QUEUE_PATH);
|
|
7498
|
+
if (!existsSync11(dir)) mkdirSync6(dir, { recursive: true });
|
|
7247
7499
|
}
|
|
7248
7500
|
function readQueue() {
|
|
7249
7501
|
try {
|
|
7250
|
-
if (!
|
|
7251
|
-
return JSON.parse(
|
|
7502
|
+
if (!existsSync11(QUEUE_PATH)) return [];
|
|
7503
|
+
return JSON.parse(readFileSync9(QUEUE_PATH, "utf8"));
|
|
7252
7504
|
} catch {
|
|
7253
7505
|
return [];
|
|
7254
7506
|
}
|
|
@@ -7256,7 +7508,7 @@ function readQueue() {
|
|
|
7256
7508
|
function writeQueue(queue) {
|
|
7257
7509
|
ensureDir();
|
|
7258
7510
|
const tmp = `${QUEUE_PATH}.tmp`;
|
|
7259
|
-
|
|
7511
|
+
writeFileSync6(tmp, JSON.stringify(queue, null, 2));
|
|
7260
7512
|
renameSync3(tmp, QUEUE_PATH);
|
|
7261
7513
|
}
|
|
7262
7514
|
function queueIntercom(targetSession, reason) {
|
|
@@ -7348,20 +7600,20 @@ var QUEUE_PATH, MAX_RETRIES2, TTL_MS, INTERCOM_LOG;
|
|
|
7348
7600
|
var init_intercom_queue = __esm({
|
|
7349
7601
|
"src/lib/intercom-queue.ts"() {
|
|
7350
7602
|
"use strict";
|
|
7351
|
-
QUEUE_PATH =
|
|
7603
|
+
QUEUE_PATH = path12.join(os9.homedir(), ".exe-os", "intercom-queue.json");
|
|
7352
7604
|
MAX_RETRIES2 = 5;
|
|
7353
7605
|
TTL_MS = 60 * 60 * 1e3;
|
|
7354
|
-
INTERCOM_LOG =
|
|
7606
|
+
INTERCOM_LOG = path12.join(os9.homedir(), ".exe-os", "intercom.log");
|
|
7355
7607
|
}
|
|
7356
7608
|
});
|
|
7357
7609
|
|
|
7358
7610
|
// src/lib/plan-limits.ts
|
|
7359
|
-
import { readFileSync as
|
|
7360
|
-
import
|
|
7611
|
+
import { readFileSync as readFileSync10, existsSync as existsSync12 } from "fs";
|
|
7612
|
+
import path13 from "path";
|
|
7361
7613
|
function getLicenseSync() {
|
|
7362
7614
|
try {
|
|
7363
|
-
if (!
|
|
7364
|
-
const raw = JSON.parse(
|
|
7615
|
+
if (!existsSync12(CACHE_PATH2)) return freeLicense();
|
|
7616
|
+
const raw = JSON.parse(readFileSync10(CACHE_PATH2, "utf8"));
|
|
7365
7617
|
if (!raw.token || typeof raw.token !== "string") return freeLicense();
|
|
7366
7618
|
const parts = raw.token.split(".");
|
|
7367
7619
|
if (parts.length !== 3) return freeLicense();
|
|
@@ -7399,8 +7651,8 @@ function assertEmployeeLimitSync(rosterPath) {
|
|
|
7399
7651
|
const filePath = rosterPath ?? EMPLOYEES_PATH;
|
|
7400
7652
|
let count = 0;
|
|
7401
7653
|
try {
|
|
7402
|
-
if (
|
|
7403
|
-
const raw =
|
|
7654
|
+
if (existsSync12(filePath)) {
|
|
7655
|
+
const raw = readFileSync10(filePath, "utf8");
|
|
7404
7656
|
const employees = JSON.parse(raw);
|
|
7405
7657
|
count = Array.isArray(employees) ? employees.length : 0;
|
|
7406
7658
|
}
|
|
@@ -7429,29 +7681,63 @@ var init_plan_limits = __esm({
|
|
|
7429
7681
|
this.name = "PlanLimitError";
|
|
7430
7682
|
}
|
|
7431
7683
|
};
|
|
7432
|
-
CACHE_PATH2 =
|
|
7684
|
+
CACHE_PATH2 = path13.join(EXE_AI_DIR, "license-cache.json");
|
|
7685
|
+
}
|
|
7686
|
+
});
|
|
7687
|
+
|
|
7688
|
+
// src/lib/task-scope.ts
|
|
7689
|
+
function getCurrentSessionScope() {
|
|
7690
|
+
try {
|
|
7691
|
+
return resolveExeSession();
|
|
7692
|
+
} catch {
|
|
7693
|
+
return null;
|
|
7694
|
+
}
|
|
7695
|
+
}
|
|
7696
|
+
function sessionScopeFilter(sessionScope, tableAlias) {
|
|
7697
|
+
const scope = sessionScope !== void 0 ? sessionScope : getCurrentSessionScope();
|
|
7698
|
+
if (!scope) return { sql: "", args: [] };
|
|
7699
|
+
const col = tableAlias ? `${tableAlias}.session_scope` : "session_scope";
|
|
7700
|
+
return {
|
|
7701
|
+
sql: ` AND (${col} IS NULL OR ${col} = ?)`,
|
|
7702
|
+
args: [scope]
|
|
7703
|
+
};
|
|
7704
|
+
}
|
|
7705
|
+
function strictSessionScopeFilter(sessionScope, tableAlias) {
|
|
7706
|
+
const scope = sessionScope !== void 0 ? sessionScope : getCurrentSessionScope();
|
|
7707
|
+
if (!scope) return { sql: "", args: [] };
|
|
7708
|
+
const col = tableAlias ? `${tableAlias}.session_scope` : "session_scope";
|
|
7709
|
+
return {
|
|
7710
|
+
sql: ` AND ${col} = ?`,
|
|
7711
|
+
args: [scope]
|
|
7712
|
+
};
|
|
7713
|
+
}
|
|
7714
|
+
var init_task_scope = __esm({
|
|
7715
|
+
"src/lib/task-scope.ts"() {
|
|
7716
|
+
"use strict";
|
|
7717
|
+
init_tmux_routing();
|
|
7433
7718
|
}
|
|
7434
7719
|
});
|
|
7435
7720
|
|
|
7436
7721
|
// src/lib/notifications.ts
|
|
7437
|
-
import
|
|
7438
|
-
import
|
|
7439
|
-
import
|
|
7722
|
+
import crypto4 from "crypto";
|
|
7723
|
+
import path14 from "path";
|
|
7724
|
+
import os10 from "os";
|
|
7440
7725
|
import {
|
|
7441
|
-
readFileSync as
|
|
7726
|
+
readFileSync as readFileSync11,
|
|
7442
7727
|
readdirSync as readdirSync2,
|
|
7443
7728
|
unlinkSync as unlinkSync3,
|
|
7444
|
-
existsSync as
|
|
7729
|
+
existsSync as existsSync13,
|
|
7445
7730
|
rmdirSync
|
|
7446
7731
|
} from "fs";
|
|
7447
7732
|
async function writeNotification(notification) {
|
|
7448
7733
|
try {
|
|
7449
7734
|
const client = getClient();
|
|
7450
|
-
const id =
|
|
7735
|
+
const id = crypto4.randomUUID();
|
|
7451
7736
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
7737
|
+
const sessionScope = notification.sessionScope === void 0 ? getCurrentSessionScope() : notification.sessionScope;
|
|
7452
7738
|
await client.execute({
|
|
7453
|
-
sql: `INSERT INTO notifications (id, agent_id, agent_role, event, project, summary, task_file, read, created_at)
|
|
7454
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, 0, ?)`,
|
|
7739
|
+
sql: `INSERT INTO notifications (id, agent_id, agent_role, event, project, summary, task_file, session_scope, read, created_at)
|
|
7740
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, 0, ?)`,
|
|
7455
7741
|
args: [
|
|
7456
7742
|
id,
|
|
7457
7743
|
notification.agentId,
|
|
@@ -7460,6 +7746,7 @@ async function writeNotification(notification) {
|
|
|
7460
7746
|
notification.project,
|
|
7461
7747
|
notification.summary,
|
|
7462
7748
|
notification.taskFile ?? null,
|
|
7749
|
+
sessionScope,
|
|
7463
7750
|
now
|
|
7464
7751
|
]
|
|
7465
7752
|
});
|
|
@@ -7468,12 +7755,14 @@ async function writeNotification(notification) {
|
|
|
7468
7755
|
`);
|
|
7469
7756
|
}
|
|
7470
7757
|
}
|
|
7471
|
-
async function markAsReadByTaskFile(taskFile) {
|
|
7758
|
+
async function markAsReadByTaskFile(taskFile, sessionScope) {
|
|
7472
7759
|
try {
|
|
7473
7760
|
const client = getClient();
|
|
7761
|
+
const scope = strictSessionScopeFilter(sessionScope);
|
|
7474
7762
|
await client.execute({
|
|
7475
|
-
sql:
|
|
7476
|
-
|
|
7763
|
+
sql: `UPDATE notifications SET read = 1
|
|
7764
|
+
WHERE task_file = ? AND read = 0${scope.sql}`,
|
|
7765
|
+
args: [taskFile, ...scope.args]
|
|
7477
7766
|
});
|
|
7478
7767
|
} catch {
|
|
7479
7768
|
}
|
|
@@ -7482,11 +7771,12 @@ var init_notifications = __esm({
|
|
|
7482
7771
|
"src/lib/notifications.ts"() {
|
|
7483
7772
|
"use strict";
|
|
7484
7773
|
init_database();
|
|
7774
|
+
init_task_scope();
|
|
7485
7775
|
}
|
|
7486
7776
|
});
|
|
7487
7777
|
|
|
7488
7778
|
// src/lib/session-kill-telemetry.ts
|
|
7489
|
-
import
|
|
7779
|
+
import crypto5 from "crypto";
|
|
7490
7780
|
async function recordSessionKill(input) {
|
|
7491
7781
|
try {
|
|
7492
7782
|
const client = getClient();
|
|
@@ -7496,7 +7786,7 @@ async function recordSessionKill(input) {
|
|
|
7496
7786
|
ticks_idle, estimated_tokens_saved)
|
|
7497
7787
|
VALUES (?, ?, ?, ?, ?, ?, ?)`,
|
|
7498
7788
|
args: [
|
|
7499
|
-
|
|
7789
|
+
crypto5.randomUUID(),
|
|
7500
7790
|
input.sessionName,
|
|
7501
7791
|
input.agentId,
|
|
7502
7792
|
(/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -7519,37 +7809,13 @@ var init_session_kill_telemetry = __esm({
|
|
|
7519
7809
|
}
|
|
7520
7810
|
});
|
|
7521
7811
|
|
|
7522
|
-
// src/lib/task-scope.ts
|
|
7523
|
-
function getCurrentSessionScope() {
|
|
7524
|
-
try {
|
|
7525
|
-
return resolveExeSession();
|
|
7526
|
-
} catch {
|
|
7527
|
-
return null;
|
|
7528
|
-
}
|
|
7529
|
-
}
|
|
7530
|
-
function sessionScopeFilter(sessionScope, tableAlias) {
|
|
7531
|
-
const scope = sessionScope !== void 0 ? sessionScope : getCurrentSessionScope();
|
|
7532
|
-
if (!scope) return { sql: "", args: [] };
|
|
7533
|
-
const col = tableAlias ? `${tableAlias}.session_scope` : "session_scope";
|
|
7534
|
-
return {
|
|
7535
|
-
sql: ` AND (${col} IS NULL OR ${col} = ?)`,
|
|
7536
|
-
args: [scope]
|
|
7537
|
-
};
|
|
7538
|
-
}
|
|
7539
|
-
var init_task_scope = __esm({
|
|
7540
|
-
"src/lib/task-scope.ts"() {
|
|
7541
|
-
"use strict";
|
|
7542
|
-
init_tmux_routing();
|
|
7543
|
-
}
|
|
7544
|
-
});
|
|
7545
|
-
|
|
7546
7812
|
// src/lib/tasks-crud.ts
|
|
7547
|
-
import
|
|
7548
|
-
import
|
|
7549
|
-
import
|
|
7813
|
+
import crypto6 from "crypto";
|
|
7814
|
+
import path15 from "path";
|
|
7815
|
+
import os11 from "os";
|
|
7550
7816
|
import { execSync as execSync4 } from "child_process";
|
|
7551
7817
|
import { mkdir as mkdir4, writeFile as writeFile4, appendFile } from "fs/promises";
|
|
7552
|
-
import { existsSync as
|
|
7818
|
+
import { existsSync as existsSync14, readFileSync as readFileSync12 } from "fs";
|
|
7553
7819
|
async function writeCheckpoint(input) {
|
|
7554
7820
|
const client = getClient();
|
|
7555
7821
|
const row = await resolveTask(client, input.taskId);
|
|
@@ -7665,7 +7931,7 @@ async function resolveTask(client, identifier, scopeSession) {
|
|
|
7665
7931
|
}
|
|
7666
7932
|
async function createTaskCore(input) {
|
|
7667
7933
|
const client = getClient();
|
|
7668
|
-
const id =
|
|
7934
|
+
const id = crypto6.randomUUID();
|
|
7669
7935
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
7670
7936
|
const slug = slugify(input.title);
|
|
7671
7937
|
let earlySessionScope = null;
|
|
@@ -7724,8 +7990,8 @@ ${laneWarning}` : laneWarning;
|
|
|
7724
7990
|
}
|
|
7725
7991
|
if (input.baseDir) {
|
|
7726
7992
|
try {
|
|
7727
|
-
await mkdir4(
|
|
7728
|
-
await mkdir4(
|
|
7993
|
+
await mkdir4(path15.join(input.baseDir, "exe", "output"), { recursive: true });
|
|
7994
|
+
await mkdir4(path15.join(input.baseDir, "exe", "research"), { recursive: true });
|
|
7729
7995
|
await ensureArchitectureDoc(input.baseDir, input.projectName);
|
|
7730
7996
|
await ensureGitignoreExe(input.baseDir);
|
|
7731
7997
|
} catch {
|
|
@@ -7761,13 +8027,19 @@ ${laneWarning}` : laneWarning;
|
|
|
7761
8027
|
});
|
|
7762
8028
|
if (input.baseDir) {
|
|
7763
8029
|
try {
|
|
7764
|
-
const EXE_OS_DIR =
|
|
7765
|
-
const mdPath =
|
|
7766
|
-
const mdDir =
|
|
7767
|
-
if (!
|
|
8030
|
+
const EXE_OS_DIR = path15.join(os11.homedir(), ".exe-os");
|
|
8031
|
+
const mdPath = path15.join(EXE_OS_DIR, taskFile);
|
|
8032
|
+
const mdDir = path15.dirname(mdPath);
|
|
8033
|
+
if (!existsSync14(mdDir)) await mkdir4(mdDir, { recursive: true });
|
|
7768
8034
|
const reviewer = input.reviewer ?? input.assignedBy;
|
|
7769
8035
|
const mdContent = `# ${input.title}
|
|
7770
8036
|
|
|
8037
|
+
## MANDATORY: When done
|
|
8038
|
+
|
|
8039
|
+
You MUST call update_task with status "done" and a result summary when finished.
|
|
8040
|
+
If you skip this, your reviewer will not know you're done and your work won't be reviewed.
|
|
8041
|
+
Do NOT let a failed commit or any error prevent you from calling update_task(done).
|
|
8042
|
+
|
|
7771
8043
|
**ID:** ${id}
|
|
7772
8044
|
**Status:** ${initialStatus}
|
|
7773
8045
|
**Priority:** ${input.priority}
|
|
@@ -7781,12 +8053,6 @@ ${laneWarning}` : laneWarning;
|
|
|
7781
8053
|
## Context
|
|
7782
8054
|
|
|
7783
8055
|
${input.context}
|
|
7784
|
-
|
|
7785
|
-
## MANDATORY: When done
|
|
7786
|
-
|
|
7787
|
-
You MUST call update_task with status "done" and a result summary when finished.
|
|
7788
|
-
If you skip this, your reviewer will not know you're done and your work won't be reviewed.
|
|
7789
|
-
Do NOT let a failed commit or any error prevent you from calling update_task(done).
|
|
7790
8056
|
`;
|
|
7791
8057
|
await writeFile4(mdPath, mdContent, "utf-8");
|
|
7792
8058
|
} catch (err) {
|
|
@@ -8035,7 +8301,7 @@ ${input.result}` : `\u26A0\uFE0F ${warning}`;
|
|
|
8035
8301
|
await client.execute("PRAGMA wal_checkpoint(PASSIVE)");
|
|
8036
8302
|
} catch {
|
|
8037
8303
|
}
|
|
8038
|
-
if (input.status === "done" || input.status === "cancelled") {
|
|
8304
|
+
if (input.status === "done" || input.status === "cancelled" || input.status === "closed") {
|
|
8039
8305
|
try {
|
|
8040
8306
|
const { clearQueueForAgent: clearQueueForAgent2 } = await Promise.resolve().then(() => (init_intercom_queue(), intercom_queue_exports));
|
|
8041
8307
|
clearQueueForAgent2(String(row.assigned_to));
|
|
@@ -8064,9 +8330,9 @@ async function deleteTaskCore(taskId, _baseDir) {
|
|
|
8064
8330
|
return { taskFile, assignedTo, assignedBy, taskSlug };
|
|
8065
8331
|
}
|
|
8066
8332
|
async function ensureArchitectureDoc(baseDir, projectName) {
|
|
8067
|
-
const archPath =
|
|
8333
|
+
const archPath = path15.join(baseDir, "exe", "ARCHITECTURE.md");
|
|
8068
8334
|
try {
|
|
8069
|
-
if (
|
|
8335
|
+
if (existsSync14(archPath)) return;
|
|
8070
8336
|
const template = [
|
|
8071
8337
|
`# ${projectName} \u2014 System Architecture`,
|
|
8072
8338
|
"",
|
|
@@ -8099,10 +8365,10 @@ async function ensureArchitectureDoc(baseDir, projectName) {
|
|
|
8099
8365
|
}
|
|
8100
8366
|
}
|
|
8101
8367
|
async function ensureGitignoreExe(baseDir) {
|
|
8102
|
-
const gitignorePath =
|
|
8368
|
+
const gitignorePath = path15.join(baseDir, ".gitignore");
|
|
8103
8369
|
try {
|
|
8104
|
-
if (
|
|
8105
|
-
const content =
|
|
8370
|
+
if (existsSync14(gitignorePath)) {
|
|
8371
|
+
const content = readFileSync12(gitignorePath, "utf-8");
|
|
8106
8372
|
if (/^\/?exe\/?$/m.test(content)) return;
|
|
8107
8373
|
await appendFile(gitignorePath, "\n# Employee task assignments (private)\n/exe/\n");
|
|
8108
8374
|
} else {
|
|
@@ -8133,58 +8399,42 @@ var init_tasks_crud = __esm({
|
|
|
8133
8399
|
});
|
|
8134
8400
|
|
|
8135
8401
|
// src/lib/tasks-review.ts
|
|
8136
|
-
import
|
|
8137
|
-
import { existsSync as
|
|
8402
|
+
import path16 from "path";
|
|
8403
|
+
import { existsSync as existsSync15, readdirSync as readdirSync3, unlinkSync as unlinkSync4 } from "fs";
|
|
8138
8404
|
async function countPendingReviews(sessionScope) {
|
|
8139
8405
|
const client = getClient();
|
|
8140
|
-
|
|
8141
|
-
|
|
8142
|
-
|
|
8143
|
-
args: [sessionScope]
|
|
8144
|
-
});
|
|
8145
|
-
return Number(result2.rows[0]?.cnt) || 0;
|
|
8146
|
-
}
|
|
8406
|
+
const scope = strictSessionScopeFilter(
|
|
8407
|
+
sessionScope === void 0 ? getCurrentSessionScope() : sessionScope
|
|
8408
|
+
);
|
|
8147
8409
|
const result = await client.execute({
|
|
8148
|
-
sql:
|
|
8149
|
-
|
|
8410
|
+
sql: `SELECT COUNT(*) as cnt FROM tasks
|
|
8411
|
+
WHERE status = 'needs_review'${scope.sql}`,
|
|
8412
|
+
args: [...scope.args]
|
|
8150
8413
|
});
|
|
8151
8414
|
return Number(result.rows[0]?.cnt) || 0;
|
|
8152
8415
|
}
|
|
8153
8416
|
async function countNewPendingReviewsSince(sinceIso, sessionScope) {
|
|
8154
8417
|
const client = getClient();
|
|
8155
|
-
|
|
8156
|
-
|
|
8157
|
-
|
|
8158
|
-
WHERE status = 'needs_review' AND updated_at > ?
|
|
8159
|
-
AND session_scope = ?`,
|
|
8160
|
-
args: [sinceIso, sessionScope]
|
|
8161
|
-
});
|
|
8162
|
-
return Number(result2.rows[0]?.cnt) || 0;
|
|
8163
|
-
}
|
|
8418
|
+
const scope = strictSessionScopeFilter(
|
|
8419
|
+
sessionScope === void 0 ? getCurrentSessionScope() : sessionScope
|
|
8420
|
+
);
|
|
8164
8421
|
const result = await client.execute({
|
|
8165
8422
|
sql: `SELECT COUNT(*) as cnt FROM tasks
|
|
8166
|
-
WHERE status = 'needs_review' AND updated_at >
|
|
8167
|
-
args: [sinceIso]
|
|
8423
|
+
WHERE status = 'needs_review' AND updated_at > ?${scope.sql}`,
|
|
8424
|
+
args: [sinceIso, ...scope.args]
|
|
8168
8425
|
});
|
|
8169
8426
|
return Number(result.rows[0]?.cnt) || 0;
|
|
8170
8427
|
}
|
|
8171
8428
|
async function listPendingReviews(limit, sessionScope) {
|
|
8172
8429
|
const client = getClient();
|
|
8173
|
-
|
|
8174
|
-
|
|
8175
|
-
|
|
8176
|
-
WHERE status = 'needs_review'
|
|
8177
|
-
AND session_scope = ?
|
|
8178
|
-
ORDER BY updated_at ASC LIMIT ?`,
|
|
8179
|
-
args: [sessionScope, limit]
|
|
8180
|
-
});
|
|
8181
|
-
return result2.rows;
|
|
8182
|
-
}
|
|
8430
|
+
const scope = strictSessionScopeFilter(
|
|
8431
|
+
sessionScope === void 0 ? getCurrentSessionScope() : sessionScope
|
|
8432
|
+
);
|
|
8183
8433
|
const result = await client.execute({
|
|
8184
8434
|
sql: `SELECT title, assigned_to, project_name, updated_at FROM tasks
|
|
8185
|
-
WHERE status = 'needs_review'
|
|
8435
|
+
WHERE status = 'needs_review'${scope.sql}
|
|
8186
8436
|
ORDER BY updated_at ASC LIMIT ?`,
|
|
8187
|
-
args: [limit]
|
|
8437
|
+
args: [...scope.args, limit]
|
|
8188
8438
|
});
|
|
8189
8439
|
return result.rows;
|
|
8190
8440
|
}
|
|
@@ -8196,7 +8446,7 @@ async function cleanupOrphanedReviews() {
|
|
|
8196
8446
|
WHERE status IN ('open', 'needs_review', 'in_progress')
|
|
8197
8447
|
AND assigned_by = 'system'
|
|
8198
8448
|
AND title LIKE 'Review:%'
|
|
8199
|
-
AND parent_task_id IN (SELECT id FROM tasks WHERE status IN ('done', 'cancelled'))`,
|
|
8449
|
+
AND parent_task_id IN (SELECT id FROM tasks WHERE status IN ('done', 'cancelled', 'closed'))`,
|
|
8200
8450
|
args: [now]
|
|
8201
8451
|
});
|
|
8202
8452
|
const r1b = await client.execute({
|
|
@@ -8315,11 +8565,11 @@ async function cleanupReviewFile(row, taskFile, _baseDir) {
|
|
|
8315
8565
|
);
|
|
8316
8566
|
}
|
|
8317
8567
|
try {
|
|
8318
|
-
const cacheDir =
|
|
8319
|
-
if (
|
|
8568
|
+
const cacheDir = path16.join(EXE_AI_DIR, "session-cache");
|
|
8569
|
+
if (existsSync15(cacheDir)) {
|
|
8320
8570
|
for (const f of readdirSync3(cacheDir)) {
|
|
8321
8571
|
if (f.startsWith("review-notified-")) {
|
|
8322
|
-
unlinkSync4(
|
|
8572
|
+
unlinkSync4(path16.join(cacheDir, f));
|
|
8323
8573
|
}
|
|
8324
8574
|
}
|
|
8325
8575
|
}
|
|
@@ -8336,11 +8586,12 @@ var init_tasks_review = __esm({
|
|
|
8336
8586
|
init_tmux_routing();
|
|
8337
8587
|
init_session_key();
|
|
8338
8588
|
init_state_bus();
|
|
8589
|
+
init_task_scope();
|
|
8339
8590
|
}
|
|
8340
8591
|
});
|
|
8341
8592
|
|
|
8342
8593
|
// src/lib/tasks-chain.ts
|
|
8343
|
-
import
|
|
8594
|
+
import path17 from "path";
|
|
8344
8595
|
import { readFile as readFile4, writeFile as writeFile5 } from "fs/promises";
|
|
8345
8596
|
async function cascadeUnblock(taskId, baseDir, now) {
|
|
8346
8597
|
const client = getClient();
|
|
@@ -8357,7 +8608,7 @@ async function cascadeUnblock(taskId, baseDir, now) {
|
|
|
8357
8608
|
});
|
|
8358
8609
|
for (const ur of unblockedRows.rows) {
|
|
8359
8610
|
try {
|
|
8360
|
-
const ubFile =
|
|
8611
|
+
const ubFile = path17.join(baseDir, String(ur.task_file));
|
|
8361
8612
|
let ubContent = await readFile4(ubFile, "utf-8");
|
|
8362
8613
|
ubContent = ubContent.replace(/\*\*Status:\*\* blocked/, "**Status:** open");
|
|
8363
8614
|
ubContent = ubContent.replace(/\n\*\*Blocked by:\*\*.*\n/, "\n");
|
|
@@ -8392,7 +8643,7 @@ async function checkSubtaskCompletion(parentTaskId, projectName) {
|
|
|
8392
8643
|
const scScope = sessionScopeFilter();
|
|
8393
8644
|
const remaining = await client.execute({
|
|
8394
8645
|
sql: `SELECT COUNT(*) as cnt FROM tasks
|
|
8395
|
-
WHERE parent_task_id = ? AND status NOT IN ('done', 'cancelled')${scScope.sql}`,
|
|
8646
|
+
WHERE parent_task_id = ? AND status NOT IN ('done', 'cancelled', 'closed')${scScope.sql}`,
|
|
8396
8647
|
args: [parentTaskId, ...scScope.args]
|
|
8397
8648
|
});
|
|
8398
8649
|
const cnt = Number(remaining.rows[0]?.cnt ?? 1);
|
|
@@ -8426,7 +8677,7 @@ var init_tasks_chain = __esm({
|
|
|
8426
8677
|
|
|
8427
8678
|
// src/lib/project-name.ts
|
|
8428
8679
|
import { execSync as execSync5 } from "child_process";
|
|
8429
|
-
import
|
|
8680
|
+
import path18 from "path";
|
|
8430
8681
|
function getProjectName(cwd) {
|
|
8431
8682
|
const dir = cwd ?? process.cwd();
|
|
8432
8683
|
if (_cached2 && _cachedCwd === dir) return _cached2;
|
|
@@ -8439,7 +8690,7 @@ function getProjectName(cwd) {
|
|
|
8439
8690
|
timeout: 2e3,
|
|
8440
8691
|
stdio: ["pipe", "pipe", "pipe"]
|
|
8441
8692
|
}).trim();
|
|
8442
|
-
repoRoot =
|
|
8693
|
+
repoRoot = path18.dirname(gitCommonDir);
|
|
8443
8694
|
} catch {
|
|
8444
8695
|
repoRoot = execSync5("git rev-parse --show-toplevel", {
|
|
8445
8696
|
cwd: dir,
|
|
@@ -8448,11 +8699,11 @@ function getProjectName(cwd) {
|
|
|
8448
8699
|
stdio: ["pipe", "pipe", "pipe"]
|
|
8449
8700
|
}).trim();
|
|
8450
8701
|
}
|
|
8451
|
-
_cached2 =
|
|
8702
|
+
_cached2 = path18.basename(repoRoot);
|
|
8452
8703
|
_cachedCwd = dir;
|
|
8453
8704
|
return _cached2;
|
|
8454
8705
|
} catch {
|
|
8455
|
-
_cached2 =
|
|
8706
|
+
_cached2 = path18.basename(dir);
|
|
8456
8707
|
_cachedCwd = dir;
|
|
8457
8708
|
return _cached2;
|
|
8458
8709
|
}
|
|
@@ -8595,10 +8846,10 @@ var init_tasks_notify = __esm({
|
|
|
8595
8846
|
});
|
|
8596
8847
|
|
|
8597
8848
|
// src/lib/behaviors.ts
|
|
8598
|
-
import
|
|
8849
|
+
import crypto7 from "crypto";
|
|
8599
8850
|
async function storeBehavior(opts) {
|
|
8600
8851
|
const client = getClient();
|
|
8601
|
-
const id =
|
|
8852
|
+
const id = crypto7.randomUUID();
|
|
8602
8853
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
8603
8854
|
await client.execute({
|
|
8604
8855
|
sql: `INSERT INTO behaviors (id, agent_id, project_name, domain, priority, content, active, created_at, updated_at)
|
|
@@ -8627,7 +8878,7 @@ __export(skill_learning_exports, {
|
|
|
8627
8878
|
storeTrajectory: () => storeTrajectory,
|
|
8628
8879
|
sweepTrajectories: () => sweepTrajectories
|
|
8629
8880
|
});
|
|
8630
|
-
import
|
|
8881
|
+
import crypto8 from "crypto";
|
|
8631
8882
|
async function extractTrajectory(taskId, agentId) {
|
|
8632
8883
|
const client = getClient();
|
|
8633
8884
|
const result = await client.execute({
|
|
@@ -8656,11 +8907,11 @@ async function extractTrajectory(taskId, agentId) {
|
|
|
8656
8907
|
return signature;
|
|
8657
8908
|
}
|
|
8658
8909
|
function hashSignature(signature) {
|
|
8659
|
-
return
|
|
8910
|
+
return crypto8.createHash("sha256").update(signature.join("|")).digest("hex").slice(0, 16);
|
|
8660
8911
|
}
|
|
8661
8912
|
async function storeTrajectory(opts) {
|
|
8662
8913
|
const client = getClient();
|
|
8663
|
-
const id =
|
|
8914
|
+
const id = crypto8.randomUUID();
|
|
8664
8915
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
8665
8916
|
const signatureHash = hashSignature(opts.signature);
|
|
8666
8917
|
await client.execute({
|
|
@@ -8925,8 +9176,8 @@ __export(tasks_exports, {
|
|
|
8925
9176
|
updateTaskStatus: () => updateTaskStatus,
|
|
8926
9177
|
writeCheckpoint: () => writeCheckpoint
|
|
8927
9178
|
});
|
|
8928
|
-
import
|
|
8929
|
-
import { writeFileSync as
|
|
9179
|
+
import path19 from "path";
|
|
9180
|
+
import { writeFileSync as writeFileSync7, mkdirSync as mkdirSync7, unlinkSync as unlinkSync5 } from "fs";
|
|
8930
9181
|
async function createTask(input) {
|
|
8931
9182
|
const result = await createTaskCore(input);
|
|
8932
9183
|
if (!input.skipDispatch && result.status !== "blocked" && !process.env.VITEST) {
|
|
@@ -8945,12 +9196,12 @@ async function updateTask(input) {
|
|
|
8945
9196
|
const { row, taskFile, now, taskId } = await updateTaskStatus(input);
|
|
8946
9197
|
try {
|
|
8947
9198
|
const agent = String(row.assigned_to);
|
|
8948
|
-
const cacheDir =
|
|
8949
|
-
const cachePath =
|
|
9199
|
+
const cacheDir = path19.join(EXE_AI_DIR, "session-cache");
|
|
9200
|
+
const cachePath = path19.join(cacheDir, `current-task-${agent}.json`);
|
|
8950
9201
|
if (input.status === "in_progress") {
|
|
8951
9202
|
mkdirSync7(cacheDir, { recursive: true });
|
|
8952
|
-
|
|
8953
|
-
} else if (input.status === "done" || input.status === "blocked" || input.status === "cancelled") {
|
|
9203
|
+
writeFileSync7(cachePath, JSON.stringify({ taskId, title: String(row.title) }));
|
|
9204
|
+
} else if (input.status === "done" || input.status === "blocked" || input.status === "cancelled" || input.status === "closed") {
|
|
8954
9205
|
try {
|
|
8955
9206
|
unlinkSync5(cachePath);
|
|
8956
9207
|
} catch {
|
|
@@ -8958,10 +9209,10 @@ async function updateTask(input) {
|
|
|
8958
9209
|
}
|
|
8959
9210
|
} catch {
|
|
8960
9211
|
}
|
|
8961
|
-
if (input.status === "done") {
|
|
9212
|
+
if (input.status === "done" || input.status === "closed") {
|
|
8962
9213
|
await cleanupReviewFile(row, taskFile, input.baseDir);
|
|
8963
9214
|
}
|
|
8964
|
-
if (input.status === "done" || input.status === "cancelled") {
|
|
9215
|
+
if (input.status === "done" || input.status === "cancelled" || input.status === "closed") {
|
|
8965
9216
|
try {
|
|
8966
9217
|
const client = getClient();
|
|
8967
9218
|
const taskTitle = String(row.title);
|
|
@@ -8977,7 +9228,7 @@ async function updateTask(input) {
|
|
|
8977
9228
|
if (!isCoordinatorName(assignedAgent)) {
|
|
8978
9229
|
try {
|
|
8979
9230
|
const draftClient = getClient();
|
|
8980
|
-
if (input.status === "done") {
|
|
9231
|
+
if (input.status === "done" || input.status === "closed") {
|
|
8981
9232
|
await draftClient.execute({
|
|
8982
9233
|
sql: `UPDATE memories SET draft = 0 WHERE agent_id = ? AND draft = 1`,
|
|
8983
9234
|
args: [assignedAgent]
|
|
@@ -8994,7 +9245,7 @@ async function updateTask(input) {
|
|
|
8994
9245
|
try {
|
|
8995
9246
|
const client = getClient();
|
|
8996
9247
|
const cascaded = await client.execute({
|
|
8997
|
-
sql: `UPDATE tasks SET status = '
|
|
9248
|
+
sql: `UPDATE tasks SET status = 'closed', updated_at = ?
|
|
8998
9249
|
WHERE parent_task_id = ? AND status = 'needs_review'`,
|
|
8999
9250
|
args: [now, taskId]
|
|
9000
9251
|
});
|
|
@@ -9007,14 +9258,14 @@ async function updateTask(input) {
|
|
|
9007
9258
|
} catch {
|
|
9008
9259
|
}
|
|
9009
9260
|
}
|
|
9010
|
-
const isTerminal = input.status === "done" || input.status === "needs_review";
|
|
9261
|
+
const isTerminal = input.status === "done" || input.status === "needs_review" || input.status === "closed";
|
|
9011
9262
|
if (isTerminal) {
|
|
9012
9263
|
const isCoordinator = isCoordinatorName(String(row.assigned_to));
|
|
9013
9264
|
if (!isCoordinator) {
|
|
9014
9265
|
notifyTaskDone();
|
|
9015
9266
|
}
|
|
9016
9267
|
await markTaskNotificationsRead(taskFile);
|
|
9017
|
-
if (input.status === "done") {
|
|
9268
|
+
if (input.status === "done" || input.status === "closed") {
|
|
9018
9269
|
try {
|
|
9019
9270
|
await cascadeUnblock(taskId, input.baseDir, now);
|
|
9020
9271
|
} catch {
|
|
@@ -9034,7 +9285,7 @@ async function updateTask(input) {
|
|
|
9034
9285
|
}
|
|
9035
9286
|
}
|
|
9036
9287
|
}
|
|
9037
|
-
if (input.status === "done" && !isCoordinatorName(String(row.assigned_to)) && !process.env.VITEST) {
|
|
9288
|
+
if ((input.status === "done" || input.status === "closed") && !isCoordinatorName(String(row.assigned_to)) && !process.env.VITEST) {
|
|
9038
9289
|
Promise.resolve().then(() => (init_skill_learning(), skill_learning_exports)).then(
|
|
9039
9290
|
({ captureAndLearn: captureAndLearn2 }) => captureAndLearn2({
|
|
9040
9291
|
taskId,
|
|
@@ -9406,6 +9657,7 @@ __export(tmux_routing_exports, {
|
|
|
9406
9657
|
isEmployeeAlive: () => isEmployeeAlive,
|
|
9407
9658
|
isExeSession: () => isExeSession,
|
|
9408
9659
|
isSessionBusy: () => isSessionBusy,
|
|
9660
|
+
notifyCoordinatorTaskCompletion: () => notifyCoordinatorTaskCompletion,
|
|
9409
9661
|
notifyParentExe: () => notifyParentExe,
|
|
9410
9662
|
parseParentExe: () => parseParentExe,
|
|
9411
9663
|
registerParentExe: () => registerParentExe,
|
|
@@ -9416,13 +9668,13 @@ __export(tmux_routing_exports, {
|
|
|
9416
9668
|
verifyPaneAtCapacity: () => verifyPaneAtCapacity
|
|
9417
9669
|
});
|
|
9418
9670
|
import { execFileSync as execFileSync2, execSync as execSync6 } from "child_process";
|
|
9419
|
-
import { readFileSync as
|
|
9420
|
-
import
|
|
9421
|
-
import
|
|
9671
|
+
import { readFileSync as readFileSync13, writeFileSync as writeFileSync8, mkdirSync as mkdirSync8, existsSync as existsSync16, appendFileSync, readdirSync as readdirSync4 } from "fs";
|
|
9672
|
+
import path20 from "path";
|
|
9673
|
+
import os12 from "os";
|
|
9422
9674
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
9423
9675
|
import { unlinkSync as unlinkSync6 } from "fs";
|
|
9424
9676
|
function spawnLockPath(sessionName) {
|
|
9425
|
-
return
|
|
9677
|
+
return path20.join(SPAWN_LOCK_DIR, `${sessionName}.lock`);
|
|
9426
9678
|
}
|
|
9427
9679
|
function isProcessAlive(pid) {
|
|
9428
9680
|
try {
|
|
@@ -9433,13 +9685,13 @@ function isProcessAlive(pid) {
|
|
|
9433
9685
|
}
|
|
9434
9686
|
}
|
|
9435
9687
|
function acquireSpawnLock2(sessionName) {
|
|
9436
|
-
if (!
|
|
9688
|
+
if (!existsSync16(SPAWN_LOCK_DIR)) {
|
|
9437
9689
|
mkdirSync8(SPAWN_LOCK_DIR, { recursive: true });
|
|
9438
9690
|
}
|
|
9439
9691
|
const lockFile = spawnLockPath(sessionName);
|
|
9440
|
-
if (
|
|
9692
|
+
if (existsSync16(lockFile)) {
|
|
9441
9693
|
try {
|
|
9442
|
-
const lock = JSON.parse(
|
|
9694
|
+
const lock = JSON.parse(readFileSync13(lockFile, "utf8"));
|
|
9443
9695
|
const age = Date.now() - lock.timestamp;
|
|
9444
9696
|
if (isProcessAlive(lock.pid) && age < 6e4) {
|
|
9445
9697
|
return false;
|
|
@@ -9447,7 +9699,7 @@ function acquireSpawnLock2(sessionName) {
|
|
|
9447
9699
|
} catch {
|
|
9448
9700
|
}
|
|
9449
9701
|
}
|
|
9450
|
-
|
|
9702
|
+
writeFileSync8(lockFile, JSON.stringify({ pid: process.pid, timestamp: Date.now() }));
|
|
9451
9703
|
return true;
|
|
9452
9704
|
}
|
|
9453
9705
|
function releaseSpawnLock2(sessionName) {
|
|
@@ -9459,13 +9711,13 @@ function releaseSpawnLock2(sessionName) {
|
|
|
9459
9711
|
function resolveBehaviorsExporterScript() {
|
|
9460
9712
|
try {
|
|
9461
9713
|
const thisFile = fileURLToPath2(import.meta.url);
|
|
9462
|
-
const scriptPath =
|
|
9463
|
-
|
|
9714
|
+
const scriptPath = path20.join(
|
|
9715
|
+
path20.dirname(thisFile),
|
|
9464
9716
|
"..",
|
|
9465
9717
|
"bin",
|
|
9466
9718
|
"exe-export-behaviors.js"
|
|
9467
9719
|
);
|
|
9468
|
-
return
|
|
9720
|
+
return existsSync16(scriptPath) ? scriptPath : null;
|
|
9469
9721
|
} catch {
|
|
9470
9722
|
return null;
|
|
9471
9723
|
}
|
|
@@ -9531,12 +9783,12 @@ function extractRootExe(name) {
|
|
|
9531
9783
|
return parts.length > 0 ? parts[parts.length - 1] : null;
|
|
9532
9784
|
}
|
|
9533
9785
|
function registerParentExe(sessionKey, parentExe, dispatchedBy) {
|
|
9534
|
-
if (!
|
|
9786
|
+
if (!existsSync16(SESSION_CACHE)) {
|
|
9535
9787
|
mkdirSync8(SESSION_CACHE, { recursive: true });
|
|
9536
9788
|
}
|
|
9537
9789
|
const rootExe = extractRootExe(parentExe) ?? parentExe;
|
|
9538
|
-
const filePath =
|
|
9539
|
-
|
|
9790
|
+
const filePath = path20.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`);
|
|
9791
|
+
writeFileSync8(filePath, JSON.stringify({
|
|
9540
9792
|
parentExe: rootExe,
|
|
9541
9793
|
dispatchedBy: dispatchedBy || rootExe,
|
|
9542
9794
|
registeredAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -9544,7 +9796,7 @@ function registerParentExe(sessionKey, parentExe, dispatchedBy) {
|
|
|
9544
9796
|
}
|
|
9545
9797
|
function getParentExe(sessionKey) {
|
|
9546
9798
|
try {
|
|
9547
|
-
const data = JSON.parse(
|
|
9799
|
+
const data = JSON.parse(readFileSync13(path20.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
|
|
9548
9800
|
return data.parentExe || null;
|
|
9549
9801
|
} catch {
|
|
9550
9802
|
return null;
|
|
@@ -9552,8 +9804,8 @@ function getParentExe(sessionKey) {
|
|
|
9552
9804
|
}
|
|
9553
9805
|
function getDispatchedBy(sessionKey) {
|
|
9554
9806
|
try {
|
|
9555
|
-
const data = JSON.parse(
|
|
9556
|
-
|
|
9807
|
+
const data = JSON.parse(readFileSync13(
|
|
9808
|
+
path20.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`),
|
|
9557
9809
|
"utf8"
|
|
9558
9810
|
));
|
|
9559
9811
|
return data.dispatchedBy ?? data.parentExe ?? null;
|
|
@@ -9623,8 +9875,8 @@ async function verifyPaneAtCapacity(sessionName) {
|
|
|
9623
9875
|
}
|
|
9624
9876
|
function readDebounceState() {
|
|
9625
9877
|
try {
|
|
9626
|
-
if (!
|
|
9627
|
-
const raw = JSON.parse(
|
|
9878
|
+
if (!existsSync16(DEBOUNCE_FILE)) return {};
|
|
9879
|
+
const raw = JSON.parse(readFileSync13(DEBOUNCE_FILE, "utf8"));
|
|
9628
9880
|
const state = {};
|
|
9629
9881
|
for (const [key, val] of Object.entries(raw)) {
|
|
9630
9882
|
if (typeof val === "number") {
|
|
@@ -9640,8 +9892,8 @@ function readDebounceState() {
|
|
|
9640
9892
|
}
|
|
9641
9893
|
function writeDebounceState(state) {
|
|
9642
9894
|
try {
|
|
9643
|
-
if (!
|
|
9644
|
-
|
|
9895
|
+
if (!existsSync16(SESSION_CACHE)) mkdirSync8(SESSION_CACHE, { recursive: true });
|
|
9896
|
+
writeFileSync8(DEBOUNCE_FILE, JSON.stringify(state));
|
|
9645
9897
|
} catch {
|
|
9646
9898
|
}
|
|
9647
9899
|
}
|
|
@@ -9739,8 +9991,8 @@ function sendIntercom(targetSession) {
|
|
|
9739
9991
|
try {
|
|
9740
9992
|
const rawAgent = targetSession.split("-")[0] ?? targetSession;
|
|
9741
9993
|
const agent = baseAgentName(rawAgent);
|
|
9742
|
-
const markerPath =
|
|
9743
|
-
if (
|
|
9994
|
+
const markerPath = path20.join(SESSION_CACHE, `current-task-${agent}.json`);
|
|
9995
|
+
if (existsSync16(markerPath)) {
|
|
9744
9996
|
logIntercom(`SKIP \u2192 ${targetSession} (has in_progress task marker \u2014 will auto-chain)`);
|
|
9745
9997
|
return "debounced";
|
|
9746
9998
|
}
|
|
@@ -9749,8 +10001,8 @@ function sendIntercom(targetSession) {
|
|
|
9749
10001
|
try {
|
|
9750
10002
|
const rawAgent = targetSession.split("-")[0] ?? targetSession;
|
|
9751
10003
|
const agent = baseAgentName(rawAgent);
|
|
9752
|
-
const taskDir =
|
|
9753
|
-
if (
|
|
10004
|
+
const taskDir = path20.join(process.cwd(), "exe", agent);
|
|
10005
|
+
if (existsSync16(taskDir)) {
|
|
9754
10006
|
const files = readdirSync4(taskDir).filter(
|
|
9755
10007
|
(f) => f.endsWith(".md") && f !== "DONE.txt"
|
|
9756
10008
|
);
|
|
@@ -9810,6 +10062,21 @@ function notifyParentExe(sessionKey) {
|
|
|
9810
10062
|
}
|
|
9811
10063
|
return true;
|
|
9812
10064
|
}
|
|
10065
|
+
function notifyCoordinatorTaskCompletion(coordinatorSession, agentName, taskTitle) {
|
|
10066
|
+
const transport = getTransport();
|
|
10067
|
+
try {
|
|
10068
|
+
const sessions = transport.listSessions();
|
|
10069
|
+
if (!sessions.includes(coordinatorSession)) return false;
|
|
10070
|
+
execSync6(
|
|
10071
|
+
`tmux send-keys -t ${JSON.stringify(coordinatorSession)} '/exe-intercom' Enter`,
|
|
10072
|
+
{ timeout: 3e3 }
|
|
10073
|
+
);
|
|
10074
|
+
logIntercom(`COMPLETION \u2192 ${coordinatorSession} (${agentName} completed "${taskTitle.slice(0, 50)}")`);
|
|
10075
|
+
return true;
|
|
10076
|
+
} catch {
|
|
10077
|
+
return false;
|
|
10078
|
+
}
|
|
10079
|
+
}
|
|
9813
10080
|
function ensureEmployee(employeeName, exeSession, projectDir, opts) {
|
|
9814
10081
|
if (isCoordinatorName(employeeName)) {
|
|
9815
10082
|
return { status: "failed", sessionName: "", error: "The COO is not a dispatchable employee" };
|
|
@@ -9883,26 +10150,26 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
9883
10150
|
const transport = getTransport();
|
|
9884
10151
|
const sessionName = employeeSessionName(employeeName, exeSession, opts?.instance);
|
|
9885
10152
|
const instanceLabel = opts?.instance != null && opts.instance > 0 ? `${employeeName}${opts.instance}` : employeeName;
|
|
9886
|
-
const logDir =
|
|
9887
|
-
const logFile =
|
|
9888
|
-
if (!
|
|
10153
|
+
const logDir = path20.join(os12.homedir(), ".exe-os", "session-logs");
|
|
10154
|
+
const logFile = path20.join(logDir, `${instanceLabel}-${Date.now()}.log`);
|
|
10155
|
+
if (!existsSync16(logDir)) {
|
|
9889
10156
|
mkdirSync8(logDir, { recursive: true });
|
|
9890
10157
|
}
|
|
9891
10158
|
transport.kill(sessionName);
|
|
9892
10159
|
let cleanupSuffix = "";
|
|
9893
10160
|
try {
|
|
9894
10161
|
const thisFile = fileURLToPath2(import.meta.url);
|
|
9895
|
-
const cleanupScript =
|
|
9896
|
-
if (
|
|
10162
|
+
const cleanupScript = path20.join(path20.dirname(thisFile), "..", "bin", "exe-session-cleanup.js");
|
|
10163
|
+
if (existsSync16(cleanupScript)) {
|
|
9897
10164
|
cleanupSuffix = `; ${process.execPath} "${cleanupScript}" "${employeeName}" "${exeSession}"`;
|
|
9898
10165
|
}
|
|
9899
10166
|
} catch {
|
|
9900
10167
|
}
|
|
9901
10168
|
try {
|
|
9902
|
-
const claudeJsonPath =
|
|
10169
|
+
const claudeJsonPath = path20.join(os12.homedir(), ".claude.json");
|
|
9903
10170
|
let claudeJson = {};
|
|
9904
10171
|
try {
|
|
9905
|
-
claudeJson = JSON.parse(
|
|
10172
|
+
claudeJson = JSON.parse(readFileSync13(claudeJsonPath, "utf8"));
|
|
9906
10173
|
} catch {
|
|
9907
10174
|
}
|
|
9908
10175
|
if (!claudeJson.projects) claudeJson.projects = {};
|
|
@@ -9910,17 +10177,17 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
9910
10177
|
const trustDir = opts?.cwd ?? projectDir;
|
|
9911
10178
|
if (!projects[trustDir]) projects[trustDir] = {};
|
|
9912
10179
|
projects[trustDir].hasTrustDialogAccepted = true;
|
|
9913
|
-
|
|
10180
|
+
writeFileSync8(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
|
|
9914
10181
|
} catch {
|
|
9915
10182
|
}
|
|
9916
10183
|
try {
|
|
9917
|
-
const settingsDir =
|
|
10184
|
+
const settingsDir = path20.join(os12.homedir(), ".claude", "projects");
|
|
9918
10185
|
const normalizedKey = (opts?.cwd ?? projectDir).replace(/\//g, "-").replace(/^-/, "");
|
|
9919
|
-
const projSettingsDir =
|
|
9920
|
-
const settingsPath =
|
|
10186
|
+
const projSettingsDir = path20.join(settingsDir, normalizedKey);
|
|
10187
|
+
const settingsPath = path20.join(projSettingsDir, "settings.json");
|
|
9921
10188
|
let settings = {};
|
|
9922
10189
|
try {
|
|
9923
|
-
settings = JSON.parse(
|
|
10190
|
+
settings = JSON.parse(readFileSync13(settingsPath, "utf8"));
|
|
9924
10191
|
} catch {
|
|
9925
10192
|
}
|
|
9926
10193
|
const perms = settings.permissions ?? {};
|
|
@@ -9949,7 +10216,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
9949
10216
|
perms.allow = allow;
|
|
9950
10217
|
settings.permissions = perms;
|
|
9951
10218
|
mkdirSync8(projSettingsDir, { recursive: true });
|
|
9952
|
-
|
|
10219
|
+
writeFileSync8(settingsPath, JSON.stringify(settings, null, 2) + "\n");
|
|
9953
10220
|
}
|
|
9954
10221
|
} catch {
|
|
9955
10222
|
}
|
|
@@ -9964,8 +10231,8 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
9964
10231
|
let behaviorsFlag = "";
|
|
9965
10232
|
let legacyFallbackWarned = false;
|
|
9966
10233
|
if (!useExeAgent && !useBinSymlink) {
|
|
9967
|
-
const identityPath =
|
|
9968
|
-
|
|
10234
|
+
const identityPath = path20.join(
|
|
10235
|
+
os12.homedir(),
|
|
9969
10236
|
".exe-os",
|
|
9970
10237
|
"identity",
|
|
9971
10238
|
`${employeeName}.md`
|
|
@@ -9974,13 +10241,13 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
9974
10241
|
const hasAgentFlag = claudeSupportsAgentFlag();
|
|
9975
10242
|
if (hasAgentFlag) {
|
|
9976
10243
|
identityFlag = ` --agent ${employeeName}`;
|
|
9977
|
-
} else if (
|
|
10244
|
+
} else if (existsSync16(identityPath)) {
|
|
9978
10245
|
identityFlag = ` --append-system-prompt-file ${identityPath}`;
|
|
9979
10246
|
legacyFallbackWarned = true;
|
|
9980
10247
|
}
|
|
9981
10248
|
const behaviorsFile = exportBehaviorsSync(
|
|
9982
10249
|
employeeName,
|
|
9983
|
-
|
|
10250
|
+
path20.basename(spawnCwd),
|
|
9984
10251
|
sessionName
|
|
9985
10252
|
);
|
|
9986
10253
|
if (behaviorsFile) {
|
|
@@ -9995,16 +10262,16 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
9995
10262
|
}
|
|
9996
10263
|
let sessionContextFlag = "";
|
|
9997
10264
|
try {
|
|
9998
|
-
const ctxDir =
|
|
10265
|
+
const ctxDir = path20.join(os12.homedir(), ".exe-os", "session-cache");
|
|
9999
10266
|
mkdirSync8(ctxDir, { recursive: true });
|
|
10000
|
-
const ctxFile =
|
|
10267
|
+
const ctxFile = path20.join(ctxDir, `session-context-${sessionName}.md`);
|
|
10001
10268
|
const ctxContent = [
|
|
10002
10269
|
`## Session Context`,
|
|
10003
10270
|
`You are running in tmux session: ${sessionName}.`,
|
|
10004
10271
|
`Your parent coordinator session is ${exeSession}.`,
|
|
10005
10272
|
`Your employees (if any) use the -${exeSession} suffix.`
|
|
10006
10273
|
].join("\n");
|
|
10007
|
-
|
|
10274
|
+
writeFileSync8(ctxFile, ctxContent);
|
|
10008
10275
|
sessionContextFlag = ` --append-system-prompt-file ${ctxFile}`;
|
|
10009
10276
|
} catch {
|
|
10010
10277
|
}
|
|
@@ -10081,8 +10348,8 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
10081
10348
|
transport.pipeLog(sessionName, logFile);
|
|
10082
10349
|
try {
|
|
10083
10350
|
const mySession = getMySession();
|
|
10084
|
-
const dispatchInfo =
|
|
10085
|
-
|
|
10351
|
+
const dispatchInfo = path20.join(SESSION_CACHE, `dispatch-info-${sessionName}.json`);
|
|
10352
|
+
writeFileSync8(dispatchInfo, JSON.stringify({
|
|
10086
10353
|
dispatchedBy: mySession,
|
|
10087
10354
|
rootExe: exeSession,
|
|
10088
10355
|
provider: useBinSymlink ? ccProvider : useExeAgent ? opts.provider : useCodex ? "openai" : useOpencode ? "opencode" : "anthropic",
|
|
@@ -10156,15 +10423,15 @@ var init_tmux_routing = __esm({
|
|
|
10156
10423
|
init_intercom_queue();
|
|
10157
10424
|
init_plan_limits();
|
|
10158
10425
|
init_employees();
|
|
10159
|
-
SPAWN_LOCK_DIR =
|
|
10160
|
-
SESSION_CACHE =
|
|
10426
|
+
SPAWN_LOCK_DIR = path20.join(os12.homedir(), ".exe-os", "spawn-locks");
|
|
10427
|
+
SESSION_CACHE = path20.join(os12.homedir(), ".exe-os", "session-cache");
|
|
10161
10428
|
BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
|
|
10162
10429
|
VALID_SESSION_NAME = /^[a-z]+\d*-[a-zA-Z0-9_]+$/;
|
|
10163
10430
|
VERIFY_PANE_LINES = 200;
|
|
10164
10431
|
INTERCOM_DEBOUNCE_MS = 3e4;
|
|
10165
10432
|
CODEX_DEBOUNCE_MS = 12e4;
|
|
10166
|
-
INTERCOM_LOG2 =
|
|
10167
|
-
DEBOUNCE_FILE =
|
|
10433
|
+
INTERCOM_LOG2 = path20.join(os12.homedir(), ".exe-os", "intercom.log");
|
|
10434
|
+
DEBOUNCE_FILE = path20.join(SESSION_CACHE, "intercom-debounce.json");
|
|
10168
10435
|
DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
|
|
10169
10436
|
BUSY_PATTERN = /[✻✽✶✳·].*…|Running…|• Working|• Ran |• Explored|• Called|esc to interrupt/;
|
|
10170
10437
|
}
|
|
@@ -10187,10 +10454,10 @@ __export(messaging_exports, {
|
|
|
10187
10454
|
sendMessage: () => sendMessage,
|
|
10188
10455
|
setWsClientSend: () => setWsClientSend
|
|
10189
10456
|
});
|
|
10190
|
-
import
|
|
10457
|
+
import crypto9 from "crypto";
|
|
10191
10458
|
function generateUlid() {
|
|
10192
10459
|
const timestamp = Date.now().toString(36).padStart(10, "0");
|
|
10193
|
-
const random =
|
|
10460
|
+
const random = crypto9.randomBytes(10).toString("hex").slice(0, 16);
|
|
10194
10461
|
return (timestamp + random).toUpperCase();
|
|
10195
10462
|
}
|
|
10196
10463
|
function rowToMessage(row) {
|
|
@@ -10201,6 +10468,7 @@ function rowToMessage(row) {
|
|
|
10201
10468
|
targetAgent: row.target_agent,
|
|
10202
10469
|
targetProject: row.target_project ?? null,
|
|
10203
10470
|
targetDevice: row.target_device,
|
|
10471
|
+
sessionScope: row.session_scope ?? null,
|
|
10204
10472
|
content: row.content,
|
|
10205
10473
|
priority: row.priority ?? "normal",
|
|
10206
10474
|
status: row.status ?? "pending",
|
|
@@ -10218,15 +10486,17 @@ async function sendMessage(input) {
|
|
|
10218
10486
|
const id = generateUlid();
|
|
10219
10487
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
10220
10488
|
const targetDevice = input.targetDevice ?? "local";
|
|
10489
|
+
const sessionScope = input.sessionScope === void 0 ? resolveExeSession() : input.sessionScope;
|
|
10221
10490
|
await client.execute({
|
|
10222
|
-
sql: `INSERT INTO messages (id, from_agent, from_device, target_agent, target_project, target_device, content, priority, status, created_at)
|
|
10223
|
-
VALUES (?, ?, 'local', ?, ?, ?, ?, ?, 'pending', ?)`,
|
|
10491
|
+
sql: `INSERT INTO messages (id, from_agent, from_device, target_agent, target_project, target_device, session_scope, content, priority, status, created_at)
|
|
10492
|
+
VALUES (?, ?, 'local', ?, ?, ?, ?, ?, ?, 'pending', ?)`,
|
|
10224
10493
|
args: [
|
|
10225
10494
|
id,
|
|
10226
10495
|
input.fromAgent,
|
|
10227
10496
|
input.targetAgent,
|
|
10228
10497
|
input.targetProject ?? null,
|
|
10229
10498
|
targetDevice,
|
|
10499
|
+
sessionScope,
|
|
10230
10500
|
input.content,
|
|
10231
10501
|
input.priority ?? "normal",
|
|
10232
10502
|
now
|
|
@@ -10240,9 +10510,10 @@ async function sendMessage(input) {
|
|
|
10240
10510
|
}
|
|
10241
10511
|
} catch {
|
|
10242
10512
|
}
|
|
10513
|
+
const sentScope = strictSessionScopeFilter(sessionScope);
|
|
10243
10514
|
const result = await client.execute({
|
|
10244
|
-
sql:
|
|
10245
|
-
args: [id]
|
|
10515
|
+
sql: `SELECT * FROM messages WHERE id = ?${sentScope.sql}`,
|
|
10516
|
+
args: [id, ...sentScope.args]
|
|
10246
10517
|
});
|
|
10247
10518
|
return rowToMessage(result.rows[0]);
|
|
10248
10519
|
}
|
|
@@ -10266,6 +10537,7 @@ async function deliverCrossMachineMessage(messageId, targetDevice) {
|
|
|
10266
10537
|
fromAgent: msg.fromAgent,
|
|
10267
10538
|
targetAgent: msg.targetAgent,
|
|
10268
10539
|
targetProject: msg.targetProject,
|
|
10540
|
+
sessionScope: msg.sessionScope,
|
|
10269
10541
|
content: msg.content,
|
|
10270
10542
|
priority: msg.priority,
|
|
10271
10543
|
createdAt: msg.createdAt
|
|
@@ -10309,7 +10581,7 @@ async function deliverLocalMessage(messageId) {
|
|
|
10309
10581
|
} catch {
|
|
10310
10582
|
const newRetryCount = msg.retryCount + 1;
|
|
10311
10583
|
if (newRetryCount >= MAX_RETRIES3) {
|
|
10312
|
-
await markFailed(messageId, "session unavailable after 10 retries");
|
|
10584
|
+
await markFailed(messageId, "session unavailable after 10 retries", msg.sessionScope);
|
|
10313
10585
|
} else {
|
|
10314
10586
|
await client.execute({
|
|
10315
10587
|
sql: "UPDATE messages SET retry_count = ? WHERE id = ?",
|
|
@@ -10319,85 +10591,101 @@ async function deliverLocalMessage(messageId) {
|
|
|
10319
10591
|
return false;
|
|
10320
10592
|
}
|
|
10321
10593
|
}
|
|
10322
|
-
async function getPendingMessages(targetAgent) {
|
|
10594
|
+
async function getPendingMessages(targetAgent, sessionScope) {
|
|
10323
10595
|
const client = getClient();
|
|
10596
|
+
const scope = strictSessionScopeFilter(sessionScope);
|
|
10324
10597
|
const result = await client.execute({
|
|
10325
10598
|
sql: `SELECT * FROM messages
|
|
10326
|
-
WHERE target_agent = ? AND status IN ('pending', 'delivered')
|
|
10599
|
+
WHERE target_agent = ? AND status IN ('pending', 'delivered')${scope.sql}
|
|
10327
10600
|
ORDER BY id`,
|
|
10328
|
-
args: [targetAgent]
|
|
10601
|
+
args: [targetAgent, ...scope.args]
|
|
10329
10602
|
});
|
|
10330
10603
|
return result.rows.map((row) => rowToMessage(row));
|
|
10331
10604
|
}
|
|
10332
|
-
async function markRead(messageId) {
|
|
10605
|
+
async function markRead(messageId, sessionScope) {
|
|
10333
10606
|
const client = getClient();
|
|
10607
|
+
const scope = strictSessionScopeFilter(sessionScope);
|
|
10334
10608
|
await client.execute({
|
|
10335
|
-
sql:
|
|
10336
|
-
|
|
10609
|
+
sql: `UPDATE messages SET status = 'read'
|
|
10610
|
+
WHERE id = ? AND status IN ('pending', 'delivered')${scope.sql}`,
|
|
10611
|
+
args: [messageId, ...scope.args]
|
|
10337
10612
|
});
|
|
10338
10613
|
}
|
|
10339
|
-
async function markAcknowledged(messageId) {
|
|
10614
|
+
async function markAcknowledged(messageId, sessionScope) {
|
|
10340
10615
|
const client = getClient();
|
|
10616
|
+
const scope = strictSessionScopeFilter(sessionScope);
|
|
10341
10617
|
await client.execute({
|
|
10342
|
-
sql:
|
|
10343
|
-
|
|
10618
|
+
sql: `UPDATE messages SET status = 'acknowledged', processed_at = ?
|
|
10619
|
+
WHERE id = ? AND status = 'read'${scope.sql}`,
|
|
10620
|
+
args: [(/* @__PURE__ */ new Date()).toISOString(), messageId, ...scope.args]
|
|
10344
10621
|
});
|
|
10345
10622
|
}
|
|
10346
|
-
async function markProcessed(messageId) {
|
|
10623
|
+
async function markProcessed(messageId, sessionScope) {
|
|
10347
10624
|
const client = getClient();
|
|
10625
|
+
const scope = strictSessionScopeFilter(sessionScope);
|
|
10348
10626
|
await client.execute({
|
|
10349
|
-
sql:
|
|
10350
|
-
|
|
10627
|
+
sql: `UPDATE messages SET status = 'processed', processed_at = ?
|
|
10628
|
+
WHERE id = ?${scope.sql}`,
|
|
10629
|
+
args: [(/* @__PURE__ */ new Date()).toISOString(), messageId, ...scope.args]
|
|
10351
10630
|
});
|
|
10352
10631
|
}
|
|
10353
|
-
async function getMessageStatus(messageId) {
|
|
10632
|
+
async function getMessageStatus(messageId, sessionScope) {
|
|
10354
10633
|
const client = getClient();
|
|
10634
|
+
const scope = strictSessionScopeFilter(sessionScope);
|
|
10355
10635
|
const result = await client.execute({
|
|
10356
|
-
sql:
|
|
10357
|
-
args: [messageId]
|
|
10636
|
+
sql: `SELECT status FROM messages WHERE id = ?${scope.sql}`,
|
|
10637
|
+
args: [messageId, ...scope.args]
|
|
10358
10638
|
});
|
|
10359
10639
|
return result.rows[0]?.status ?? null;
|
|
10360
10640
|
}
|
|
10361
|
-
async function getUnacknowledgedMessages(targetAgent) {
|
|
10641
|
+
async function getUnacknowledgedMessages(targetAgent, sessionScope) {
|
|
10362
10642
|
const client = getClient();
|
|
10643
|
+
const scope = strictSessionScopeFilter(sessionScope);
|
|
10363
10644
|
const result = await client.execute({
|
|
10364
10645
|
sql: `SELECT * FROM messages
|
|
10365
|
-
WHERE target_agent = ? AND status IN ('pending', 'delivered', 'read')
|
|
10646
|
+
WHERE target_agent = ? AND status IN ('pending', 'delivered', 'read')${scope.sql}
|
|
10366
10647
|
ORDER BY id`,
|
|
10367
|
-
args: [targetAgent]
|
|
10648
|
+
args: [targetAgent, ...scope.args]
|
|
10368
10649
|
});
|
|
10369
10650
|
return result.rows.map((row) => rowToMessage(row));
|
|
10370
10651
|
}
|
|
10371
|
-
async function getReadMessages(targetAgent) {
|
|
10652
|
+
async function getReadMessages(targetAgent, sessionScope) {
|
|
10372
10653
|
const client = getClient();
|
|
10654
|
+
const scope = strictSessionScopeFilter(sessionScope);
|
|
10373
10655
|
const result = await client.execute({
|
|
10374
|
-
sql:
|
|
10375
|
-
|
|
10656
|
+
sql: `SELECT * FROM messages
|
|
10657
|
+
WHERE target_agent = ? AND status = 'read'${scope.sql}
|
|
10658
|
+
ORDER BY id`,
|
|
10659
|
+
args: [targetAgent, ...scope.args]
|
|
10376
10660
|
});
|
|
10377
10661
|
return result.rows.map((row) => rowToMessage(row));
|
|
10378
10662
|
}
|
|
10379
|
-
async function markFailed(messageId, reason) {
|
|
10663
|
+
async function markFailed(messageId, reason, sessionScope) {
|
|
10380
10664
|
const client = getClient();
|
|
10665
|
+
const scope = strictSessionScopeFilter(sessionScope);
|
|
10381
10666
|
await client.execute({
|
|
10382
|
-
sql:
|
|
10383
|
-
|
|
10667
|
+
sql: `UPDATE messages SET status = 'failed', failed_at = ?, failure_reason = ?
|
|
10668
|
+
WHERE id = ?${scope.sql}`,
|
|
10669
|
+
args: [(/* @__PURE__ */ new Date()).toISOString(), reason, messageId, ...scope.args]
|
|
10384
10670
|
});
|
|
10385
10671
|
}
|
|
10386
|
-
async function getFailedMessages() {
|
|
10672
|
+
async function getFailedMessages(sessionScope) {
|
|
10387
10673
|
const client = getClient();
|
|
10674
|
+
const scope = strictSessionScopeFilter(sessionScope);
|
|
10388
10675
|
const result = await client.execute({
|
|
10389
|
-
sql:
|
|
10390
|
-
args: []
|
|
10676
|
+
sql: `SELECT * FROM messages WHERE status = 'failed'${scope.sql} ORDER BY created_at DESC`,
|
|
10677
|
+
args: [...scope.args]
|
|
10391
10678
|
});
|
|
10392
10679
|
return result.rows.map((row) => rowToMessage(row));
|
|
10393
10680
|
}
|
|
10394
|
-
async function retryPendingMessages() {
|
|
10681
|
+
async function retryPendingMessages(sessionScope) {
|
|
10395
10682
|
const client = getClient();
|
|
10683
|
+
const scope = strictSessionScopeFilter(sessionScope);
|
|
10396
10684
|
const result = await client.execute({
|
|
10397
10685
|
sql: `SELECT * FROM messages
|
|
10398
|
-
WHERE status = 'pending' AND retry_count <
|
|
10686
|
+
WHERE status = 'pending' AND retry_count < ?${scope.sql}
|
|
10399
10687
|
ORDER BY id`,
|
|
10400
|
-
args: [MAX_RETRIES3]
|
|
10688
|
+
args: [MAX_RETRIES3, ...scope.args]
|
|
10401
10689
|
});
|
|
10402
10690
|
let delivered = 0;
|
|
10403
10691
|
for (const row of result.rows) {
|
|
@@ -10416,16 +10704,17 @@ var init_messaging = __esm({
|
|
|
10416
10704
|
"use strict";
|
|
10417
10705
|
init_database();
|
|
10418
10706
|
init_tmux_routing();
|
|
10707
|
+
init_task_scope();
|
|
10419
10708
|
MAX_RETRIES3 = 10;
|
|
10420
10709
|
_wsClientSend = null;
|
|
10421
10710
|
}
|
|
10422
10711
|
});
|
|
10423
10712
|
|
|
10424
10713
|
// src/automation/trigger-engine.ts
|
|
10425
|
-
import { readFileSync as
|
|
10714
|
+
import { readFileSync as readFileSync14, writeFileSync as writeFileSync9, existsSync as existsSync17, mkdirSync as mkdirSync9 } from "fs";
|
|
10426
10715
|
import { randomUUID as randomUUID8 } from "crypto";
|
|
10427
|
-
import
|
|
10428
|
-
import
|
|
10716
|
+
import path21 from "path";
|
|
10717
|
+
import os13 from "os";
|
|
10429
10718
|
function substituteTemplate(template, record) {
|
|
10430
10719
|
return template.replace(
|
|
10431
10720
|
/\{\{(\w+(?:\.\w+)*)\}\}/g,
|
|
@@ -10478,9 +10767,9 @@ function evaluateConditions(conditions, record) {
|
|
|
10478
10767
|
return conditions.every((c) => evaluateCondition(c, record));
|
|
10479
10768
|
}
|
|
10480
10769
|
function loadTriggers(project) {
|
|
10481
|
-
if (!
|
|
10770
|
+
if (!existsSync17(TRIGGERS_PATH)) return [];
|
|
10482
10771
|
try {
|
|
10483
|
-
const raw =
|
|
10772
|
+
const raw = readFileSync14(TRIGGERS_PATH, "utf-8");
|
|
10484
10773
|
const all = JSON.parse(raw);
|
|
10485
10774
|
if (!Array.isArray(all)) return [];
|
|
10486
10775
|
if (project) {
|
|
@@ -10720,7 +11009,7 @@ var TRIGGERS_PATH, GRAPH_API_VERSION;
|
|
|
10720
11009
|
var init_trigger_engine = __esm({
|
|
10721
11010
|
"src/automation/trigger-engine.ts"() {
|
|
10722
11011
|
"use strict";
|
|
10723
|
-
TRIGGERS_PATH =
|
|
11012
|
+
TRIGGERS_PATH = path21.join(os13.homedir(), ".exe-os", "triggers.json");
|
|
10724
11013
|
GRAPH_API_VERSION = "v21.0";
|
|
10725
11014
|
}
|
|
10726
11015
|
});
|
|
@@ -10783,9 +11072,9 @@ var init_crm_webhook = __esm({
|
|
|
10783
11072
|
});
|
|
10784
11073
|
|
|
10785
11074
|
// src/bin/exe-gateway.ts
|
|
10786
|
-
import { existsSync as
|
|
10787
|
-
import
|
|
10788
|
-
import
|
|
11075
|
+
import { existsSync as existsSync18, readFileSync as readFileSync15 } from "fs";
|
|
11076
|
+
import path22 from "path";
|
|
11077
|
+
import os14 from "os";
|
|
10789
11078
|
|
|
10790
11079
|
// src/gateway/webhook-server.ts
|
|
10791
11080
|
import {
|
|
@@ -11027,11 +11316,11 @@ init_crm_bridge();
|
|
|
11027
11316
|
|
|
11028
11317
|
// src/lib/pipeline-router.ts
|
|
11029
11318
|
init_database();
|
|
11030
|
-
import
|
|
11319
|
+
import crypto3 from "crypto";
|
|
11031
11320
|
async function sinkConversationStore(msg, agentResponse, agentName) {
|
|
11032
11321
|
try {
|
|
11033
11322
|
const client = getClient();
|
|
11034
|
-
const id =
|
|
11323
|
+
const id = crypto3.randomUUID();
|
|
11035
11324
|
const mediaJson = msg.media ? JSON.stringify(msg.media) : null;
|
|
11036
11325
|
await client.execute({
|
|
11037
11326
|
sql: `INSERT INTO conversations
|
|
@@ -11081,7 +11370,7 @@ async function sinkMemory(msg, agentResponse, agentName) {
|
|
|
11081
11370
|
].filter(Boolean).join("\n");
|
|
11082
11371
|
const vector = await embed2(rawText);
|
|
11083
11372
|
await writeMemory2({
|
|
11084
|
-
id:
|
|
11373
|
+
id: crypto3.randomUUID(),
|
|
11085
11374
|
agent_id: agentName ?? "gateway",
|
|
11086
11375
|
agent_role: "gateway",
|
|
11087
11376
|
session_id: `gateway-${msg.platform}`,
|
|
@@ -11751,18 +12040,18 @@ var BotRegistry = class {
|
|
|
11751
12040
|
|
|
11752
12041
|
// src/bin/exe-gateway.ts
|
|
11753
12042
|
init_employees();
|
|
11754
|
-
var CONFIG_DIR =
|
|
11755
|
-
var CONFIG_PATH3 =
|
|
12043
|
+
var CONFIG_DIR = process.env.EXE_GATEWAY_HOME || path22.join(os14.homedir(), ".exe-os");
|
|
12044
|
+
var CONFIG_PATH3 = process.env.EXE_GATEWAY_CONFIG || path22.join(CONFIG_DIR, "gateway.json");
|
|
11756
12045
|
var DEFAULT_PORT = 3100;
|
|
11757
12046
|
function loadConfig2() {
|
|
11758
|
-
if (!
|
|
12047
|
+
if (!existsSync18(CONFIG_PATH3)) {
|
|
11759
12048
|
console.log(
|
|
11760
12049
|
`[exe-gateway] No config at ${CONFIG_PATH3} \u2014 using defaults (port ${DEFAULT_PORT})`
|
|
11761
12050
|
);
|
|
11762
12051
|
return {};
|
|
11763
12052
|
}
|
|
11764
12053
|
try {
|
|
11765
|
-
const raw =
|
|
12054
|
+
const raw = readFileSync15(CONFIG_PATH3, "utf-8");
|
|
11766
12055
|
return JSON.parse(raw);
|
|
11767
12056
|
} catch (err) {
|
|
11768
12057
|
console.error(
|