@askexenow/exe-os 0.9.113 → 0.9.115
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/agentic-ontology-backfill.js +36 -12
- package/dist/bin/agentic-reflection-backfill.js +36 -12
- package/dist/bin/agentic-semantic-label.js +36 -12
- package/dist/bin/backfill-conversations.js +36 -12
- package/dist/bin/backfill-responses.js +36 -12
- package/dist/bin/backfill-vectors.js +36 -12
- package/dist/bin/bulk-sync-postgres.js +36 -12
- package/dist/bin/cleanup-stale-review-tasks.js +470 -113
- package/dist/bin/cli.js +413 -62
- package/dist/bin/exe-agent.js +27 -0
- package/dist/bin/exe-assign.js +36 -12
- package/dist/bin/exe-boot.js +246 -54
- package/dist/bin/exe-call.js +8 -0
- package/dist/bin/exe-cloud.js +47 -12
- package/dist/bin/exe-dispatch.js +348 -53
- package/dist/bin/exe-doctor.js +51 -13
- package/dist/bin/exe-export-behaviors.js +37 -12
- package/dist/bin/exe-forget.js +36 -12
- package/dist/bin/exe-gateway.js +348 -53
- package/dist/bin/exe-heartbeat.js +471 -113
- package/dist/bin/exe-kill.js +36 -12
- package/dist/bin/exe-launch-agent.js +117 -18
- package/dist/bin/exe-new-employee.js +9 -1
- package/dist/bin/exe-pending-messages.js +452 -95
- package/dist/bin/exe-pending-notifications.js +452 -95
- package/dist/bin/exe-pending-reviews.js +452 -95
- package/dist/bin/exe-rename.js +36 -12
- package/dist/bin/exe-review.js +36 -12
- package/dist/bin/exe-search.js +37 -12
- package/dist/bin/exe-session-cleanup.js +348 -53
- package/dist/bin/exe-settings.js +12 -0
- package/dist/bin/exe-start-codex.js +46 -13
- package/dist/bin/exe-start-opencode.js +46 -13
- package/dist/bin/exe-status.js +460 -114
- package/dist/bin/exe-support.js +12 -0
- package/dist/bin/exe-team.js +36 -12
- package/dist/bin/git-sweep.js +348 -53
- package/dist/bin/graph-backfill.js +36 -12
- package/dist/bin/graph-export.js +36 -12
- package/dist/bin/install.js +9 -1
- package/dist/bin/intercom-check.js +255 -53
- package/dist/bin/scan-tasks.js +348 -53
- package/dist/bin/setup.js +74 -12
- package/dist/bin/shard-migrate.js +36 -12
- package/dist/gateway/index.js +348 -53
- package/dist/hooks/bug-report-worker.js +348 -53
- package/dist/hooks/codex-stop-task-finalizer.js +308 -37
- package/dist/hooks/commit-complete.js +348 -53
- package/dist/hooks/error-recall.js +37 -12
- package/dist/hooks/ingest.js +363 -54
- package/dist/hooks/instructions-loaded.js +36 -12
- package/dist/hooks/notification.js +36 -12
- package/dist/hooks/post-compact.js +426 -72
- package/dist/hooks/post-tool-combined.js +501 -146
- package/dist/hooks/pre-compact.js +348 -53
- package/dist/hooks/pre-tool-use.js +92 -13
- package/dist/hooks/prompt-submit.js +348 -53
- package/dist/hooks/session-end.js +158 -53
- package/dist/hooks/session-start.js +66 -13
- package/dist/hooks/stop.js +420 -72
- package/dist/hooks/subagent-stop.js +419 -72
- package/dist/hooks/summary-worker.js +442 -121
- package/dist/index.js +375 -53
- package/dist/lib/agent-config.js +8 -0
- package/dist/lib/cloud-sync.js +35 -12
- package/dist/lib/config.js +13 -0
- package/dist/lib/consolidation.js +9 -1
- package/dist/lib/embedder.js +13 -0
- package/dist/lib/employees.js +8 -0
- package/dist/lib/exe-daemon.js +524 -60
- package/dist/lib/hybrid-search.js +37 -12
- package/dist/lib/keychain.js +25 -13
- package/dist/lib/messaging.js +395 -74
- package/dist/lib/schedules.js +36 -12
- package/dist/lib/skill-learning.js +21 -0
- package/dist/lib/store.js +36 -12
- package/dist/lib/tasks.js +324 -41
- package/dist/lib/tmux-routing.js +324 -41
- package/dist/mcp/server.js +374 -54
- package/dist/mcp/tools/create-task.js +324 -41
- package/dist/mcp/tools/list-tasks.js +406 -57
- package/dist/mcp/tools/send-message.js +395 -74
- package/dist/mcp/tools/update-task.js +324 -41
- package/dist/runtime/index.js +375 -53
- package/dist/tui/App.js +377 -55
- package/package.json +1 -1
|
@@ -154,6 +154,17 @@ function normalizeOrchestration(raw) {
|
|
|
154
154
|
const userOrg = raw.orchestration ?? {};
|
|
155
155
|
raw.orchestration = { ...defaultOrg, ...userOrg };
|
|
156
156
|
}
|
|
157
|
+
function normalizeCloudEndpoint(raw) {
|
|
158
|
+
const cloud = raw.cloud;
|
|
159
|
+
if (!cloud?.endpoint) return;
|
|
160
|
+
const ep = String(cloud.endpoint);
|
|
161
|
+
if (ep === "https://askexe.com/cloud" || ep === "https://askexe.com/cloud/") {
|
|
162
|
+
cloud.endpoint = "https://cloud.askexe.com";
|
|
163
|
+
process.stderr.write(
|
|
164
|
+
"[config] Auto-migrated cloud endpoint: askexe.com/cloud \u2192 cloud.askexe.com\n"
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
157
168
|
async function loadConfig() {
|
|
158
169
|
const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
|
|
159
170
|
await ensurePrivateDir(dir);
|
|
@@ -179,6 +190,7 @@ async function loadConfig() {
|
|
|
179
190
|
normalizeSessionLifecycle(migratedCfg);
|
|
180
191
|
normalizeAutoUpdate(migratedCfg);
|
|
181
192
|
normalizeOrchestration(migratedCfg);
|
|
193
|
+
normalizeCloudEndpoint(migratedCfg);
|
|
182
194
|
const config = { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db"), ...migratedCfg };
|
|
183
195
|
if (config.dbPath.startsWith("~")) {
|
|
184
196
|
config.dbPath = config.dbPath.replace(/^~/, os.homedir());
|
|
@@ -207,6 +219,7 @@ function loadConfigSync() {
|
|
|
207
219
|
normalizeSessionLifecycle(migratedCfg);
|
|
208
220
|
normalizeAutoUpdate(migratedCfg);
|
|
209
221
|
normalizeOrchestration(migratedCfg);
|
|
222
|
+
normalizeCloudEndpoint(migratedCfg);
|
|
210
223
|
const config = { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db"), ...migratedCfg };
|
|
211
224
|
if (config.dbPath.startsWith("~")) {
|
|
212
225
|
config.dbPath = config.dbPath.replace(/^~/, os.homedir());
|
|
@@ -569,11 +582,176 @@ var init_db_retry = __esm({
|
|
|
569
582
|
}
|
|
570
583
|
});
|
|
571
584
|
|
|
585
|
+
// src/lib/runtime-table.ts
|
|
586
|
+
var RUNTIME_TABLE, DEFAULT_RUNTIME;
|
|
587
|
+
var init_runtime_table = __esm({
|
|
588
|
+
"src/lib/runtime-table.ts"() {
|
|
589
|
+
"use strict";
|
|
590
|
+
RUNTIME_TABLE = {
|
|
591
|
+
codex: {
|
|
592
|
+
binary: "codex",
|
|
593
|
+
launchMode: "interactive",
|
|
594
|
+
autoApproveFlag: "--dangerously-bypass-approvals-and-sandbox",
|
|
595
|
+
inlineFlag: "--no-alt-screen",
|
|
596
|
+
apiKeyEnv: "OPENAI_API_KEY",
|
|
597
|
+
defaultModel: "gpt-5.5"
|
|
598
|
+
},
|
|
599
|
+
opencode: {
|
|
600
|
+
binary: "opencode",
|
|
601
|
+
launchMode: "exec",
|
|
602
|
+
autoApproveFlag: "--dangerously-skip-permissions",
|
|
603
|
+
inlineFlag: "",
|
|
604
|
+
apiKeyEnv: "ANTHROPIC_API_KEY",
|
|
605
|
+
defaultModel: "anthropic/claude-sonnet-4-6"
|
|
606
|
+
}
|
|
607
|
+
};
|
|
608
|
+
DEFAULT_RUNTIME = "claude";
|
|
609
|
+
}
|
|
610
|
+
});
|
|
611
|
+
|
|
612
|
+
// src/lib/agent-config.ts
|
|
613
|
+
var agent_config_exports = {};
|
|
614
|
+
__export(agent_config_exports, {
|
|
615
|
+
AGENT_CONFIG_PATH: () => AGENT_CONFIG_PATH,
|
|
616
|
+
DEFAULT_MODELS: () => DEFAULT_MODELS,
|
|
617
|
+
KNOWN_RUNTIMES: () => KNOWN_RUNTIMES,
|
|
618
|
+
RUNTIME_LABELS: () => RUNTIME_LABELS,
|
|
619
|
+
clearAgentRuntime: () => clearAgentRuntime,
|
|
620
|
+
getAgentRuntime: () => getAgentRuntime,
|
|
621
|
+
loadAgentConfig: () => loadAgentConfig,
|
|
622
|
+
normalizeCcModelName: () => normalizeCcModelName,
|
|
623
|
+
saveAgentConfig: () => saveAgentConfig,
|
|
624
|
+
setAgentMcps: () => setAgentMcps,
|
|
625
|
+
setAgentRuntime: () => setAgentRuntime
|
|
626
|
+
});
|
|
627
|
+
import { readFileSync as readFileSync2, writeFileSync, existsSync as existsSync3 } from "fs";
|
|
628
|
+
import path2 from "path";
|
|
629
|
+
function loadAgentConfig() {
|
|
630
|
+
if (!existsSync3(AGENT_CONFIG_PATH)) return {};
|
|
631
|
+
try {
|
|
632
|
+
return JSON.parse(readFileSync2(AGENT_CONFIG_PATH, "utf-8"));
|
|
633
|
+
} catch {
|
|
634
|
+
return {};
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
function saveAgentConfig(config) {
|
|
638
|
+
const dir = path2.dirname(AGENT_CONFIG_PATH);
|
|
639
|
+
ensurePrivateDirSync(dir);
|
|
640
|
+
writeFileSync(AGENT_CONFIG_PATH, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
641
|
+
enforcePrivateFileSync(AGENT_CONFIG_PATH);
|
|
642
|
+
}
|
|
643
|
+
function getAgentRuntime(agentId) {
|
|
644
|
+
const config = loadAgentConfig();
|
|
645
|
+
const entry = config[agentId];
|
|
646
|
+
if (entry) return entry;
|
|
647
|
+
const orgDefault = config["default"];
|
|
648
|
+
if (orgDefault) return orgDefault;
|
|
649
|
+
return { runtime: DEFAULT_RUNTIME, model: DEFAULT_MODELS[DEFAULT_RUNTIME] };
|
|
650
|
+
}
|
|
651
|
+
function normalizeCcModelName(model) {
|
|
652
|
+
let ccModel = model.replace(/(\d+)\.(\d+)/g, "$1-$2");
|
|
653
|
+
if (/claude-(opus|sonnet)-4-[6-9]/.test(ccModel) && !ccModel.includes("[1m]")) {
|
|
654
|
+
ccModel += "[1m]";
|
|
655
|
+
}
|
|
656
|
+
return ccModel;
|
|
657
|
+
}
|
|
658
|
+
function setAgentRuntime(agentId, runtime, model, reasoning_effort, mcps) {
|
|
659
|
+
const knownModels = KNOWN_RUNTIMES[runtime];
|
|
660
|
+
if (!knownModels) {
|
|
661
|
+
return {
|
|
662
|
+
ok: false,
|
|
663
|
+
error: `Unknown runtime "${runtime}". Valid: ${Object.keys(KNOWN_RUNTIMES).join(", ")}`
|
|
664
|
+
};
|
|
665
|
+
}
|
|
666
|
+
if (!knownModels.includes(model)) {
|
|
667
|
+
return {
|
|
668
|
+
ok: false,
|
|
669
|
+
error: `Unknown model "${model}" for runtime "${runtime}". Valid: ${knownModels.join(", ")}`
|
|
670
|
+
};
|
|
671
|
+
}
|
|
672
|
+
const config = loadAgentConfig();
|
|
673
|
+
const existing = config[agentId];
|
|
674
|
+
const entry = { runtime, model };
|
|
675
|
+
if (reasoning_effort) entry.reasoning_effort = reasoning_effort;
|
|
676
|
+
if (mcps !== void 0) {
|
|
677
|
+
entry.mcps = mcps.includes("exe-os") ? mcps : ["exe-os", ...mcps];
|
|
678
|
+
} else if (existing?.mcps) {
|
|
679
|
+
entry.mcps = existing.mcps;
|
|
680
|
+
}
|
|
681
|
+
config[agentId] = entry;
|
|
682
|
+
saveAgentConfig(config);
|
|
683
|
+
return { ok: true };
|
|
684
|
+
}
|
|
685
|
+
function setAgentMcps(agentId, mcps) {
|
|
686
|
+
const config = loadAgentConfig();
|
|
687
|
+
const existing = config[agentId] ?? getAgentRuntime(agentId);
|
|
688
|
+
existing.mcps = mcps.includes("exe-os") ? mcps : ["exe-os", ...mcps];
|
|
689
|
+
config[agentId] = existing;
|
|
690
|
+
saveAgentConfig(config);
|
|
691
|
+
return { ok: true };
|
|
692
|
+
}
|
|
693
|
+
function clearAgentRuntime(agentId) {
|
|
694
|
+
const config = loadAgentConfig();
|
|
695
|
+
delete config[agentId];
|
|
696
|
+
saveAgentConfig(config);
|
|
697
|
+
}
|
|
698
|
+
var AGENT_CONFIG_PATH, KNOWN_RUNTIMES, RUNTIME_LABELS, DEFAULT_MODELS;
|
|
699
|
+
var init_agent_config = __esm({
|
|
700
|
+
"src/lib/agent-config.ts"() {
|
|
701
|
+
"use strict";
|
|
702
|
+
init_config();
|
|
703
|
+
init_runtime_table();
|
|
704
|
+
init_secure_files();
|
|
705
|
+
AGENT_CONFIG_PATH = path2.join(EXE_AI_DIR, "agent-config.json");
|
|
706
|
+
KNOWN_RUNTIMES = {
|
|
707
|
+
claude: ["claude-opus-4.6", "claude-opus-4", "claude-sonnet-4.6", "claude-sonnet-4", "claude-haiku-4.5"],
|
|
708
|
+
codex: ["gpt-5.4", "gpt-5.5", "gpt-5.3-codex-spark", "o3", "o4-mini"],
|
|
709
|
+
opencode: ["anthropic/claude-sonnet-4-6", "openai/gpt-5.4", "google/gemini-2.5-pro", "deepseek/deepseek-r3", "minimax/minimax-m2.5"]
|
|
710
|
+
};
|
|
711
|
+
RUNTIME_LABELS = {
|
|
712
|
+
claude: "Claude Code (Anthropic)",
|
|
713
|
+
codex: "Codex (OpenAI)",
|
|
714
|
+
opencode: "OpenCode (open source)"
|
|
715
|
+
};
|
|
716
|
+
DEFAULT_MODELS = {
|
|
717
|
+
claude: "claude-opus-4.6",
|
|
718
|
+
codex: RUNTIME_TABLE.codex?.defaultModel ?? "gpt-5.4",
|
|
719
|
+
opencode: RUNTIME_TABLE.opencode?.defaultModel ?? "anthropic/claude-sonnet-4-6"
|
|
720
|
+
};
|
|
721
|
+
}
|
|
722
|
+
});
|
|
723
|
+
|
|
572
724
|
// src/lib/employees.ts
|
|
725
|
+
var employees_exports = {};
|
|
726
|
+
__export(employees_exports, {
|
|
727
|
+
COORDINATOR_ROLE: () => COORDINATOR_ROLE,
|
|
728
|
+
DEFAULT_COORDINATOR_TEMPLATE_NAME: () => DEFAULT_COORDINATOR_TEMPLATE_NAME,
|
|
729
|
+
EMPLOYEES_PATH: () => EMPLOYEES_PATH,
|
|
730
|
+
addEmployee: () => addEmployee,
|
|
731
|
+
baseAgentName: () => baseAgentName,
|
|
732
|
+
canCoordinate: () => canCoordinate,
|
|
733
|
+
getCoordinatorEmployee: () => getCoordinatorEmployee,
|
|
734
|
+
getCoordinatorName: () => getCoordinatorName,
|
|
735
|
+
getEmployee: () => getEmployee,
|
|
736
|
+
getEmployeeByRole: () => getEmployeeByRole,
|
|
737
|
+
getEmployeeNamesByRole: () => getEmployeeNamesByRole,
|
|
738
|
+
hasRole: () => hasRole,
|
|
739
|
+
hireEmployee: () => hireEmployee,
|
|
740
|
+
isCoordinatorName: () => isCoordinatorName,
|
|
741
|
+
isCoordinatorRole: () => isCoordinatorRole,
|
|
742
|
+
isMultiInstance: () => isMultiInstance,
|
|
743
|
+
loadEmployees: () => loadEmployees,
|
|
744
|
+
loadEmployeesSync: () => loadEmployeesSync,
|
|
745
|
+
normalizeRole: () => normalizeRole,
|
|
746
|
+
normalizeRosterCase: () => normalizeRosterCase,
|
|
747
|
+
registerBinSymlinks: () => registerBinSymlinks,
|
|
748
|
+
saveEmployees: () => saveEmployees,
|
|
749
|
+
validateEmployeeName: () => validateEmployeeName
|
|
750
|
+
});
|
|
573
751
|
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
574
|
-
import { existsSync as
|
|
752
|
+
import { existsSync as existsSync4, symlinkSync, readlinkSync, readFileSync as readFileSync3, renameSync as renameSync2, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
|
|
575
753
|
import { execSync } from "child_process";
|
|
576
|
-
import
|
|
754
|
+
import path3 from "path";
|
|
577
755
|
import os2 from "os";
|
|
578
756
|
function normalizeRole(role) {
|
|
579
757
|
return (role ?? "").trim().toLowerCase();
|
|
@@ -587,10 +765,47 @@ function getCoordinatorEmployee(employees) {
|
|
|
587
765
|
function getCoordinatorName(employees = loadEmployeesSync()) {
|
|
588
766
|
return getCoordinatorEmployee(employees)?.name ?? DEFAULT_COORDINATOR_TEMPLATE_NAME;
|
|
589
767
|
}
|
|
768
|
+
function isCoordinatorName(agentName, employees = loadEmployeesSync()) {
|
|
769
|
+
if (!agentName) return false;
|
|
770
|
+
return agentName.toLowerCase() === getCoordinatorName(employees).toLowerCase();
|
|
771
|
+
}
|
|
772
|
+
function canCoordinate(agentName, agentRole, employees = loadEmployeesSync()) {
|
|
773
|
+
return agentName === "default" || isCoordinatorRole(agentRole) || isCoordinatorName(agentName, employees);
|
|
774
|
+
}
|
|
775
|
+
function validateEmployeeName(name) {
|
|
776
|
+
if (!name) {
|
|
777
|
+
return { valid: false, error: "Name is required" };
|
|
778
|
+
}
|
|
779
|
+
if (name.length > 32) {
|
|
780
|
+
return { valid: false, error: "Name must be 32 characters or fewer" };
|
|
781
|
+
}
|
|
782
|
+
if (!/^[a-z][a-z0-9]*$/.test(name)) {
|
|
783
|
+
return {
|
|
784
|
+
valid: false,
|
|
785
|
+
error: "Name must start with a letter and contain only lowercase alphanumeric characters"
|
|
786
|
+
};
|
|
787
|
+
}
|
|
788
|
+
return { valid: true };
|
|
789
|
+
}
|
|
790
|
+
async function loadEmployees(employeesPath = EMPLOYEES_PATH) {
|
|
791
|
+
if (!existsSync4(employeesPath)) {
|
|
792
|
+
return [];
|
|
793
|
+
}
|
|
794
|
+
const raw = await readFile2(employeesPath, "utf-8");
|
|
795
|
+
try {
|
|
796
|
+
return JSON.parse(raw);
|
|
797
|
+
} catch {
|
|
798
|
+
return [];
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
async function saveEmployees(employees, employeesPath = EMPLOYEES_PATH) {
|
|
802
|
+
await mkdir2(path3.dirname(employeesPath), { recursive: true });
|
|
803
|
+
await writeFile2(employeesPath, JSON.stringify(employees, null, 2) + "\n", "utf-8");
|
|
804
|
+
}
|
|
590
805
|
function loadEmployeesSync(employeesPath = EMPLOYEES_PATH) {
|
|
591
|
-
if (!
|
|
806
|
+
if (!existsSync4(employeesPath)) return [];
|
|
592
807
|
try {
|
|
593
|
-
return JSON.parse(
|
|
808
|
+
return JSON.parse(readFileSync3(employeesPath, "utf-8"));
|
|
594
809
|
} catch {
|
|
595
810
|
return [];
|
|
596
811
|
}
|
|
@@ -598,21 +813,174 @@ function loadEmployeesSync(employeesPath = EMPLOYEES_PATH) {
|
|
|
598
813
|
function getEmployee(employees, name) {
|
|
599
814
|
return employees.find((e) => e.name.toLowerCase() === name.toLowerCase());
|
|
600
815
|
}
|
|
601
|
-
|
|
816
|
+
function getEmployeeByRole(employees, role) {
|
|
817
|
+
const lower = role.toLowerCase();
|
|
818
|
+
return employees.find((e) => e.role.toLowerCase() === lower);
|
|
819
|
+
}
|
|
820
|
+
function getEmployeeNamesByRole(employees, role) {
|
|
821
|
+
const lower = role.toLowerCase();
|
|
822
|
+
return employees.filter((e) => e.role.toLowerCase() === lower).map((e) => e.name);
|
|
823
|
+
}
|
|
824
|
+
function hasRole(agentName, role) {
|
|
825
|
+
const employees = loadEmployeesSync();
|
|
826
|
+
const emp = getEmployee(employees, agentName);
|
|
827
|
+
return emp ? emp.role.toLowerCase() === role.toLowerCase() : false;
|
|
828
|
+
}
|
|
829
|
+
function baseAgentName(name, employees) {
|
|
830
|
+
const match = name.match(/^([a-zA-Z]+)\d+$/);
|
|
831
|
+
if (!match) return name;
|
|
832
|
+
const base = match[1];
|
|
833
|
+
const roster = employees ?? loadEmployeesSync();
|
|
834
|
+
if (getEmployee(roster, base)) return base;
|
|
835
|
+
return name;
|
|
836
|
+
}
|
|
837
|
+
function isMultiInstance(agentName, employees) {
|
|
838
|
+
const roster = employees ?? loadEmployeesSync();
|
|
839
|
+
const emp = getEmployee(roster, agentName);
|
|
840
|
+
if (!emp) return false;
|
|
841
|
+
return MULTI_INSTANCE_ROLES.has(emp.role.toLowerCase());
|
|
842
|
+
}
|
|
843
|
+
function addEmployee(employees, employee) {
|
|
844
|
+
const { systemPrompt: _legacyPrompt, ...rest } = employee;
|
|
845
|
+
const normalized = { ...rest, name: employee.name.toLowerCase() };
|
|
846
|
+
if (employees.some((e) => e.name.toLowerCase() === normalized.name)) {
|
|
847
|
+
throw new Error(`Employee '${normalized.name}' already exists`);
|
|
848
|
+
}
|
|
849
|
+
return [...employees, normalized];
|
|
850
|
+
}
|
|
851
|
+
function appendToCoordinatorTeam(employee) {
|
|
852
|
+
const coordinator = getCoordinatorEmployee(loadEmployeesSync());
|
|
853
|
+
if (!coordinator) return;
|
|
854
|
+
const idPath = path3.join(IDENTITY_DIR, `${coordinator.name}.md`);
|
|
855
|
+
if (!existsSync4(idPath)) return;
|
|
856
|
+
const content = readFileSync3(idPath, "utf-8");
|
|
857
|
+
if (content.includes(`**${capitalize(employee.name)}`)) return;
|
|
858
|
+
const teamMatch = content.match(TEAM_SECTION_RE);
|
|
859
|
+
if (!teamMatch || teamMatch.index === void 0) return;
|
|
860
|
+
const afterTeam = content.slice(teamMatch.index + teamMatch[0].length);
|
|
861
|
+
const nextHeading = afterTeam.match(/\n## /);
|
|
862
|
+
const entry = `
|
|
863
|
+
**${capitalize(employee.name)} (${employee.role}):** Newly hired. Update this description as the role develops.
|
|
864
|
+
`;
|
|
865
|
+
let updated;
|
|
866
|
+
if (nextHeading && nextHeading.index !== void 0) {
|
|
867
|
+
const insertAt = teamMatch.index + teamMatch[0].length + nextHeading.index;
|
|
868
|
+
updated = content.slice(0, insertAt) + entry + content.slice(insertAt);
|
|
869
|
+
} else {
|
|
870
|
+
updated = content.trimEnd() + "\n" + entry;
|
|
871
|
+
}
|
|
872
|
+
writeFileSync2(idPath, updated, "utf-8");
|
|
873
|
+
}
|
|
874
|
+
function capitalize(s) {
|
|
875
|
+
return s.charAt(0).toUpperCase() + s.slice(1);
|
|
876
|
+
}
|
|
877
|
+
async function hireEmployee(employee) {
|
|
878
|
+
const employees = await loadEmployees();
|
|
879
|
+
const updated = addEmployee(employees, employee);
|
|
880
|
+
await saveEmployees(updated);
|
|
881
|
+
try {
|
|
882
|
+
appendToCoordinatorTeam(employee);
|
|
883
|
+
} catch {
|
|
884
|
+
}
|
|
885
|
+
try {
|
|
886
|
+
const { loadAgentConfig: loadAgentConfig2, saveAgentConfig: saveAgentConfig2 } = await Promise.resolve().then(() => (init_agent_config(), agent_config_exports));
|
|
887
|
+
const config = loadAgentConfig2();
|
|
888
|
+
const name = employee.name.toLowerCase();
|
|
889
|
+
if (!config[name] && config["default"]) {
|
|
890
|
+
config[name] = { ...config["default"] };
|
|
891
|
+
saveAgentConfig2(config);
|
|
892
|
+
}
|
|
893
|
+
} catch {
|
|
894
|
+
}
|
|
895
|
+
return updated;
|
|
896
|
+
}
|
|
897
|
+
async function normalizeRosterCase(rosterPath) {
|
|
898
|
+
const employees = await loadEmployees(rosterPath);
|
|
899
|
+
let changed = false;
|
|
900
|
+
for (const emp of employees) {
|
|
901
|
+
if (emp.name !== emp.name.toLowerCase()) {
|
|
902
|
+
const oldName = emp.name;
|
|
903
|
+
emp.name = emp.name.toLowerCase();
|
|
904
|
+
changed = true;
|
|
905
|
+
try {
|
|
906
|
+
const identityDir = path3.join(os2.homedir(), ".exe-os", "identity");
|
|
907
|
+
const oldPath = path3.join(identityDir, `${oldName}.md`);
|
|
908
|
+
const newPath = path3.join(identityDir, `${emp.name}.md`);
|
|
909
|
+
if (existsSync4(oldPath) && !existsSync4(newPath)) {
|
|
910
|
+
renameSync2(oldPath, newPath);
|
|
911
|
+
} else if (existsSync4(oldPath) && oldPath !== newPath) {
|
|
912
|
+
const content = readFileSync3(oldPath, "utf-8");
|
|
913
|
+
writeFileSync2(newPath, content, "utf-8");
|
|
914
|
+
if (oldPath.toLowerCase() !== newPath.toLowerCase()) {
|
|
915
|
+
unlinkSync(oldPath);
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
} catch {
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
if (changed) {
|
|
923
|
+
await saveEmployees(employees, rosterPath);
|
|
924
|
+
}
|
|
925
|
+
return changed;
|
|
926
|
+
}
|
|
927
|
+
function findExeBin() {
|
|
928
|
+
try {
|
|
929
|
+
return execSync(process.platform === "win32" ? "where exe-os" : "which exe-os", { encoding: "utf8" }).trim();
|
|
930
|
+
} catch {
|
|
931
|
+
return null;
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
function registerBinSymlinks(name) {
|
|
935
|
+
const created = [];
|
|
936
|
+
const skipped = [];
|
|
937
|
+
const errors = [];
|
|
938
|
+
const exeBinPath = findExeBin();
|
|
939
|
+
if (!exeBinPath) {
|
|
940
|
+
errors.push("Could not find 'exe-os' in PATH");
|
|
941
|
+
return { created, skipped, errors };
|
|
942
|
+
}
|
|
943
|
+
const binDir = path3.dirname(exeBinPath);
|
|
944
|
+
let target;
|
|
945
|
+
try {
|
|
946
|
+
target = readlinkSync(exeBinPath);
|
|
947
|
+
} catch {
|
|
948
|
+
errors.push("Could not read 'exe' symlink");
|
|
949
|
+
return { created, skipped, errors };
|
|
950
|
+
}
|
|
951
|
+
for (const suffix of ["", "-opencode"]) {
|
|
952
|
+
const linkName = `${name}${suffix}`;
|
|
953
|
+
const linkPath = path3.join(binDir, linkName);
|
|
954
|
+
if (existsSync4(linkPath)) {
|
|
955
|
+
skipped.push(linkName);
|
|
956
|
+
continue;
|
|
957
|
+
}
|
|
958
|
+
try {
|
|
959
|
+
symlinkSync(target, linkPath);
|
|
960
|
+
created.push(linkName);
|
|
961
|
+
} catch (err) {
|
|
962
|
+
errors.push(`${linkName}: ${err instanceof Error ? err.message : String(err)}`);
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
return { created, skipped, errors };
|
|
966
|
+
}
|
|
967
|
+
var EMPLOYEES_PATH, DEFAULT_COORDINATOR_TEMPLATE_NAME, COORDINATOR_ROLE, MULTI_INSTANCE_ROLES, IDENTITY_DIR, TEAM_SECTION_RE;
|
|
602
968
|
var init_employees = __esm({
|
|
603
969
|
"src/lib/employees.ts"() {
|
|
604
970
|
"use strict";
|
|
605
971
|
init_config();
|
|
606
|
-
EMPLOYEES_PATH =
|
|
972
|
+
EMPLOYEES_PATH = path3.join(EXE_AI_DIR, "exe-employees.json");
|
|
607
973
|
DEFAULT_COORDINATOR_TEMPLATE_NAME = "exe";
|
|
608
974
|
COORDINATOR_ROLE = "COO";
|
|
609
|
-
|
|
975
|
+
MULTI_INSTANCE_ROLES = /* @__PURE__ */ new Set(["principal engineer", "content production specialist", "staff code reviewer"]);
|
|
976
|
+
IDENTITY_DIR = path3.join(EXE_AI_DIR, "identity");
|
|
977
|
+
TEAM_SECTION_RE = /^## Team\b.*$/m;
|
|
610
978
|
}
|
|
611
979
|
});
|
|
612
980
|
|
|
613
981
|
// src/lib/database-adapter.ts
|
|
614
982
|
import os3 from "os";
|
|
615
|
-
import
|
|
983
|
+
import path4 from "path";
|
|
616
984
|
import { createRequire } from "module";
|
|
617
985
|
import { pathToFileURL } from "url";
|
|
618
986
|
function quotedIdentifier(identifier) {
|
|
@@ -923,8 +1291,8 @@ async function loadPrismaClient() {
|
|
|
923
1291
|
}
|
|
924
1292
|
return new PrismaClient2();
|
|
925
1293
|
}
|
|
926
|
-
const exeDbRoot = process.env.EXE_DB_ROOT ??
|
|
927
|
-
const requireFromExeDb = createRequire(
|
|
1294
|
+
const exeDbRoot = process.env.EXE_DB_ROOT ?? path4.join(os3.homedir(), "exe-db");
|
|
1295
|
+
const requireFromExeDb = createRequire(path4.join(exeDbRoot, "package.json"));
|
|
928
1296
|
const prismaEntry = requireFromExeDb.resolve("@prisma/client");
|
|
929
1297
|
const module = await import(pathToFileURL(prismaEntry).href);
|
|
930
1298
|
const PrismaClient = module.PrismaClient ?? module.default?.PrismaClient;
|
|
@@ -1196,8 +1564,8 @@ var init_database_adapter = __esm({
|
|
|
1196
1564
|
|
|
1197
1565
|
// src/lib/daemon-auth.ts
|
|
1198
1566
|
import crypto2 from "crypto";
|
|
1199
|
-
import
|
|
1200
|
-
import { existsSync as
|
|
1567
|
+
import path5 from "path";
|
|
1568
|
+
import { existsSync as existsSync5, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "fs";
|
|
1201
1569
|
function normalizeToken(token) {
|
|
1202
1570
|
if (!token) return null;
|
|
1203
1571
|
const trimmed = token.trim();
|
|
@@ -1205,8 +1573,8 @@ function normalizeToken(token) {
|
|
|
1205
1573
|
}
|
|
1206
1574
|
function readDaemonToken() {
|
|
1207
1575
|
try {
|
|
1208
|
-
if (!
|
|
1209
|
-
return normalizeToken(
|
|
1576
|
+
if (!existsSync5(DAEMON_TOKEN_PATH)) return null;
|
|
1577
|
+
return normalizeToken(readFileSync4(DAEMON_TOKEN_PATH, "utf8"));
|
|
1210
1578
|
} catch {
|
|
1211
1579
|
return null;
|
|
1212
1580
|
}
|
|
@@ -1216,7 +1584,7 @@ function ensureDaemonToken(seed) {
|
|
|
1216
1584
|
if (existing) return existing;
|
|
1217
1585
|
const token = normalizeToken(seed) ?? crypto2.randomBytes(32).toString("hex");
|
|
1218
1586
|
ensurePrivateDirSync(EXE_AI_DIR);
|
|
1219
|
-
|
|
1587
|
+
writeFileSync3(DAEMON_TOKEN_PATH, `${token}
|
|
1220
1588
|
`, "utf8");
|
|
1221
1589
|
enforcePrivateFileSync(DAEMON_TOKEN_PATH);
|
|
1222
1590
|
return token;
|
|
@@ -1227,7 +1595,7 @@ var init_daemon_auth = __esm({
|
|
|
1227
1595
|
"use strict";
|
|
1228
1596
|
init_config();
|
|
1229
1597
|
init_secure_files();
|
|
1230
|
-
DAEMON_TOKEN_PATH =
|
|
1598
|
+
DAEMON_TOKEN_PATH = path5.join(EXE_AI_DIR, "exed.token");
|
|
1231
1599
|
}
|
|
1232
1600
|
});
|
|
1233
1601
|
|
|
@@ -1247,8 +1615,8 @@ import net from "net";
|
|
|
1247
1615
|
import os4 from "os";
|
|
1248
1616
|
import { spawn, execSync as execSync2 } from "child_process";
|
|
1249
1617
|
import { randomUUID } from "crypto";
|
|
1250
|
-
import { existsSync as
|
|
1251
|
-
import
|
|
1618
|
+
import { existsSync as existsSync6, unlinkSync as unlinkSync2, readFileSync as readFileSync5, openSync, closeSync, statSync } from "fs";
|
|
1619
|
+
import path6 from "path";
|
|
1252
1620
|
import { fileURLToPath } from "url";
|
|
1253
1621
|
function handleData(chunk) {
|
|
1254
1622
|
_buffer += chunk.toString();
|
|
@@ -1284,9 +1652,9 @@ function isZombie(pid) {
|
|
|
1284
1652
|
}
|
|
1285
1653
|
}
|
|
1286
1654
|
function cleanupStaleFiles() {
|
|
1287
|
-
if (
|
|
1655
|
+
if (existsSync6(PID_PATH)) {
|
|
1288
1656
|
try {
|
|
1289
|
-
const pid = parseInt(
|
|
1657
|
+
const pid = parseInt(readFileSync5(PID_PATH, "utf8").trim(), 10);
|
|
1290
1658
|
if (pid > 0) {
|
|
1291
1659
|
try {
|
|
1292
1660
|
process.kill(pid, 0);
|
|
@@ -1311,11 +1679,11 @@ function cleanupStaleFiles() {
|
|
|
1311
1679
|
}
|
|
1312
1680
|
}
|
|
1313
1681
|
function findPackageRoot() {
|
|
1314
|
-
let dir =
|
|
1315
|
-
const { root } =
|
|
1682
|
+
let dir = path6.dirname(fileURLToPath(import.meta.url));
|
|
1683
|
+
const { root } = path6.parse(dir);
|
|
1316
1684
|
while (dir !== root) {
|
|
1317
|
-
if (
|
|
1318
|
-
dir =
|
|
1685
|
+
if (existsSync6(path6.join(dir, "package.json"))) return dir;
|
|
1686
|
+
dir = path6.dirname(dir);
|
|
1319
1687
|
}
|
|
1320
1688
|
return null;
|
|
1321
1689
|
}
|
|
@@ -1333,8 +1701,8 @@ function spawnDaemon() {
|
|
|
1333
1701
|
process.stderr.write("[exed-client] WARN: cannot find package root\n");
|
|
1334
1702
|
return;
|
|
1335
1703
|
}
|
|
1336
|
-
const daemonPath =
|
|
1337
|
-
if (!
|
|
1704
|
+
const daemonPath = path6.join(pkgRoot, "dist", "lib", "exe-daemon.js");
|
|
1705
|
+
if (!existsSync6(daemonPath)) {
|
|
1338
1706
|
process.stderr.write(`[exed-client] WARN: daemon script not found at ${daemonPath}
|
|
1339
1707
|
`);
|
|
1340
1708
|
return;
|
|
@@ -1343,7 +1711,7 @@ function spawnDaemon() {
|
|
|
1343
1711
|
const daemonToken = ensureDaemonToken(process.env[DAEMON_TOKEN_ENV] ?? null);
|
|
1344
1712
|
process.stderr.write(`[exed-client] Spawning daemon: ${resolvedPath}
|
|
1345
1713
|
`);
|
|
1346
|
-
const logPath =
|
|
1714
|
+
const logPath = path6.join(path6.dirname(SOCKET_PATH), "exed.log");
|
|
1347
1715
|
let stderrFd = "ignore";
|
|
1348
1716
|
try {
|
|
1349
1717
|
stderrFd = openSync(logPath, "a");
|
|
@@ -1508,9 +1876,9 @@ function killAndRespawnDaemon() {
|
|
|
1508
1876
|
}
|
|
1509
1877
|
try {
|
|
1510
1878
|
process.stderr.write("[exed-client] Killing daemon for restart...\n");
|
|
1511
|
-
if (
|
|
1879
|
+
if (existsSync6(PID_PATH)) {
|
|
1512
1880
|
try {
|
|
1513
|
-
const pid = parseInt(
|
|
1881
|
+
const pid = parseInt(readFileSync5(PID_PATH, "utf8").trim(), 10);
|
|
1514
1882
|
if (pid > 0) {
|
|
1515
1883
|
try {
|
|
1516
1884
|
process.kill(pid, "SIGKILL");
|
|
@@ -1656,9 +2024,9 @@ var init_exe_daemon_client = __esm({
|
|
|
1656
2024
|
"use strict";
|
|
1657
2025
|
init_config();
|
|
1658
2026
|
init_daemon_auth();
|
|
1659
|
-
SOCKET_PATH = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ??
|
|
1660
|
-
PID_PATH = process.env.EXE_DAEMON_PID ?? process.env.EXE_EMBED_PID ??
|
|
1661
|
-
SPAWN_LOCK_PATH =
|
|
2027
|
+
SOCKET_PATH = process.env.EXE_DAEMON_SOCK ?? process.env.EXE_EMBED_SOCK ?? path6.join(EXE_AI_DIR, "exed.sock");
|
|
2028
|
+
PID_PATH = process.env.EXE_DAEMON_PID ?? process.env.EXE_EMBED_PID ?? path6.join(EXE_AI_DIR, "exed.pid");
|
|
2029
|
+
SPAWN_LOCK_PATH = path6.join(EXE_AI_DIR, "exed-spawn.lock");
|
|
1662
2030
|
SPAWN_LOCK_STALE_MS = 3e4;
|
|
1663
2031
|
CONNECT_TIMEOUT_MS = 15e3;
|
|
1664
2032
|
REQUEST_TIMEOUT_MS = 3e4;
|
|
@@ -1926,7 +2294,7 @@ __export(database_exports, {
|
|
|
1926
2294
|
isInitialized: () => isInitialized,
|
|
1927
2295
|
setExternalClient: () => setExternalClient
|
|
1928
2296
|
});
|
|
1929
|
-
import { chmodSync as chmodSync2, existsSync as
|
|
2297
|
+
import { chmodSync as chmodSync2, existsSync as existsSync7, statSync as statSync2, copyFileSync, unlinkSync as unlinkSync3, openSync as openSync2, closeSync as closeSync2, mkdirSync as mkdirSync2 } from "fs";
|
|
1930
2298
|
import { createClient } from "@libsql/client";
|
|
1931
2299
|
import { homedir } from "os";
|
|
1932
2300
|
import { join } from "path";
|
|
@@ -1979,11 +2347,11 @@ function releaseDbLock() {
|
|
|
1979
2347
|
}
|
|
1980
2348
|
async function initDatabase(config) {
|
|
1981
2349
|
acquireDbLock();
|
|
1982
|
-
if (
|
|
2350
|
+
if (existsSync7(config.dbPath)) {
|
|
1983
2351
|
const dbStat = statSync2(config.dbPath);
|
|
1984
2352
|
if (dbStat.size === 0) {
|
|
1985
2353
|
const walPath = config.dbPath + "-wal";
|
|
1986
|
-
if (
|
|
2354
|
+
if (existsSync7(walPath) && statSync2(walPath).size > 0) {
|
|
1987
2355
|
const backupPath = config.dbPath + ".zeroed-" + Date.now();
|
|
1988
2356
|
copyFileSync(config.dbPath, backupPath);
|
|
1989
2357
|
unlinkSync3(config.dbPath);
|
|
@@ -3569,16 +3937,16 @@ var init_database = __esm({
|
|
|
3569
3937
|
});
|
|
3570
3938
|
|
|
3571
3939
|
// src/lib/keychain.ts
|
|
3572
|
-
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
|
|
3573
|
-
import { existsSync as
|
|
3940
|
+
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2, rename, copyFile } from "fs/promises";
|
|
3941
|
+
import { existsSync as existsSync8, statSync as statSync3 } from "fs";
|
|
3574
3942
|
import { execSync as execSync3 } from "child_process";
|
|
3575
|
-
import
|
|
3943
|
+
import path7 from "path";
|
|
3576
3944
|
import os5 from "os";
|
|
3577
3945
|
function getKeyDir() {
|
|
3578
|
-
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ??
|
|
3946
|
+
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path7.join(os5.homedir(), ".exe-os");
|
|
3579
3947
|
}
|
|
3580
3948
|
function getKeyPath() {
|
|
3581
|
-
return
|
|
3949
|
+
return path7.join(getKeyDir(), "master.key");
|
|
3582
3950
|
}
|
|
3583
3951
|
function nativeKeychainAllowed() {
|
|
3584
3952
|
return process.env.EXE_OS_DISABLE_NATIVE_KEYCHAIN !== "1";
|
|
@@ -3604,12 +3972,14 @@ function linuxSecretAvailable() {
|
|
|
3604
3972
|
function isRootOnlyTrustedServerKeyFile(keyPath) {
|
|
3605
3973
|
if (process.platform !== "linux") return false;
|
|
3606
3974
|
try {
|
|
3607
|
-
const uid = typeof os5.userInfo().uid === "number" ? os5.userInfo().uid : -1;
|
|
3608
3975
|
const st = statSync3(keyPath);
|
|
3609
3976
|
if (!st.isFile() || (st.mode & 63) !== 0) return false;
|
|
3977
|
+
const uid = typeof os5.userInfo().uid === "number" ? os5.userInfo().uid : -1;
|
|
3610
3978
|
if (uid === 0) return true;
|
|
3611
3979
|
const exeOsDir = process.env.EXE_OS_DIR;
|
|
3612
|
-
|
|
3980
|
+
if (exeOsDir && path7.resolve(keyPath).startsWith(path7.resolve(exeOsDir) + path7.sep)) return true;
|
|
3981
|
+
if (!linuxSecretAvailable()) return true;
|
|
3982
|
+
return false;
|
|
3613
3983
|
} catch {
|
|
3614
3984
|
return false;
|
|
3615
3985
|
}
|
|
@@ -3759,15 +4129,25 @@ async function writeMachineBoundFileFallback(b64) {
|
|
|
3759
4129
|
await mkdir3(dir, { recursive: true });
|
|
3760
4130
|
const keyPath = getKeyPath();
|
|
3761
4131
|
const machineKey = deriveMachineKey();
|
|
3762
|
-
|
|
3763
|
-
|
|
3764
|
-
|
|
3765
|
-
|
|
3766
|
-
|
|
4132
|
+
const content = machineKey ? encryptWithMachineKey(b64, machineKey) + "\n" : b64 + "\n";
|
|
4133
|
+
const result = machineKey ? "encrypted" : "plaintext";
|
|
4134
|
+
const tmpPath = keyPath + ".tmp";
|
|
4135
|
+
try {
|
|
4136
|
+
if (existsSync8(keyPath)) {
|
|
4137
|
+
await copyFile(keyPath, keyPath + ".bak").catch(() => {
|
|
4138
|
+
});
|
|
4139
|
+
}
|
|
4140
|
+
await writeFile3(tmpPath, content, "utf-8");
|
|
4141
|
+
await chmod2(tmpPath, 384);
|
|
4142
|
+
await rename(tmpPath, keyPath);
|
|
4143
|
+
} catch (err) {
|
|
4144
|
+
try {
|
|
4145
|
+
await unlink(tmpPath);
|
|
4146
|
+
} catch {
|
|
4147
|
+
}
|
|
4148
|
+
throw err;
|
|
3767
4149
|
}
|
|
3768
|
-
|
|
3769
|
-
await chmod2(keyPath, 384);
|
|
3770
|
-
return "plaintext";
|
|
4150
|
+
return result;
|
|
3771
4151
|
}
|
|
3772
4152
|
async function getMasterKey() {
|
|
3773
4153
|
let nativeValue = macKeychainGet() ?? linuxSecretGet();
|
|
@@ -3806,7 +4186,7 @@ async function getMasterKey() {
|
|
|
3806
4186
|
}
|
|
3807
4187
|
}
|
|
3808
4188
|
const keyPath = getKeyPath();
|
|
3809
|
-
if (!
|
|
4189
|
+
if (!existsSync8(keyPath)) {
|
|
3810
4190
|
process.stderr.write(
|
|
3811
4191
|
`[keychain] Key not found at ${keyPath} (HOME=${os5.homedir()}, EXE_OS_DIR=${process.env.EXE_OS_DIR ?? "unset"})
|
|
3812
4192
|
`
|
|
@@ -3834,7 +4214,7 @@ async function getMasterKey() {
|
|
|
3834
4214
|
b64Value = content;
|
|
3835
4215
|
}
|
|
3836
4216
|
const key = Buffer.from(b64Value, "base64");
|
|
3837
|
-
if (
|
|
4217
|
+
if (isRootOnlyTrustedServerKeyFile(keyPath)) {
|
|
3838
4218
|
return key;
|
|
3839
4219
|
}
|
|
3840
4220
|
const migrated = macKeychainSet(b64Value) || linuxSecretSet(b64Value);
|
|
@@ -4140,14 +4520,14 @@ __export(shard_manager_exports, {
|
|
|
4140
4520
|
listShards: () => listShards,
|
|
4141
4521
|
shardExists: () => shardExists
|
|
4142
4522
|
});
|
|
4143
|
-
import
|
|
4144
|
-
import { existsSync as
|
|
4523
|
+
import path8 from "path";
|
|
4524
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync3, readdirSync, renameSync as renameSync3, statSync as statSync4 } from "fs";
|
|
4145
4525
|
import { createClient as createClient2 } from "@libsql/client";
|
|
4146
4526
|
function initShardManager(encryptionKey) {
|
|
4147
4527
|
_encryptionKey = encryptionKey;
|
|
4148
4528
|
_keyValidated = false;
|
|
4149
4529
|
_keyValidationPromise = null;
|
|
4150
|
-
if (!
|
|
4530
|
+
if (!existsSync9(SHARDS_DIR)) {
|
|
4151
4531
|
mkdirSync3(SHARDS_DIR, { recursive: true });
|
|
4152
4532
|
}
|
|
4153
4533
|
const existingShards = readdirSync(SHARDS_DIR).filter((f) => f.endsWith(".db"));
|
|
@@ -4168,7 +4548,7 @@ async function validateEncryptionKey() {
|
|
|
4168
4548
|
return true;
|
|
4169
4549
|
}
|
|
4170
4550
|
for (const shardFile of existingShards.slice(0, 3)) {
|
|
4171
|
-
const dbPath =
|
|
4551
|
+
const dbPath = path8.join(SHARDS_DIR, shardFile);
|
|
4172
4552
|
const testClient = createClient2({ url: `file:${dbPath}`, encryptionKey: _encryptionKey });
|
|
4173
4553
|
try {
|
|
4174
4554
|
await testClient.execute("SELECT COUNT(*) FROM sqlite_schema");
|
|
@@ -4211,7 +4591,7 @@ function getShardClient(projectName) {
|
|
|
4211
4591
|
while (_shards.size >= MAX_OPEN_SHARDS) {
|
|
4212
4592
|
evictLRU();
|
|
4213
4593
|
}
|
|
4214
|
-
const dbPath =
|
|
4594
|
+
const dbPath = path8.join(SHARDS_DIR, `${safeName}.db`);
|
|
4215
4595
|
const client = createClient2({
|
|
4216
4596
|
url: `file:${dbPath}`,
|
|
4217
4597
|
encryptionKey: _encryptionKey
|
|
@@ -4222,13 +4602,13 @@ function getShardClient(projectName) {
|
|
|
4222
4602
|
}
|
|
4223
4603
|
function shardExists(projectName) {
|
|
4224
4604
|
const safeName = safeShardName(projectName);
|
|
4225
|
-
return
|
|
4605
|
+
return existsSync9(path8.join(SHARDS_DIR, `${safeName}.db`));
|
|
4226
4606
|
}
|
|
4227
4607
|
function safeShardName(projectName) {
|
|
4228
4608
|
return projectName.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
4229
4609
|
}
|
|
4230
4610
|
function listShards() {
|
|
4231
|
-
if (!
|
|
4611
|
+
if (!existsSync9(SHARDS_DIR)) return [];
|
|
4232
4612
|
return readdirSync(SHARDS_DIR).filter((f) => f.endsWith(".db")).map((f) => f.replace(".db", ""));
|
|
4233
4613
|
}
|
|
4234
4614
|
async function auditShardHealth(options = {}) {
|
|
@@ -4240,7 +4620,7 @@ async function auditShardHealth(options = {}) {
|
|
|
4240
4620
|
const names = listShards();
|
|
4241
4621
|
const shards = [];
|
|
4242
4622
|
for (const name of names) {
|
|
4243
|
-
const dbPath =
|
|
4623
|
+
const dbPath = path8.join(SHARDS_DIR, `${name}.db`);
|
|
4244
4624
|
const stat = statSync4(dbPath);
|
|
4245
4625
|
const item = {
|
|
4246
4626
|
name,
|
|
@@ -4275,7 +4655,7 @@ async function auditShardHealth(options = {}) {
|
|
|
4275
4655
|
_shards.delete(name);
|
|
4276
4656
|
_shardLastAccess.delete(name);
|
|
4277
4657
|
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
4278
|
-
const archivedPath =
|
|
4658
|
+
const archivedPath = path8.join(SHARDS_DIR, `${name}.db.broken-${stamp}`);
|
|
4279
4659
|
renameSync3(dbPath, archivedPath);
|
|
4280
4660
|
item.archivedPath = archivedPath;
|
|
4281
4661
|
}
|
|
@@ -4503,11 +4883,11 @@ async function getReadyShardClient(projectName) {
|
|
|
4503
4883
|
client.close();
|
|
4504
4884
|
_shards.delete(safeName);
|
|
4505
4885
|
_shardLastAccess.delete(safeName);
|
|
4506
|
-
const dbPath =
|
|
4507
|
-
if (
|
|
4886
|
+
const dbPath = path8.join(SHARDS_DIR, `${safeName}.db`);
|
|
4887
|
+
if (existsSync9(dbPath)) {
|
|
4508
4888
|
const stat = statSync4(dbPath);
|
|
4509
4889
|
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
4510
|
-
const archivedPath =
|
|
4890
|
+
const archivedPath = path8.join(SHARDS_DIR, `${safeName}.db.broken-${stamp}`);
|
|
4511
4891
|
renameSync3(dbPath, archivedPath);
|
|
4512
4892
|
process.stderr.write(
|
|
4513
4893
|
`[shard-manager] Archived unreadable shard ${safeName}: ${archivedPath} (${stat.size} bytes, mtime ${stat.mtime.toISOString()})
|
|
@@ -4575,7 +4955,7 @@ var init_shard_manager = __esm({
|
|
|
4575
4955
|
"src/lib/shard-manager.ts"() {
|
|
4576
4956
|
"use strict";
|
|
4577
4957
|
init_config();
|
|
4578
|
-
SHARDS_DIR =
|
|
4958
|
+
SHARDS_DIR = path8.join(EXE_AI_DIR, "shards");
|
|
4579
4959
|
SHARD_IDLE_MS = 5 * 60 * 1e3;
|
|
4580
4960
|
MAX_OPEN_SHARDS = 10;
|
|
4581
4961
|
EVICTION_INTERVAL_MS = 60 * 1e3;
|
|
@@ -6167,8 +6547,8 @@ __export(reranker_exports, {
|
|
|
6167
6547
|
rerankWithContext: () => rerankWithContext,
|
|
6168
6548
|
rerankWithScores: () => rerankWithScores
|
|
6169
6549
|
});
|
|
6170
|
-
import
|
|
6171
|
-
import { existsSync as
|
|
6550
|
+
import path9 from "path";
|
|
6551
|
+
import { existsSync as existsSync10 } from "fs";
|
|
6172
6552
|
function resetIdleTimer() {
|
|
6173
6553
|
if (_idleTimer) clearTimeout(_idleTimer);
|
|
6174
6554
|
_idleTimer = setTimeout(() => {
|
|
@@ -6179,18 +6559,18 @@ function resetIdleTimer() {
|
|
|
6179
6559
|
}
|
|
6180
6560
|
}
|
|
6181
6561
|
function isRerankerAvailable() {
|
|
6182
|
-
return
|
|
6562
|
+
return existsSync10(path9.join(MODELS_DIR, RERANKER_MODEL_FILE));
|
|
6183
6563
|
}
|
|
6184
6564
|
function getRerankerModelPath() {
|
|
6185
|
-
return
|
|
6565
|
+
return path9.join(MODELS_DIR, RERANKER_MODEL_FILE);
|
|
6186
6566
|
}
|
|
6187
6567
|
async function ensureLoaded() {
|
|
6188
6568
|
if (_rerankerContext) {
|
|
6189
6569
|
resetIdleTimer();
|
|
6190
6570
|
return;
|
|
6191
6571
|
}
|
|
6192
|
-
const modelPath =
|
|
6193
|
-
if (!
|
|
6572
|
+
const modelPath = path9.join(MODELS_DIR, RERANKER_MODEL_FILE);
|
|
6573
|
+
if (!existsSync10(modelPath)) {
|
|
6194
6574
|
throw new Error(
|
|
6195
6575
|
`Reranker model not found at ${modelPath}. Run /exe-setup to download it.`
|
|
6196
6576
|
);
|
|
@@ -6361,7 +6741,7 @@ __export(project_name_exports, {
|
|
|
6361
6741
|
getProjectName: () => getProjectName
|
|
6362
6742
|
});
|
|
6363
6743
|
import { execSync as execSync4 } from "child_process";
|
|
6364
|
-
import
|
|
6744
|
+
import path10 from "path";
|
|
6365
6745
|
function getProjectName(cwd) {
|
|
6366
6746
|
const dir = cwd ?? process.cwd();
|
|
6367
6747
|
if (_cached && _cachedCwd === dir) return _cached;
|
|
@@ -6374,7 +6754,7 @@ function getProjectName(cwd) {
|
|
|
6374
6754
|
timeout: 2e3,
|
|
6375
6755
|
stdio: ["pipe", "pipe", "pipe"]
|
|
6376
6756
|
}).trim();
|
|
6377
|
-
repoRoot =
|
|
6757
|
+
repoRoot = path10.dirname(gitCommonDir);
|
|
6378
6758
|
} catch {
|
|
6379
6759
|
repoRoot = execSync4("git rev-parse --show-toplevel", {
|
|
6380
6760
|
cwd: dir,
|
|
@@ -6383,11 +6763,11 @@ function getProjectName(cwd) {
|
|
|
6383
6763
|
stdio: ["pipe", "pipe", "pipe"]
|
|
6384
6764
|
}).trim();
|
|
6385
6765
|
}
|
|
6386
|
-
_cached =
|
|
6766
|
+
_cached = path10.basename(repoRoot);
|
|
6387
6767
|
_cachedCwd = dir;
|
|
6388
6768
|
return _cached;
|
|
6389
6769
|
} catch {
|
|
6390
|
-
_cached =
|
|
6770
|
+
_cached = path10.basename(dir);
|
|
6391
6771
|
_cachedCwd = dir;
|
|
6392
6772
|
return _cached;
|
|
6393
6773
|
}
|
|
@@ -6411,8 +6791,8 @@ __export(file_grep_exports, {
|
|
|
6411
6791
|
grepProjectFiles: () => grepProjectFiles
|
|
6412
6792
|
});
|
|
6413
6793
|
import { execSync as execSync5 } from "child_process";
|
|
6414
|
-
import { readFileSync as
|
|
6415
|
-
import
|
|
6794
|
+
import { readFileSync as readFileSync6, readdirSync as readdirSync2, statSync as statSync5, existsSync as existsSync11 } from "fs";
|
|
6795
|
+
import path11 from "path";
|
|
6416
6796
|
import crypto3 from "crypto";
|
|
6417
6797
|
function hasRipgrep() {
|
|
6418
6798
|
if (_hasRg === null) {
|
|
@@ -6452,7 +6832,7 @@ async function grepProjectFiles(query, projectRoot, options) {
|
|
|
6452
6832
|
session_id: "file-grep",
|
|
6453
6833
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6454
6834
|
tool_name: "file_grep",
|
|
6455
|
-
project_name:
|
|
6835
|
+
project_name: path11.basename(projectRoot),
|
|
6456
6836
|
has_error: false,
|
|
6457
6837
|
raw_text: `${prefix} ${buildSnippet(hit, projectRoot)}`,
|
|
6458
6838
|
vector: null,
|
|
@@ -6464,7 +6844,7 @@ function getChunkContext(filePath, lineNumber) {
|
|
|
6464
6844
|
try {
|
|
6465
6845
|
const ext = filePath.split(".").pop()?.toLowerCase();
|
|
6466
6846
|
if (ext !== "ts" && ext !== "tsx" && ext !== "js" && ext !== "jsx") return "";
|
|
6467
|
-
const source =
|
|
6847
|
+
const source = readFileSync6(filePath, "utf8");
|
|
6468
6848
|
const lines = source.split("\n");
|
|
6469
6849
|
for (let i = Math.min(lineNumber - 1, lines.length - 1); i >= 0; i--) {
|
|
6470
6850
|
const line = lines[i];
|
|
@@ -6526,11 +6906,11 @@ function grepWithNodeFs(pattern, projectRoot, patterns) {
|
|
|
6526
6906
|
const files = collectFiles(projectRoot, patterns ?? DEFAULT_PATTERNS);
|
|
6527
6907
|
const hits = [];
|
|
6528
6908
|
for (const filePath of files.slice(0, MAX_FILES)) {
|
|
6529
|
-
const absPath =
|
|
6909
|
+
const absPath = path11.join(projectRoot, filePath);
|
|
6530
6910
|
try {
|
|
6531
6911
|
const stat = statSync5(absPath);
|
|
6532
6912
|
if (stat.size > MAX_FILE_SIZE) continue;
|
|
6533
|
-
const content =
|
|
6913
|
+
const content = readFileSync6(absPath, "utf8");
|
|
6534
6914
|
const lines = content.split("\n");
|
|
6535
6915
|
const matches = content.match(regex);
|
|
6536
6916
|
if (!matches || matches.length === 0) continue;
|
|
@@ -6553,15 +6933,15 @@ function collectFiles(root, patterns) {
|
|
|
6553
6933
|
const files = [];
|
|
6554
6934
|
function walk(dir, relative) {
|
|
6555
6935
|
if (files.length >= MAX_FILES) return;
|
|
6556
|
-
const basename =
|
|
6936
|
+
const basename = path11.basename(dir);
|
|
6557
6937
|
if (EXCLUDE_DIRS.includes(basename)) return;
|
|
6558
6938
|
try {
|
|
6559
6939
|
const entries = readdirSync2(dir, { withFileTypes: true });
|
|
6560
6940
|
for (const entry of entries) {
|
|
6561
6941
|
if (files.length >= MAX_FILES) return;
|
|
6562
|
-
const rel =
|
|
6942
|
+
const rel = path11.join(relative, entry.name);
|
|
6563
6943
|
if (entry.isDirectory()) {
|
|
6564
|
-
walk(
|
|
6944
|
+
walk(path11.join(dir, entry.name), rel);
|
|
6565
6945
|
} else if (entry.isFile()) {
|
|
6566
6946
|
for (const pat of patterns) {
|
|
6567
6947
|
if (matchGlob(rel, pat)) {
|
|
@@ -6593,7 +6973,7 @@ function matchGlob(filePath, pattern) {
|
|
|
6593
6973
|
if (slashIdx !== -1) {
|
|
6594
6974
|
const dir = pattern.slice(0, slashIdx);
|
|
6595
6975
|
const ext2 = pattern.slice(slashIdx + 1).replace("*", "");
|
|
6596
|
-
const fileDir =
|
|
6976
|
+
const fileDir = path11.dirname(filePath);
|
|
6597
6977
|
return fileDir === dir && filePath.endsWith(ext2);
|
|
6598
6978
|
}
|
|
6599
6979
|
const ext = pattern.replace("*", "");
|
|
@@ -6601,9 +6981,9 @@ function matchGlob(filePath, pattern) {
|
|
|
6601
6981
|
}
|
|
6602
6982
|
function buildSnippet(hit, projectRoot) {
|
|
6603
6983
|
try {
|
|
6604
|
-
const absPath =
|
|
6605
|
-
if (!
|
|
6606
|
-
const lines =
|
|
6984
|
+
const absPath = path11.join(projectRoot, hit.filePath);
|
|
6985
|
+
if (!existsSync11(absPath)) return hit.matchLine;
|
|
6986
|
+
const lines = readFileSync6(absPath, "utf8").split("\n");
|
|
6607
6987
|
const start = Math.max(0, hit.lineNumber - 3);
|
|
6608
6988
|
const end = Math.min(lines.length, hit.lineNumber + 2);
|
|
6609
6989
|
return lines.slice(start, end).join("\n").slice(0, 500);
|
|
@@ -7989,9 +8369,9 @@ var init_agent_context = __esm({
|
|
|
7989
8369
|
});
|
|
7990
8370
|
|
|
7991
8371
|
// src/lib/active-agent.ts
|
|
7992
|
-
import { readFileSync as
|
|
8372
|
+
import { readFileSync as readFileSync7, writeFileSync as writeFileSync4, mkdirSync as mkdirSync4, unlinkSync as unlinkSync4, readdirSync as readdirSync3 } from "fs";
|
|
7993
8373
|
import { execSync as execSync7 } from "child_process";
|
|
7994
|
-
import
|
|
8374
|
+
import path12 from "path";
|
|
7995
8375
|
function isNameWithOptionalInstance(candidate, baseName) {
|
|
7996
8376
|
if (candidate === baseName) return true;
|
|
7997
8377
|
if (!candidate.startsWith(baseName)) return false;
|
|
@@ -8035,12 +8415,12 @@ function resolveActiveAgentFromTmuxSession(sessionName) {
|
|
|
8035
8415
|
return null;
|
|
8036
8416
|
}
|
|
8037
8417
|
function getMarkerPath() {
|
|
8038
|
-
return
|
|
8418
|
+
return path12.join(CACHE_DIR, `active-agent-${getSessionKey()}.json`);
|
|
8039
8419
|
}
|
|
8040
8420
|
function writeActiveAgent(agentId, agentRole) {
|
|
8041
8421
|
try {
|
|
8042
8422
|
mkdirSync4(CACHE_DIR, { recursive: true });
|
|
8043
|
-
|
|
8423
|
+
writeFileSync4(
|
|
8044
8424
|
getMarkerPath(),
|
|
8045
8425
|
JSON.stringify({ agentId, agentRole, startedAt: (/* @__PURE__ */ new Date()).toISOString() })
|
|
8046
8426
|
);
|
|
@@ -8058,7 +8438,7 @@ function getActiveAgent() {
|
|
|
8058
8438
|
if (httpCtx) return httpCtx;
|
|
8059
8439
|
try {
|
|
8060
8440
|
const markerPath = getMarkerPath();
|
|
8061
|
-
const raw =
|
|
8441
|
+
const raw = readFileSync7(markerPath, "utf8");
|
|
8062
8442
|
const data = JSON.parse(raw);
|
|
8063
8443
|
if (data.agentId) {
|
|
8064
8444
|
if (data.startedAt) {
|
|
@@ -8106,14 +8486,14 @@ function getAllActiveAgents() {
|
|
|
8106
8486
|
const key = file.slice("active-agent-".length, -".json".length);
|
|
8107
8487
|
if (key === "undefined") continue;
|
|
8108
8488
|
try {
|
|
8109
|
-
const raw =
|
|
8489
|
+
const raw = readFileSync7(path12.join(CACHE_DIR, file), "utf8");
|
|
8110
8490
|
const data = JSON.parse(raw);
|
|
8111
8491
|
if (!data.agentId) continue;
|
|
8112
8492
|
if (data.startedAt) {
|
|
8113
8493
|
const age = Date.now() - new Date(data.startedAt).getTime();
|
|
8114
8494
|
if (age > STALE_MS) {
|
|
8115
8495
|
try {
|
|
8116
|
-
unlinkSync4(
|
|
8496
|
+
unlinkSync4(path12.join(CACHE_DIR, file));
|
|
8117
8497
|
} catch {
|
|
8118
8498
|
}
|
|
8119
8499
|
continue;
|
|
@@ -8136,11 +8516,11 @@ function getAllActiveAgents() {
|
|
|
8136
8516
|
function cleanupSessionMarkers() {
|
|
8137
8517
|
const key = getSessionKey();
|
|
8138
8518
|
try {
|
|
8139
|
-
unlinkSync4(
|
|
8519
|
+
unlinkSync4(path12.join(CACHE_DIR, `active-agent-${key}.json`));
|
|
8140
8520
|
} catch {
|
|
8141
8521
|
}
|
|
8142
8522
|
try {
|
|
8143
|
-
unlinkSync4(
|
|
8523
|
+
unlinkSync4(path12.join(CACHE_DIR, "active-agent-undefined.json"));
|
|
8144
8524
|
} catch {
|
|
8145
8525
|
}
|
|
8146
8526
|
}
|
|
@@ -8152,7 +8532,7 @@ var init_active_agent = __esm({
|
|
|
8152
8532
|
init_session_key();
|
|
8153
8533
|
init_agent_context();
|
|
8154
8534
|
init_employees();
|
|
8155
|
-
CACHE_DIR =
|
|
8535
|
+
CACHE_DIR = path12.join(EXE_AI_DIR, "session-cache");
|
|
8156
8536
|
STALE_MS = 24 * 60 * 60 * 1e3;
|
|
8157
8537
|
}
|
|
8158
8538
|
});
|
|
@@ -8477,13 +8857,13 @@ var init_fast_db_init = __esm({
|
|
|
8477
8857
|
});
|
|
8478
8858
|
|
|
8479
8859
|
// src/lib/session-registry.ts
|
|
8480
|
-
import
|
|
8860
|
+
import path13 from "path";
|
|
8481
8861
|
import os6 from "os";
|
|
8482
8862
|
var REGISTRY_PATH;
|
|
8483
8863
|
var init_session_registry = __esm({
|
|
8484
8864
|
"src/lib/session-registry.ts"() {
|
|
8485
8865
|
"use strict";
|
|
8486
|
-
REGISTRY_PATH =
|
|
8866
|
+
REGISTRY_PATH = path13.join(os6.homedir(), ".exe-os", "session-registry.json");
|
|
8487
8867
|
}
|
|
8488
8868
|
});
|
|
8489
8869
|
|
|
@@ -8619,51 +8999,6 @@ var init_provider_table = __esm({
|
|
|
8619
8999
|
}
|
|
8620
9000
|
});
|
|
8621
9001
|
|
|
8622
|
-
// src/lib/runtime-table.ts
|
|
8623
|
-
var RUNTIME_TABLE;
|
|
8624
|
-
var init_runtime_table = __esm({
|
|
8625
|
-
"src/lib/runtime-table.ts"() {
|
|
8626
|
-
"use strict";
|
|
8627
|
-
RUNTIME_TABLE = {
|
|
8628
|
-
codex: {
|
|
8629
|
-
binary: "codex",
|
|
8630
|
-
launchMode: "interactive",
|
|
8631
|
-
autoApproveFlag: "--dangerously-bypass-approvals-and-sandbox",
|
|
8632
|
-
inlineFlag: "--no-alt-screen",
|
|
8633
|
-
apiKeyEnv: "OPENAI_API_KEY",
|
|
8634
|
-
defaultModel: "gpt-5.5"
|
|
8635
|
-
},
|
|
8636
|
-
opencode: {
|
|
8637
|
-
binary: "opencode",
|
|
8638
|
-
launchMode: "exec",
|
|
8639
|
-
autoApproveFlag: "--dangerously-skip-permissions",
|
|
8640
|
-
inlineFlag: "",
|
|
8641
|
-
apiKeyEnv: "ANTHROPIC_API_KEY",
|
|
8642
|
-
defaultModel: "anthropic/claude-sonnet-4-6"
|
|
8643
|
-
}
|
|
8644
|
-
};
|
|
8645
|
-
}
|
|
8646
|
-
});
|
|
8647
|
-
|
|
8648
|
-
// src/lib/agent-config.ts
|
|
8649
|
-
import { readFileSync as readFileSync7, writeFileSync as writeFileSync4, existsSync as existsSync11 } from "fs";
|
|
8650
|
-
import path13 from "path";
|
|
8651
|
-
var AGENT_CONFIG_PATH, DEFAULT_MODELS;
|
|
8652
|
-
var init_agent_config = __esm({
|
|
8653
|
-
"src/lib/agent-config.ts"() {
|
|
8654
|
-
"use strict";
|
|
8655
|
-
init_config();
|
|
8656
|
-
init_runtime_table();
|
|
8657
|
-
init_secure_files();
|
|
8658
|
-
AGENT_CONFIG_PATH = path13.join(EXE_AI_DIR, "agent-config.json");
|
|
8659
|
-
DEFAULT_MODELS = {
|
|
8660
|
-
claude: "claude-opus-4.6",
|
|
8661
|
-
codex: RUNTIME_TABLE.codex?.defaultModel ?? "gpt-5.4",
|
|
8662
|
-
opencode: RUNTIME_TABLE.opencode?.defaultModel ?? "anthropic/claude-sonnet-4-6"
|
|
8663
|
-
};
|
|
8664
|
-
}
|
|
8665
|
-
});
|
|
8666
|
-
|
|
8667
9002
|
// src/lib/intercom-queue.ts
|
|
8668
9003
|
import { readFileSync as readFileSync8, writeFileSync as writeFileSync5, renameSync as renameSync4, existsSync as existsSync12, mkdirSync as mkdirSync5 } from "fs";
|
|
8669
9004
|
import path14 from "path";
|
|
@@ -8744,6 +9079,21 @@ function isRootSession(name) {
|
|
|
8744
9079
|
function extractRootExe(name) {
|
|
8745
9080
|
if (!name) return null;
|
|
8746
9081
|
if (!name.includes("-")) return name;
|
|
9082
|
+
try {
|
|
9083
|
+
const roster = (init_employees(), __toCommonJS(employees_exports)).loadEmployeesSync();
|
|
9084
|
+
if (roster.length > 0) {
|
|
9085
|
+
const sortedNames = roster.map((e) => e.name).sort((a, b) => b.length - a.length);
|
|
9086
|
+
for (const agentName of sortedNames) {
|
|
9087
|
+
const escaped = agentName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
9088
|
+
const regex = new RegExp(`^${escaped}\\d*-(.+)$`);
|
|
9089
|
+
const match = name.match(regex);
|
|
9090
|
+
if (match) {
|
|
9091
|
+
return extractRootExe(match[1]);
|
|
9092
|
+
}
|
|
9093
|
+
}
|
|
9094
|
+
}
|
|
9095
|
+
} catch {
|
|
9096
|
+
}
|
|
8747
9097
|
const parts = name.split("-").filter(Boolean);
|
|
8748
9098
|
return parts.length > 0 ? parts[parts.length - 1] : null;
|
|
8749
9099
|
}
|
|
@@ -8762,6 +9112,10 @@ function registerParentExe(sessionKey, parentExe, dispatchedBy) {
|
|
|
8762
9112
|
function getParentExe(sessionKey) {
|
|
8763
9113
|
try {
|
|
8764
9114
|
const data = JSON.parse(readFileSync11(path18.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
|
|
9115
|
+
if (data.registeredAt) {
|
|
9116
|
+
const age = Date.now() - new Date(data.registeredAt).getTime();
|
|
9117
|
+
if (age > PARENT_EXE_CACHE_TTL_MS) return null;
|
|
9118
|
+
}
|
|
8765
9119
|
return data.parentExe || null;
|
|
8766
9120
|
} catch {
|
|
8767
9121
|
return null;
|
|
@@ -8834,7 +9188,7 @@ function resolveExeSession() {
|
|
|
8834
9188
|
}
|
|
8835
9189
|
return candidate;
|
|
8836
9190
|
}
|
|
8837
|
-
var SPAWN_LOCK_DIR, SESSION_CACHE, INTERCOM_LOG2, DEBOUNCE_FILE, DEBOUNCE_CLEANUP_AGE_MS;
|
|
9191
|
+
var SPAWN_LOCK_DIR, SESSION_CACHE, PARENT_EXE_CACHE_TTL_MS, INTERCOM_LOG2, DEBOUNCE_FILE, DEBOUNCE_CLEANUP_AGE_MS;
|
|
8838
9192
|
var init_tmux_routing = __esm({
|
|
8839
9193
|
"src/lib/tmux-routing.ts"() {
|
|
8840
9194
|
"use strict";
|
|
@@ -8852,6 +9206,7 @@ var init_tmux_routing = __esm({
|
|
|
8852
9206
|
init_agent_symlinks();
|
|
8853
9207
|
SPAWN_LOCK_DIR = path18.join(os10.homedir(), ".exe-os", "spawn-locks");
|
|
8854
9208
|
SESSION_CACHE = path18.join(os10.homedir(), ".exe-os", "session-cache");
|
|
9209
|
+
PARENT_EXE_CACHE_TTL_MS = 4 * 60 * 60 * 1e3;
|
|
8855
9210
|
INTERCOM_LOG2 = path18.join(os10.homedir(), ".exe-os", "intercom.log");
|
|
8856
9211
|
DEBOUNCE_FILE = path18.join(SESSION_CACHE, "intercom-debounce.json");
|
|
8857
9212
|
DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
|