@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());
|
|
@@ -435,6 +448,7 @@ __export(agent_config_exports, {
|
|
|
435
448
|
clearAgentRuntime: () => clearAgentRuntime,
|
|
436
449
|
getAgentRuntime: () => getAgentRuntime,
|
|
437
450
|
loadAgentConfig: () => loadAgentConfig,
|
|
451
|
+
normalizeCcModelName: () => normalizeCcModelName,
|
|
438
452
|
saveAgentConfig: () => saveAgentConfig,
|
|
439
453
|
setAgentMcps: () => setAgentMcps,
|
|
440
454
|
setAgentRuntime: () => setAgentRuntime
|
|
@@ -463,6 +477,13 @@ function getAgentRuntime(agentId) {
|
|
|
463
477
|
if (orgDefault) return orgDefault;
|
|
464
478
|
return { runtime: DEFAULT_RUNTIME, model: DEFAULT_MODELS[DEFAULT_RUNTIME] };
|
|
465
479
|
}
|
|
480
|
+
function normalizeCcModelName(model) {
|
|
481
|
+
let ccModel = model.replace(/(\d+)\.(\d+)/g, "$1-$2");
|
|
482
|
+
if (/claude-(opus|sonnet)-4-[6-9]/.test(ccModel) && !ccModel.includes("[1m]")) {
|
|
483
|
+
ccModel += "[1m]";
|
|
484
|
+
}
|
|
485
|
+
return ccModel;
|
|
486
|
+
}
|
|
466
487
|
function setAgentRuntime(agentId, runtime, model, reasoning_effort, mcps) {
|
|
467
488
|
const knownModels = KNOWN_RUNTIMES[runtime];
|
|
468
489
|
if (!knownModels) {
|
|
@@ -1013,6 +1034,7 @@ var init_provider_table = __esm({
|
|
|
1013
1034
|
// src/lib/intercom-queue.ts
|
|
1014
1035
|
var intercom_queue_exports = {};
|
|
1015
1036
|
__export(intercom_queue_exports, {
|
|
1037
|
+
_resetDrainGuard: () => _resetDrainGuard,
|
|
1016
1038
|
clearQueueForAgent: () => clearQueueForAgent,
|
|
1017
1039
|
drainForSession: () => drainForSession,
|
|
1018
1040
|
drainQueue: () => drainQueue,
|
|
@@ -1058,38 +1080,47 @@ function queueIntercom(targetSession, reason) {
|
|
|
1058
1080
|
writeQueue(queue);
|
|
1059
1081
|
}
|
|
1060
1082
|
function drainQueue(isSessionBusy2, sendKeys) {
|
|
1083
|
+
if (_draining) {
|
|
1084
|
+
logQueue("SKIP_DRAIN \u2014 previous drain still running (possible tmux hang)");
|
|
1085
|
+
return { drained: 0, failed: 0 };
|
|
1086
|
+
}
|
|
1061
1087
|
const queue = readQueue();
|
|
1062
1088
|
if (queue.length === 0) return { drained: 0, failed: 0 };
|
|
1089
|
+
_draining = true;
|
|
1063
1090
|
const remaining = [];
|
|
1064
1091
|
let drained = 0;
|
|
1065
1092
|
let failed = 0;
|
|
1066
|
-
|
|
1067
|
-
const
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1093
|
+
try {
|
|
1094
|
+
for (const item of queue) {
|
|
1095
|
+
const age = Date.now() - new Date(item.queuedAt).getTime();
|
|
1096
|
+
if (age > TTL_MS) {
|
|
1097
|
+
logQueue(`EXPIRED \u2192 ${item.targetSession} (${Math.round(age / 6e4)}min old, reason: ${item.reason})`);
|
|
1098
|
+
failed++;
|
|
1099
|
+
continue;
|
|
1100
|
+
}
|
|
1101
|
+
try {
|
|
1102
|
+
if (!isSessionBusy2(item.targetSession)) {
|
|
1103
|
+
const success = sendKeys(item.targetSession);
|
|
1104
|
+
if (success) {
|
|
1105
|
+
logQueue(`DRAINED \u2192 ${item.targetSession} (after ${item.attempts} retries)`);
|
|
1106
|
+
drained++;
|
|
1107
|
+
continue;
|
|
1108
|
+
}
|
|
1080
1109
|
}
|
|
1110
|
+
} catch {
|
|
1081
1111
|
}
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1112
|
+
item.attempts++;
|
|
1113
|
+
if (item.attempts >= MAX_RETRIES) {
|
|
1114
|
+
logQueue(`FAILED \u2192 ${item.targetSession} (${MAX_RETRIES} retries exhausted, reason: ${item.reason})`);
|
|
1115
|
+
failed++;
|
|
1116
|
+
continue;
|
|
1117
|
+
}
|
|
1118
|
+
remaining.push(item);
|
|
1089
1119
|
}
|
|
1090
|
-
remaining
|
|
1120
|
+
writeQueue(remaining);
|
|
1121
|
+
} finally {
|
|
1122
|
+
_draining = false;
|
|
1091
1123
|
}
|
|
1092
|
-
writeQueue(remaining);
|
|
1093
1124
|
return { drained, failed };
|
|
1094
1125
|
}
|
|
1095
1126
|
function drainForSession(targetSession, sendKeys) {
|
|
@@ -1114,6 +1145,9 @@ function clearQueueForAgent(agentName) {
|
|
|
1114
1145
|
logQueue(`CLEARED ${before - filtered.length} stale item(s) for ${agentName}`);
|
|
1115
1146
|
}
|
|
1116
1147
|
}
|
|
1148
|
+
function _resetDrainGuard() {
|
|
1149
|
+
_draining = false;
|
|
1150
|
+
}
|
|
1117
1151
|
function logQueue(msg) {
|
|
1118
1152
|
const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] [queue] ${msg}
|
|
1119
1153
|
`;
|
|
@@ -1125,13 +1159,14 @@ function logQueue(msg) {
|
|
|
1125
1159
|
} catch {
|
|
1126
1160
|
}
|
|
1127
1161
|
}
|
|
1128
|
-
var QUEUE_PATH, MAX_RETRIES, TTL_MS, INTERCOM_LOG;
|
|
1162
|
+
var QUEUE_PATH, MAX_RETRIES, TTL_MS, _draining, INTERCOM_LOG;
|
|
1129
1163
|
var init_intercom_queue = __esm({
|
|
1130
1164
|
"src/lib/intercom-queue.ts"() {
|
|
1131
1165
|
"use strict";
|
|
1132
1166
|
QUEUE_PATH = path7.join(os5.homedir(), ".exe-os", "intercom-queue.json");
|
|
1133
1167
|
MAX_RETRIES = 5;
|
|
1134
1168
|
TTL_MS = 60 * 60 * 1e3;
|
|
1169
|
+
_draining = false;
|
|
1135
1170
|
INTERCOM_LOG = path7.join(os5.homedir(), ".exe-os", "intercom.log");
|
|
1136
1171
|
}
|
|
1137
1172
|
});
|
|
@@ -6072,7 +6107,13 @@ async function createReviewForCompletedTask(row, result, _baseDir, now) {
|
|
|
6072
6107
|
taskFile
|
|
6073
6108
|
});
|
|
6074
6109
|
const originalPriority = String(row.priority).toLowerCase();
|
|
6075
|
-
const
|
|
6110
|
+
const resultLower = result?.toLowerCase() ?? "";
|
|
6111
|
+
const hasTestEvidence = (
|
|
6112
|
+
// Vitest/Jest output patterns (hard to fake without actually running tests)
|
|
6113
|
+
/\d+\s+pass(ed|ing)/.test(resultLower) || /test files?\s+\d+\s+passed/.test(resultLower) || /tests?\s+\d+\s+passed/.test(resultLower)
|
|
6114
|
+
);
|
|
6115
|
+
const hasNoFailures = !/fail(ed|ure|ing)|error/i.test(resultLower);
|
|
6116
|
+
const autoApprove = originalPriority === "p2" && hasTestEvidence && hasNoFailures;
|
|
6076
6117
|
if (!autoApprove) {
|
|
6077
6118
|
try {
|
|
6078
6119
|
const key = getSessionKey();
|
|
@@ -6080,6 +6121,13 @@ async function createReviewForCompletedTask(row, result, _baseDir, now) {
|
|
|
6080
6121
|
if (exeSession) {
|
|
6081
6122
|
sendIntercom(exeSession);
|
|
6082
6123
|
}
|
|
6124
|
+
if (reviewer && reviewer !== coordinatorName && reviewer !== exeSession) {
|
|
6125
|
+
const { employeeSessionName: employeeSessionName2 } = await Promise.resolve().then(() => (init_tmux_routing(), tmux_routing_exports));
|
|
6126
|
+
if (exeSession) {
|
|
6127
|
+
const reviewerSession = employeeSessionName2(reviewer, exeSession);
|
|
6128
|
+
sendIntercom(reviewerSession);
|
|
6129
|
+
}
|
|
6130
|
+
}
|
|
6083
6131
|
} catch {
|
|
6084
6132
|
}
|
|
6085
6133
|
}
|
|
@@ -6855,6 +6903,20 @@ async function updateTask(input2) {
|
|
|
6855
6903
|
notifyTaskDone();
|
|
6856
6904
|
}
|
|
6857
6905
|
await markTaskNotificationsRead(taskFile);
|
|
6906
|
+
if (input2.status === "needs_review" && !isCoordinator) {
|
|
6907
|
+
try {
|
|
6908
|
+
const { writeNotification: writeNotification2 } = await Promise.resolve().then(() => (init_notifications(), notifications_exports));
|
|
6909
|
+
await writeNotification2({
|
|
6910
|
+
agentId: String(row.assigned_to),
|
|
6911
|
+
agentRole: String(row.assigned_to),
|
|
6912
|
+
event: "task_complete",
|
|
6913
|
+
project: String(row.project_name),
|
|
6914
|
+
summary: `"${String(row.title)}" is ready for review`,
|
|
6915
|
+
taskFile
|
|
6916
|
+
});
|
|
6917
|
+
} catch {
|
|
6918
|
+
}
|
|
6919
|
+
}
|
|
6858
6920
|
if (input2.status === "done" || input2.status === "closed") {
|
|
6859
6921
|
try {
|
|
6860
6922
|
await cascadeUnblock(taskId, input2.baseDir, now);
|
|
@@ -7287,18 +7349,31 @@ function acquireSpawnLock2(sessionName) {
|
|
|
7287
7349
|
mkdirSync10(SPAWN_LOCK_DIR, { recursive: true });
|
|
7288
7350
|
}
|
|
7289
7351
|
const lockFile = spawnLockPath(sessionName);
|
|
7290
|
-
|
|
7291
|
-
|
|
7292
|
-
|
|
7293
|
-
|
|
7294
|
-
|
|
7295
|
-
|
|
7296
|
-
|
|
7297
|
-
|
|
7352
|
+
const lockData = JSON.stringify({ pid: process.pid, timestamp: Date.now() });
|
|
7353
|
+
const { openSync: openSync3, closeSync: closeSync3, writeSync } = __require("fs");
|
|
7354
|
+
const { constants } = __require("fs");
|
|
7355
|
+
try {
|
|
7356
|
+
const fd = openSync3(lockFile, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL, 420);
|
|
7357
|
+
writeSync(fd, lockData);
|
|
7358
|
+
closeSync3(fd);
|
|
7359
|
+
return true;
|
|
7360
|
+
} catch (err) {
|
|
7361
|
+
if (err?.code !== "EEXIST") {
|
|
7362
|
+
return true;
|
|
7298
7363
|
}
|
|
7299
7364
|
}
|
|
7300
|
-
|
|
7301
|
-
|
|
7365
|
+
try {
|
|
7366
|
+
const lock = JSON.parse(readFileSync14(lockFile, "utf8"));
|
|
7367
|
+
const age = Date.now() - lock.timestamp;
|
|
7368
|
+
if (isProcessAlive(lock.pid) && age < 6e4) {
|
|
7369
|
+
return false;
|
|
7370
|
+
}
|
|
7371
|
+
writeFileSync10(lockFile, lockData);
|
|
7372
|
+
return true;
|
|
7373
|
+
} catch {
|
|
7374
|
+
writeFileSync10(lockFile, lockData);
|
|
7375
|
+
return true;
|
|
7376
|
+
}
|
|
7302
7377
|
}
|
|
7303
7378
|
function releaseSpawnLock2(sessionName) {
|
|
7304
7379
|
try {
|
|
@@ -7377,6 +7452,21 @@ function parseParentExe(sessionName, agentId) {
|
|
|
7377
7452
|
function extractRootExe(name) {
|
|
7378
7453
|
if (!name) return null;
|
|
7379
7454
|
if (!name.includes("-")) return name;
|
|
7455
|
+
try {
|
|
7456
|
+
const roster = (init_employees(), __toCommonJS(employees_exports)).loadEmployeesSync();
|
|
7457
|
+
if (roster.length > 0) {
|
|
7458
|
+
const sortedNames = roster.map((e) => e.name).sort((a, b) => b.length - a.length);
|
|
7459
|
+
for (const agentName of sortedNames) {
|
|
7460
|
+
const escaped = agentName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
7461
|
+
const regex = new RegExp(`^${escaped}\\d*-(.+)$`);
|
|
7462
|
+
const match = name.match(regex);
|
|
7463
|
+
if (match) {
|
|
7464
|
+
return extractRootExe(match[1]);
|
|
7465
|
+
}
|
|
7466
|
+
}
|
|
7467
|
+
}
|
|
7468
|
+
} catch {
|
|
7469
|
+
}
|
|
7380
7470
|
const parts = name.split("-").filter(Boolean);
|
|
7381
7471
|
return parts.length > 0 ? parts[parts.length - 1] : null;
|
|
7382
7472
|
}
|
|
@@ -7395,6 +7485,10 @@ function registerParentExe(sessionKey, parentExe, dispatchedBy) {
|
|
|
7395
7485
|
function getParentExe(sessionKey) {
|
|
7396
7486
|
try {
|
|
7397
7487
|
const data = JSON.parse(readFileSync14(path20.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
|
|
7488
|
+
if (data.registeredAt) {
|
|
7489
|
+
const age = Date.now() - new Date(data.registeredAt).getTime();
|
|
7490
|
+
if (age > PARENT_EXE_CACHE_TTL_MS) return null;
|
|
7491
|
+
}
|
|
7398
7492
|
return data.parentExe || null;
|
|
7399
7493
|
} catch {
|
|
7400
7494
|
return null;
|
|
@@ -7943,7 +8037,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
7943
8037
|
sessionContextFlag = ` --append-system-prompt-file ${ctxFile}`;
|
|
7944
8038
|
} catch {
|
|
7945
8039
|
}
|
|
7946
|
-
let envPrefix = `EXE_SESSION=${exeSession} EXE_SESSION_NAME=${sessionName}`;
|
|
8040
|
+
let envPrefix = `EXE_SESSION=${exeSession} EXE_SESSION_NAME=${sessionName} EXE_SESSION_START_ISO=${(/* @__PURE__ */ new Date()).toISOString()}`;
|
|
7947
8041
|
if (ccProvider !== DEFAULT_PROVIDER) {
|
|
7948
8042
|
const cfg = PROVIDER_TABLE[ccProvider];
|
|
7949
8043
|
if (cfg?.apiKeyEnv) {
|
|
@@ -7978,10 +8072,8 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
7978
8072
|
}
|
|
7979
8073
|
if (!useExeAgent && !useCodex && !useOpencode && !useBinSymlink) {
|
|
7980
8074
|
if (agentRtConfig.runtime === "claude" && agentRtConfig.model) {
|
|
7981
|
-
|
|
7982
|
-
|
|
7983
|
-
ccModel += "[1m]";
|
|
7984
|
-
}
|
|
8075
|
+
const { normalizeCcModelName: normalizeCcModelName2 } = (init_agent_config(), __toCommonJS(agent_config_exports));
|
|
8076
|
+
const ccModel = normalizeCcModelName2(agentRtConfig.model);
|
|
7985
8077
|
envPrefix = `${envPrefix} ANTHROPIC_MODEL=${ccModel}`;
|
|
7986
8078
|
}
|
|
7987
8079
|
}
|
|
@@ -8082,7 +8174,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
8082
8174
|
releaseSpawnLock2(sessionName);
|
|
8083
8175
|
return { sessionName };
|
|
8084
8176
|
}
|
|
8085
|
-
var SPAWN_LOCK_DIR, SESSION_CACHE, BEHAVIORS_EXPORT_TIMEOUT_MS, VALID_SESSION_NAME, VERIFY_PANE_LINES, INTERCOM_DEBOUNCE_MS, CODEX_DEBOUNCE_MS, INTERCOM_LOG2, DEBOUNCE_FILE, DEBOUNCE_CLEANUP_AGE_MS, BUSY_PATTERN;
|
|
8177
|
+
var SPAWN_LOCK_DIR, SESSION_CACHE, BEHAVIORS_EXPORT_TIMEOUT_MS, VALID_SESSION_NAME, PARENT_EXE_CACHE_TTL_MS, VERIFY_PANE_LINES, INTERCOM_DEBOUNCE_MS, CODEX_DEBOUNCE_MS, INTERCOM_LOG2, DEBOUNCE_FILE, DEBOUNCE_CLEANUP_AGE_MS, BUSY_PATTERN;
|
|
8086
8178
|
var init_tmux_routing = __esm({
|
|
8087
8179
|
"src/lib/tmux-routing.ts"() {
|
|
8088
8180
|
"use strict";
|
|
@@ -8102,6 +8194,7 @@ var init_tmux_routing = __esm({
|
|
|
8102
8194
|
SESSION_CACHE = path20.join(os12.homedir(), ".exe-os", "session-cache");
|
|
8103
8195
|
BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
|
|
8104
8196
|
VALID_SESSION_NAME = /^[a-z]+\d*-[a-zA-Z0-9_]+$/;
|
|
8197
|
+
PARENT_EXE_CACHE_TTL_MS = 4 * 60 * 60 * 1e3;
|
|
8105
8198
|
VERIFY_PANE_LINES = 200;
|
|
8106
8199
|
INTERCOM_DEBOUNCE_MS = 3e4;
|
|
8107
8200
|
CODEX_DEBOUNCE_MS = 12e4;
|
|
@@ -8146,7 +8239,7 @@ var init_task_scope = __esm({
|
|
|
8146
8239
|
});
|
|
8147
8240
|
|
|
8148
8241
|
// src/lib/keychain.ts
|
|
8149
|
-
import { readFile as readFile4, writeFile as writeFile5, unlink, mkdir as mkdir4, chmod as chmod2 } from "fs/promises";
|
|
8242
|
+
import { readFile as readFile4, writeFile as writeFile5, unlink, mkdir as mkdir4, chmod as chmod2, rename, copyFile } from "fs/promises";
|
|
8150
8243
|
import { existsSync as existsSync19, statSync as statSync4 } from "fs";
|
|
8151
8244
|
import { execSync as execSync9 } from "child_process";
|
|
8152
8245
|
import path22 from "path";
|
|
@@ -8181,12 +8274,14 @@ function linuxSecretAvailable() {
|
|
|
8181
8274
|
function isRootOnlyTrustedServerKeyFile(keyPath) {
|
|
8182
8275
|
if (process.platform !== "linux") return false;
|
|
8183
8276
|
try {
|
|
8184
|
-
const uid = typeof os13.userInfo().uid === "number" ? os13.userInfo().uid : -1;
|
|
8185
8277
|
const st = statSync4(keyPath);
|
|
8186
8278
|
if (!st.isFile() || (st.mode & 63) !== 0) return false;
|
|
8279
|
+
const uid = typeof os13.userInfo().uid === "number" ? os13.userInfo().uid : -1;
|
|
8187
8280
|
if (uid === 0) return true;
|
|
8188
8281
|
const exeOsDir = process.env.EXE_OS_DIR;
|
|
8189
|
-
|
|
8282
|
+
if (exeOsDir && path22.resolve(keyPath).startsWith(path22.resolve(exeOsDir) + path22.sep)) return true;
|
|
8283
|
+
if (!linuxSecretAvailable()) return true;
|
|
8284
|
+
return false;
|
|
8190
8285
|
} catch {
|
|
8191
8286
|
return false;
|
|
8192
8287
|
}
|
|
@@ -8336,15 +8431,25 @@ async function writeMachineBoundFileFallback(b64) {
|
|
|
8336
8431
|
await mkdir4(dir, { recursive: true });
|
|
8337
8432
|
const keyPath = getKeyPath();
|
|
8338
8433
|
const machineKey = deriveMachineKey();
|
|
8339
|
-
|
|
8340
|
-
|
|
8341
|
-
|
|
8342
|
-
|
|
8343
|
-
|
|
8434
|
+
const content = machineKey ? encryptWithMachineKey(b64, machineKey) + "\n" : b64 + "\n";
|
|
8435
|
+
const result = machineKey ? "encrypted" : "plaintext";
|
|
8436
|
+
const tmpPath = keyPath + ".tmp";
|
|
8437
|
+
try {
|
|
8438
|
+
if (existsSync19(keyPath)) {
|
|
8439
|
+
await copyFile(keyPath, keyPath + ".bak").catch(() => {
|
|
8440
|
+
});
|
|
8441
|
+
}
|
|
8442
|
+
await writeFile5(tmpPath, content, "utf-8");
|
|
8443
|
+
await chmod2(tmpPath, 384);
|
|
8444
|
+
await rename(tmpPath, keyPath);
|
|
8445
|
+
} catch (err) {
|
|
8446
|
+
try {
|
|
8447
|
+
await unlink(tmpPath);
|
|
8448
|
+
} catch {
|
|
8449
|
+
}
|
|
8450
|
+
throw err;
|
|
8344
8451
|
}
|
|
8345
|
-
|
|
8346
|
-
await chmod2(keyPath, 384);
|
|
8347
|
-
return "plaintext";
|
|
8452
|
+
return result;
|
|
8348
8453
|
}
|
|
8349
8454
|
async function getMasterKey() {
|
|
8350
8455
|
let nativeValue = macKeychainGet() ?? linuxSecretGet();
|
|
@@ -8411,7 +8516,7 @@ async function getMasterKey() {
|
|
|
8411
8516
|
b64Value = content;
|
|
8412
8517
|
}
|
|
8413
8518
|
const key = Buffer.from(b64Value, "base64");
|
|
8414
|
-
if (
|
|
8519
|
+
if (isRootOnlyTrustedServerKeyFile(keyPath)) {
|
|
8415
8520
|
return key;
|
|
8416
8521
|
}
|
|
8417
8522
|
const migrated = macKeychainSet(b64Value) || linuxSecretSet(b64Value);
|
|
@@ -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());
|
|
@@ -422,6 +435,7 @@ __export(agent_config_exports, {
|
|
|
422
435
|
clearAgentRuntime: () => clearAgentRuntime,
|
|
423
436
|
getAgentRuntime: () => getAgentRuntime,
|
|
424
437
|
loadAgentConfig: () => loadAgentConfig,
|
|
438
|
+
normalizeCcModelName: () => normalizeCcModelName,
|
|
425
439
|
saveAgentConfig: () => saveAgentConfig,
|
|
426
440
|
setAgentMcps: () => setAgentMcps,
|
|
427
441
|
setAgentRuntime: () => setAgentRuntime
|
|
@@ -450,6 +464,13 @@ function getAgentRuntime(agentId) {
|
|
|
450
464
|
if (orgDefault) return orgDefault;
|
|
451
465
|
return { runtime: DEFAULT_RUNTIME, model: DEFAULT_MODELS[DEFAULT_RUNTIME] };
|
|
452
466
|
}
|
|
467
|
+
function normalizeCcModelName(model) {
|
|
468
|
+
let ccModel = model.replace(/(\d+)\.(\d+)/g, "$1-$2");
|
|
469
|
+
if (/claude-(opus|sonnet)-4-[6-9]/.test(ccModel) && !ccModel.includes("[1m]")) {
|
|
470
|
+
ccModel += "[1m]";
|
|
471
|
+
}
|
|
472
|
+
return ccModel;
|
|
473
|
+
}
|
|
453
474
|
function setAgentRuntime(agentId, runtime, model, reasoning_effort, mcps) {
|
|
454
475
|
const knownModels = KNOWN_RUNTIMES[runtime];
|
|
455
476
|
if (!knownModels) {
|
|
@@ -3741,7 +3762,7 @@ var init_database = __esm({
|
|
|
3741
3762
|
});
|
|
3742
3763
|
|
|
3743
3764
|
// src/lib/keychain.ts
|
|
3744
|
-
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2 } from "fs/promises";
|
|
3765
|
+
import { readFile as readFile3, writeFile as writeFile3, unlink, mkdir as mkdir3, chmod as chmod2, rename, copyFile } from "fs/promises";
|
|
3745
3766
|
import { existsSync as existsSync8, statSync as statSync3 } from "fs";
|
|
3746
3767
|
import { execSync as execSync3 } from "child_process";
|
|
3747
3768
|
import path7 from "path";
|
|
@@ -3776,12 +3797,14 @@ function linuxSecretAvailable() {
|
|
|
3776
3797
|
function isRootOnlyTrustedServerKeyFile(keyPath) {
|
|
3777
3798
|
if (process.platform !== "linux") return false;
|
|
3778
3799
|
try {
|
|
3779
|
-
const uid = typeof os5.userInfo().uid === "number" ? os5.userInfo().uid : -1;
|
|
3780
3800
|
const st = statSync3(keyPath);
|
|
3781
3801
|
if (!st.isFile() || (st.mode & 63) !== 0) return false;
|
|
3802
|
+
const uid = typeof os5.userInfo().uid === "number" ? os5.userInfo().uid : -1;
|
|
3782
3803
|
if (uid === 0) return true;
|
|
3783
3804
|
const exeOsDir = process.env.EXE_OS_DIR;
|
|
3784
|
-
|
|
3805
|
+
if (exeOsDir && path7.resolve(keyPath).startsWith(path7.resolve(exeOsDir) + path7.sep)) return true;
|
|
3806
|
+
if (!linuxSecretAvailable()) return true;
|
|
3807
|
+
return false;
|
|
3785
3808
|
} catch {
|
|
3786
3809
|
return false;
|
|
3787
3810
|
}
|
|
@@ -3931,15 +3954,25 @@ async function writeMachineBoundFileFallback(b64) {
|
|
|
3931
3954
|
await mkdir3(dir, { recursive: true });
|
|
3932
3955
|
const keyPath = getKeyPath();
|
|
3933
3956
|
const machineKey = deriveMachineKey();
|
|
3934
|
-
|
|
3935
|
-
|
|
3936
|
-
|
|
3937
|
-
|
|
3938
|
-
|
|
3957
|
+
const content = machineKey ? encryptWithMachineKey(b64, machineKey) + "\n" : b64 + "\n";
|
|
3958
|
+
const result = machineKey ? "encrypted" : "plaintext";
|
|
3959
|
+
const tmpPath = keyPath + ".tmp";
|
|
3960
|
+
try {
|
|
3961
|
+
if (existsSync8(keyPath)) {
|
|
3962
|
+
await copyFile(keyPath, keyPath + ".bak").catch(() => {
|
|
3963
|
+
});
|
|
3964
|
+
}
|
|
3965
|
+
await writeFile3(tmpPath, content, "utf-8");
|
|
3966
|
+
await chmod2(tmpPath, 384);
|
|
3967
|
+
await rename(tmpPath, keyPath);
|
|
3968
|
+
} catch (err) {
|
|
3969
|
+
try {
|
|
3970
|
+
await unlink(tmpPath);
|
|
3971
|
+
} catch {
|
|
3972
|
+
}
|
|
3973
|
+
throw err;
|
|
3939
3974
|
}
|
|
3940
|
-
|
|
3941
|
-
await chmod2(keyPath, 384);
|
|
3942
|
-
return "plaintext";
|
|
3975
|
+
return result;
|
|
3943
3976
|
}
|
|
3944
3977
|
async function getMasterKey() {
|
|
3945
3978
|
let nativeValue = macKeychainGet() ?? linuxSecretGet();
|
|
@@ -4006,7 +4039,7 @@ async function getMasterKey() {
|
|
|
4006
4039
|
b64Value = content;
|
|
4007
4040
|
}
|
|
4008
4041
|
const key = Buffer.from(b64Value, "base64");
|
|
4009
|
-
if (
|
|
4042
|
+
if (isRootOnlyTrustedServerKeyFile(keyPath)) {
|
|
4010
4043
|
return key;
|
|
4011
4044
|
}
|
|
4012
4045
|
const migrated = macKeychainSet(b64Value) || linuxSecretSet(b64Value);
|
|
@@ -8583,6 +8616,21 @@ function isRootSession(name) {
|
|
|
8583
8616
|
function extractRootExe(name) {
|
|
8584
8617
|
if (!name) return null;
|
|
8585
8618
|
if (!name.includes("-")) return name;
|
|
8619
|
+
try {
|
|
8620
|
+
const roster = (init_employees(), __toCommonJS(employees_exports)).loadEmployeesSync();
|
|
8621
|
+
if (roster.length > 0) {
|
|
8622
|
+
const sortedNames = roster.map((e) => e.name).sort((a, b) => b.length - a.length);
|
|
8623
|
+
for (const agentName of sortedNames) {
|
|
8624
|
+
const escaped = agentName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
8625
|
+
const regex = new RegExp(`^${escaped}\\d*-(.+)$`);
|
|
8626
|
+
const match = name.match(regex);
|
|
8627
|
+
if (match) {
|
|
8628
|
+
return extractRootExe(match[1]);
|
|
8629
|
+
}
|
|
8630
|
+
}
|
|
8631
|
+
}
|
|
8632
|
+
} catch {
|
|
8633
|
+
}
|
|
8586
8634
|
const parts = name.split("-").filter(Boolean);
|
|
8587
8635
|
return parts.length > 0 ? parts[parts.length - 1] : null;
|
|
8588
8636
|
}
|
|
@@ -8601,6 +8649,10 @@ function registerParentExe(sessionKey, parentExe, dispatchedBy) {
|
|
|
8601
8649
|
function getParentExe(sessionKey) {
|
|
8602
8650
|
try {
|
|
8603
8651
|
const data = JSON.parse(readFileSync11(path18.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
|
|
8652
|
+
if (data.registeredAt) {
|
|
8653
|
+
const age = Date.now() - new Date(data.registeredAt).getTime();
|
|
8654
|
+
if (age > PARENT_EXE_CACHE_TTL_MS) return null;
|
|
8655
|
+
}
|
|
8604
8656
|
return data.parentExe || null;
|
|
8605
8657
|
} catch {
|
|
8606
8658
|
return null;
|
|
@@ -8673,7 +8725,7 @@ function resolveExeSession() {
|
|
|
8673
8725
|
}
|
|
8674
8726
|
return candidate;
|
|
8675
8727
|
}
|
|
8676
|
-
var SPAWN_LOCK_DIR, SESSION_CACHE, INTERCOM_LOG2, DEBOUNCE_FILE, DEBOUNCE_CLEANUP_AGE_MS;
|
|
8728
|
+
var SPAWN_LOCK_DIR, SESSION_CACHE, PARENT_EXE_CACHE_TTL_MS, INTERCOM_LOG2, DEBOUNCE_FILE, DEBOUNCE_CLEANUP_AGE_MS;
|
|
8677
8729
|
var init_tmux_routing = __esm({
|
|
8678
8730
|
"src/lib/tmux-routing.ts"() {
|
|
8679
8731
|
"use strict";
|
|
@@ -8691,6 +8743,7 @@ var init_tmux_routing = __esm({
|
|
|
8691
8743
|
init_agent_symlinks();
|
|
8692
8744
|
SPAWN_LOCK_DIR = path18.join(os10.homedir(), ".exe-os", "spawn-locks");
|
|
8693
8745
|
SESSION_CACHE = path18.join(os10.homedir(), ".exe-os", "session-cache");
|
|
8746
|
+
PARENT_EXE_CACHE_TTL_MS = 4 * 60 * 60 * 1e3;
|
|
8694
8747
|
INTERCOM_LOG2 = path18.join(os10.homedir(), ".exe-os", "intercom.log");
|
|
8695
8748
|
DEBOUNCE_FILE = path18.join(SESSION_CACHE, "intercom-debounce.json");
|
|
8696
8749
|
DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
|