@askexenow/exe-os 0.9.114 → 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 +13 -1
- package/dist/bin/agentic-reflection-backfill.js +13 -1
- package/dist/bin/agentic-semantic-label.js +13 -1
- package/dist/bin/backfill-conversations.js +13 -1
- package/dist/bin/backfill-responses.js +13 -1
- package/dist/bin/backfill-vectors.js +13 -1
- package/dist/bin/bulk-sync-postgres.js +13 -1
- package/dist/bin/cleanup-stale-review-tasks.js +449 -104
- package/dist/bin/cli.js +317 -40
- package/dist/bin/exe-assign.js +13 -1
- package/dist/bin/exe-boot.js +202 -39
- package/dist/bin/exe-cloud.js +13 -1
- package/dist/bin/exe-dispatch.js +315 -38
- package/dist/bin/exe-doctor.js +28 -2
- package/dist/bin/exe-export-behaviors.js +14 -1
- package/dist/bin/exe-forget.js +13 -1
- package/dist/bin/exe-gateway.js +315 -38
- package/dist/bin/exe-heartbeat.js +450 -104
- package/dist/bin/exe-kill.js +13 -1
- package/dist/bin/exe-launch-agent.js +14 -1
- package/dist/bin/exe-pending-messages.js +429 -84
- package/dist/bin/exe-pending-notifications.js +429 -84
- package/dist/bin/exe-pending-reviews.js +429 -84
- package/dist/bin/exe-rename.js +13 -1
- package/dist/bin/exe-review.js +13 -1
- package/dist/bin/exe-search.js +14 -1
- package/dist/bin/exe-session-cleanup.js +315 -38
- package/dist/bin/exe-settings.js +12 -0
- package/dist/bin/exe-start-codex.js +14 -1
- package/dist/bin/exe-start-opencode.js +14 -1
- package/dist/bin/exe-status.js +439 -105
- package/dist/bin/exe-support.js +12 -0
- package/dist/bin/exe-team.js +13 -1
- package/dist/bin/git-sweep.js +315 -38
- package/dist/bin/graph-backfill.js +13 -1
- package/dist/bin/graph-export.js +13 -1
- package/dist/bin/intercom-check.js +222 -38
- package/dist/bin/scan-tasks.js +315 -38
- package/dist/bin/setup.js +14 -1
- package/dist/bin/shard-migrate.js +13 -1
- package/dist/gateway/index.js +315 -38
- package/dist/hooks/bug-report-worker.js +315 -38
- package/dist/hooks/codex-stop-task-finalizer.js +277 -26
- package/dist/hooks/commit-complete.js +315 -38
- package/dist/hooks/error-recall.js +14 -1
- package/dist/hooks/ingest.js +330 -39
- package/dist/hooks/instructions-loaded.js +13 -1
- package/dist/hooks/notification.js +13 -1
- package/dist/hooks/post-compact.js +403 -61
- package/dist/hooks/post-tool-combined.js +480 -137
- package/dist/hooks/pre-compact.js +315 -38
- package/dist/hooks/pre-tool-use.js +34 -2
- package/dist/hooks/prompt-submit.js +315 -38
- package/dist/hooks/session-end.js +125 -38
- package/dist/hooks/session-start.js +35 -2
- package/dist/hooks/stop.js +397 -61
- package/dist/hooks/subagent-stop.js +396 -61
- package/dist/hooks/summary-worker.js +410 -112
- package/dist/index.js +315 -38
- package/dist/lib/cloud-sync.js +1 -1
- package/dist/lib/config.js +13 -0
- package/dist/lib/embedder.js +13 -0
- package/dist/lib/exe-daemon.js +351 -44
- package/dist/lib/hybrid-search.js +14 -1
- package/dist/lib/keychain.js +1 -1
- package/dist/lib/messaging.js +395 -74
- package/dist/lib/schedules.js +13 -1
- package/dist/lib/skill-learning.js +13 -0
- package/dist/lib/store.js +13 -1
- package/dist/lib/tasks.js +314 -37
- package/dist/lib/tmux-routing.js +314 -37
- package/dist/mcp/server.js +331 -40
- package/dist/mcp/tools/create-task.js +314 -37
- 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 +314 -37
- package/dist/runtime/index.js +315 -38
- package/dist/tui/App.js +317 -40
- package/package.json +1 -1
package/dist/bin/exe-boot.js
CHANGED
|
@@ -155,6 +155,17 @@ function normalizeOrchestration(raw) {
|
|
|
155
155
|
const userOrg = raw.orchestration ?? {};
|
|
156
156
|
raw.orchestration = { ...defaultOrg, ...userOrg };
|
|
157
157
|
}
|
|
158
|
+
function normalizeCloudEndpoint(raw) {
|
|
159
|
+
const cloud = raw.cloud;
|
|
160
|
+
if (!cloud?.endpoint) return;
|
|
161
|
+
const ep = String(cloud.endpoint);
|
|
162
|
+
if (ep === "https://askexe.com/cloud" || ep === "https://askexe.com/cloud/") {
|
|
163
|
+
cloud.endpoint = "https://cloud.askexe.com";
|
|
164
|
+
process.stderr.write(
|
|
165
|
+
"[config] Auto-migrated cloud endpoint: askexe.com/cloud \u2192 cloud.askexe.com\n"
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
158
169
|
async function loadConfig() {
|
|
159
170
|
const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
|
|
160
171
|
await ensurePrivateDir(dir);
|
|
@@ -180,6 +191,7 @@ async function loadConfig() {
|
|
|
180
191
|
normalizeSessionLifecycle(migratedCfg);
|
|
181
192
|
normalizeAutoUpdate(migratedCfg);
|
|
182
193
|
normalizeOrchestration(migratedCfg);
|
|
194
|
+
normalizeCloudEndpoint(migratedCfg);
|
|
183
195
|
const config = { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db"), ...migratedCfg };
|
|
184
196
|
if (config.dbPath.startsWith("~")) {
|
|
185
197
|
config.dbPath = config.dbPath.replace(/^~/, os.homedir());
|
|
@@ -208,6 +220,7 @@ function loadConfigSync() {
|
|
|
208
220
|
normalizeSessionLifecycle(migratedCfg);
|
|
209
221
|
normalizeAutoUpdate(migratedCfg);
|
|
210
222
|
normalizeOrchestration(migratedCfg);
|
|
223
|
+
normalizeCloudEndpoint(migratedCfg);
|
|
211
224
|
const config = { ...DEFAULT_CONFIG, dbPath: path.join(dir, "memories.db"), ...migratedCfg };
|
|
212
225
|
if (config.dbPath.startsWith("~")) {
|
|
213
226
|
config.dbPath = config.dbPath.replace(/^~/, os.homedir());
|
|
@@ -4345,7 +4358,7 @@ async function getMasterKey() {
|
|
|
4345
4358
|
b64Value = content;
|
|
4346
4359
|
}
|
|
4347
4360
|
const key = Buffer.from(b64Value, "base64");
|
|
4348
|
-
if (
|
|
4361
|
+
if (isRootOnlyTrustedServerKeyFile(keyPath)) {
|
|
4349
4362
|
return key;
|
|
4350
4363
|
}
|
|
4351
4364
|
const migrated = macKeychainSet(b64Value) || linuxSecretSet(b64Value);
|
|
@@ -5532,6 +5545,7 @@ var init_provider_table = __esm({
|
|
|
5532
5545
|
// src/lib/intercom-queue.ts
|
|
5533
5546
|
var intercom_queue_exports = {};
|
|
5534
5547
|
__export(intercom_queue_exports, {
|
|
5548
|
+
_resetDrainGuard: () => _resetDrainGuard,
|
|
5535
5549
|
clearQueueForAgent: () => clearQueueForAgent,
|
|
5536
5550
|
drainForSession: () => drainForSession,
|
|
5537
5551
|
drainQueue: () => drainQueue,
|
|
@@ -5577,38 +5591,47 @@ function queueIntercom(targetSession, reason) {
|
|
|
5577
5591
|
writeQueue(queue);
|
|
5578
5592
|
}
|
|
5579
5593
|
function drainQueue(isSessionBusy2, sendKeys) {
|
|
5594
|
+
if (_draining) {
|
|
5595
|
+
logQueue("SKIP_DRAIN \u2014 previous drain still running (possible tmux hang)");
|
|
5596
|
+
return { drained: 0, failed: 0 };
|
|
5597
|
+
}
|
|
5580
5598
|
const queue = readQueue();
|
|
5581
5599
|
if (queue.length === 0) return { drained: 0, failed: 0 };
|
|
5600
|
+
_draining = true;
|
|
5582
5601
|
const remaining = [];
|
|
5583
5602
|
let drained = 0;
|
|
5584
5603
|
let failed = 0;
|
|
5585
|
-
|
|
5586
|
-
const
|
|
5587
|
-
|
|
5588
|
-
|
|
5589
|
-
|
|
5590
|
-
|
|
5591
|
-
|
|
5592
|
-
|
|
5593
|
-
|
|
5594
|
-
|
|
5595
|
-
|
|
5596
|
-
|
|
5597
|
-
|
|
5598
|
-
|
|
5604
|
+
try {
|
|
5605
|
+
for (const item of queue) {
|
|
5606
|
+
const age = Date.now() - new Date(item.queuedAt).getTime();
|
|
5607
|
+
if (age > TTL_MS) {
|
|
5608
|
+
logQueue(`EXPIRED \u2192 ${item.targetSession} (${Math.round(age / 6e4)}min old, reason: ${item.reason})`);
|
|
5609
|
+
failed++;
|
|
5610
|
+
continue;
|
|
5611
|
+
}
|
|
5612
|
+
try {
|
|
5613
|
+
if (!isSessionBusy2(item.targetSession)) {
|
|
5614
|
+
const success = sendKeys(item.targetSession);
|
|
5615
|
+
if (success) {
|
|
5616
|
+
logQueue(`DRAINED \u2192 ${item.targetSession} (after ${item.attempts} retries)`);
|
|
5617
|
+
drained++;
|
|
5618
|
+
continue;
|
|
5619
|
+
}
|
|
5599
5620
|
}
|
|
5621
|
+
} catch {
|
|
5600
5622
|
}
|
|
5601
|
-
|
|
5602
|
-
|
|
5603
|
-
|
|
5604
|
-
|
|
5605
|
-
|
|
5606
|
-
|
|
5607
|
-
|
|
5623
|
+
item.attempts++;
|
|
5624
|
+
if (item.attempts >= MAX_RETRIES2) {
|
|
5625
|
+
logQueue(`FAILED \u2192 ${item.targetSession} (${MAX_RETRIES2} retries exhausted, reason: ${item.reason})`);
|
|
5626
|
+
failed++;
|
|
5627
|
+
continue;
|
|
5628
|
+
}
|
|
5629
|
+
remaining.push(item);
|
|
5608
5630
|
}
|
|
5609
|
-
remaining
|
|
5631
|
+
writeQueue(remaining);
|
|
5632
|
+
} finally {
|
|
5633
|
+
_draining = false;
|
|
5610
5634
|
}
|
|
5611
|
-
writeQueue(remaining);
|
|
5612
5635
|
return { drained, failed };
|
|
5613
5636
|
}
|
|
5614
5637
|
function drainForSession(targetSession, sendKeys) {
|
|
@@ -5633,6 +5656,9 @@ function clearQueueForAgent(agentName) {
|
|
|
5633
5656
|
logQueue(`CLEARED ${before - filtered.length} stale item(s) for ${agentName}`);
|
|
5634
5657
|
}
|
|
5635
5658
|
}
|
|
5659
|
+
function _resetDrainGuard() {
|
|
5660
|
+
_draining = false;
|
|
5661
|
+
}
|
|
5636
5662
|
function logQueue(msg) {
|
|
5637
5663
|
const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] [queue] ${msg}
|
|
5638
5664
|
`;
|
|
@@ -5644,13 +5670,14 @@ function logQueue(msg) {
|
|
|
5644
5670
|
} catch {
|
|
5645
5671
|
}
|
|
5646
5672
|
}
|
|
5647
|
-
var QUEUE_PATH, MAX_RETRIES2, TTL_MS, INTERCOM_LOG;
|
|
5673
|
+
var QUEUE_PATH, MAX_RETRIES2, TTL_MS, _draining, INTERCOM_LOG;
|
|
5648
5674
|
var init_intercom_queue = __esm({
|
|
5649
5675
|
"src/lib/intercom-queue.ts"() {
|
|
5650
5676
|
"use strict";
|
|
5651
5677
|
QUEUE_PATH = path10.join(os7.homedir(), ".exe-os", "intercom-queue.json");
|
|
5652
5678
|
MAX_RETRIES2 = 5;
|
|
5653
5679
|
TTL_MS = 60 * 60 * 1e3;
|
|
5680
|
+
_draining = false;
|
|
5654
5681
|
INTERCOM_LOG = path10.join(os7.homedir(), ".exe-os", "intercom.log");
|
|
5655
5682
|
}
|
|
5656
5683
|
});
|
|
@@ -6265,6 +6292,17 @@ var init_agent_symlinks = __esm({
|
|
|
6265
6292
|
});
|
|
6266
6293
|
|
|
6267
6294
|
// src/lib/notifications.ts
|
|
6295
|
+
var notifications_exports = {};
|
|
6296
|
+
__export(notifications_exports, {
|
|
6297
|
+
cleanupOldNotifications: () => cleanupOldNotifications,
|
|
6298
|
+
formatNotifications: () => formatNotifications,
|
|
6299
|
+
markAsRead: () => markAsRead,
|
|
6300
|
+
markAsReadByTaskFile: () => markAsReadByTaskFile,
|
|
6301
|
+
markDoneTaskNotificationsAsRead: () => markDoneTaskNotificationsAsRead,
|
|
6302
|
+
migrateJsonNotifications: () => migrateJsonNotifications,
|
|
6303
|
+
readUnreadNotifications: () => readUnreadNotifications,
|
|
6304
|
+
writeNotification: () => writeNotification
|
|
6305
|
+
});
|
|
6268
6306
|
import crypto2 from "crypto";
|
|
6269
6307
|
import path14 from "path";
|
|
6270
6308
|
import os10 from "os";
|
|
@@ -6394,6 +6432,29 @@ async function markDoneTaskNotificationsAsRead(sessionScope) {
|
|
|
6394
6432
|
return 0;
|
|
6395
6433
|
}
|
|
6396
6434
|
}
|
|
6435
|
+
function formatNotifications(notifications) {
|
|
6436
|
+
if (notifications.length === 0) return "";
|
|
6437
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
6438
|
+
for (const n of notifications) {
|
|
6439
|
+
const key = `${n.agentId}|${n.agentRole}`;
|
|
6440
|
+
if (!grouped.has(key)) grouped.set(key, []);
|
|
6441
|
+
grouped.get(key).push(n);
|
|
6442
|
+
}
|
|
6443
|
+
const lines = [];
|
|
6444
|
+
lines.push(`## Notifications (${notifications.length} unread)
|
|
6445
|
+
`);
|
|
6446
|
+
for (const [key, items] of grouped) {
|
|
6447
|
+
const [agentId, agentRole] = key.split("|");
|
|
6448
|
+
lines.push(`**${agentId}** (${agentRole}):`);
|
|
6449
|
+
for (const item of items) {
|
|
6450
|
+
const ago = formatTimeAgo(item.timestamp);
|
|
6451
|
+
const icon = eventIcon(item.event);
|
|
6452
|
+
lines.push(`- ${icon} ${item.summary} (${item.project}) \u2014 ${ago}`);
|
|
6453
|
+
}
|
|
6454
|
+
lines.push("");
|
|
6455
|
+
}
|
|
6456
|
+
return lines.join("\n");
|
|
6457
|
+
}
|
|
6397
6458
|
async function migrateJsonNotifications() {
|
|
6398
6459
|
const base = process.env.EXE_OS_DIR || process.env.EXE_MEM_DIR || path14.join(os10.homedir(), ".exe-os");
|
|
6399
6460
|
const notifDir = path14.join(base, "notifications");
|
|
@@ -6439,6 +6500,34 @@ async function migrateJsonNotifications() {
|
|
|
6439
6500
|
}
|
|
6440
6501
|
return migrated;
|
|
6441
6502
|
}
|
|
6503
|
+
function eventIcon(event) {
|
|
6504
|
+
switch (event) {
|
|
6505
|
+
case "task_complete":
|
|
6506
|
+
return "Completed:";
|
|
6507
|
+
case "task_needs_fix":
|
|
6508
|
+
return "Needs fix:";
|
|
6509
|
+
case "session_summary":
|
|
6510
|
+
return "Session:";
|
|
6511
|
+
case "error_spike":
|
|
6512
|
+
return "Errors:";
|
|
6513
|
+
case "orphan_task":
|
|
6514
|
+
return "Orphan:";
|
|
6515
|
+
case "subtasks_complete":
|
|
6516
|
+
return "Subtasks done:";
|
|
6517
|
+
case "capacity_relaunch":
|
|
6518
|
+
return "Relaunched:";
|
|
6519
|
+
}
|
|
6520
|
+
}
|
|
6521
|
+
function formatTimeAgo(timestamp) {
|
|
6522
|
+
const diffMs = Date.now() - new Date(timestamp).getTime();
|
|
6523
|
+
const mins = Math.floor(diffMs / 6e4);
|
|
6524
|
+
if (mins < 1) return "just now";
|
|
6525
|
+
if (mins < 60) return `${mins}m ago`;
|
|
6526
|
+
const hours = Math.floor(mins / 60);
|
|
6527
|
+
if (hours < 24) return `${hours}h ago`;
|
|
6528
|
+
const days = Math.floor(hours / 24);
|
|
6529
|
+
return `${days}d ago`;
|
|
6530
|
+
}
|
|
6442
6531
|
var CLEANUP_DAYS;
|
|
6443
6532
|
var init_notifications = __esm({
|
|
6444
6533
|
"src/lib/notifications.ts"() {
|
|
@@ -7515,7 +7604,13 @@ async function createReviewForCompletedTask(row, result, _baseDir, now) {
|
|
|
7515
7604
|
taskFile
|
|
7516
7605
|
});
|
|
7517
7606
|
const originalPriority = String(row.priority).toLowerCase();
|
|
7518
|
-
const
|
|
7607
|
+
const resultLower = result?.toLowerCase() ?? "";
|
|
7608
|
+
const hasTestEvidence = (
|
|
7609
|
+
// Vitest/Jest output patterns (hard to fake without actually running tests)
|
|
7610
|
+
/\d+\s+pass(ed|ing)/.test(resultLower) || /test files?\s+\d+\s+passed/.test(resultLower) || /tests?\s+\d+\s+passed/.test(resultLower)
|
|
7611
|
+
);
|
|
7612
|
+
const hasNoFailures = !/fail(ed|ure|ing)|error/i.test(resultLower);
|
|
7613
|
+
const autoApprove = originalPriority === "p2" && hasTestEvidence && hasNoFailures;
|
|
7519
7614
|
if (!autoApprove) {
|
|
7520
7615
|
try {
|
|
7521
7616
|
const key = getSessionKey();
|
|
@@ -7523,6 +7618,13 @@ async function createReviewForCompletedTask(row, result, _baseDir, now) {
|
|
|
7523
7618
|
if (exeSession) {
|
|
7524
7619
|
sendIntercom(exeSession);
|
|
7525
7620
|
}
|
|
7621
|
+
if (reviewer && reviewer !== coordinatorName && reviewer !== exeSession) {
|
|
7622
|
+
const { employeeSessionName: employeeSessionName2 } = await Promise.resolve().then(() => (init_tmux_routing(), tmux_routing_exports));
|
|
7623
|
+
if (exeSession) {
|
|
7624
|
+
const reviewerSession = employeeSessionName2(reviewer, exeSession);
|
|
7625
|
+
sendIntercom(reviewerSession);
|
|
7626
|
+
}
|
|
7627
|
+
}
|
|
7526
7628
|
} catch {
|
|
7527
7629
|
}
|
|
7528
7630
|
}
|
|
@@ -8298,6 +8400,20 @@ async function updateTask(input) {
|
|
|
8298
8400
|
notifyTaskDone();
|
|
8299
8401
|
}
|
|
8300
8402
|
await markTaskNotificationsRead(taskFile);
|
|
8403
|
+
if (input.status === "needs_review" && !isCoordinator) {
|
|
8404
|
+
try {
|
|
8405
|
+
const { writeNotification: writeNotification2 } = await Promise.resolve().then(() => (init_notifications(), notifications_exports));
|
|
8406
|
+
await writeNotification2({
|
|
8407
|
+
agentId: String(row.assigned_to),
|
|
8408
|
+
agentRole: String(row.assigned_to),
|
|
8409
|
+
event: "task_complete",
|
|
8410
|
+
project: String(row.project_name),
|
|
8411
|
+
summary: `"${String(row.title)}" is ready for review`,
|
|
8412
|
+
taskFile
|
|
8413
|
+
});
|
|
8414
|
+
} catch {
|
|
8415
|
+
}
|
|
8416
|
+
}
|
|
8301
8417
|
if (input.status === "done" || input.status === "closed") {
|
|
8302
8418
|
try {
|
|
8303
8419
|
await cascadeUnblock(taskId, input.baseDir, now);
|
|
@@ -8730,18 +8846,31 @@ function acquireSpawnLock2(sessionName) {
|
|
|
8730
8846
|
mkdirSync9(SPAWN_LOCK_DIR, { recursive: true });
|
|
8731
8847
|
}
|
|
8732
8848
|
const lockFile = spawnLockPath(sessionName);
|
|
8733
|
-
|
|
8734
|
-
|
|
8735
|
-
|
|
8736
|
-
|
|
8737
|
-
|
|
8738
|
-
|
|
8739
|
-
|
|
8740
|
-
|
|
8849
|
+
const lockData = JSON.stringify({ pid: process.pid, timestamp: Date.now() });
|
|
8850
|
+
const { openSync: openSync4, closeSync: closeSync4, writeSync } = __require("fs");
|
|
8851
|
+
const { constants: constants2 } = __require("fs");
|
|
8852
|
+
try {
|
|
8853
|
+
const fd = openSync4(lockFile, constants2.O_WRONLY | constants2.O_CREAT | constants2.O_EXCL, 420);
|
|
8854
|
+
writeSync(fd, lockData);
|
|
8855
|
+
closeSync4(fd);
|
|
8856
|
+
return true;
|
|
8857
|
+
} catch (err) {
|
|
8858
|
+
if (err?.code !== "EEXIST") {
|
|
8859
|
+
return true;
|
|
8741
8860
|
}
|
|
8742
8861
|
}
|
|
8743
|
-
|
|
8744
|
-
|
|
8862
|
+
try {
|
|
8863
|
+
const lock = JSON.parse(readFileSync12(lockFile, "utf8"));
|
|
8864
|
+
const age = Date.now() - lock.timestamp;
|
|
8865
|
+
if (isProcessAlive(lock.pid) && age < 6e4) {
|
|
8866
|
+
return false;
|
|
8867
|
+
}
|
|
8868
|
+
writeFileSync8(lockFile, lockData);
|
|
8869
|
+
return true;
|
|
8870
|
+
} catch {
|
|
8871
|
+
writeFileSync8(lockFile, lockData);
|
|
8872
|
+
return true;
|
|
8873
|
+
}
|
|
8745
8874
|
}
|
|
8746
8875
|
function releaseSpawnLock2(sessionName) {
|
|
8747
8876
|
try {
|
|
@@ -8820,6 +8949,21 @@ function parseParentExe(sessionName, agentId) {
|
|
|
8820
8949
|
function extractRootExe(name) {
|
|
8821
8950
|
if (!name) return null;
|
|
8822
8951
|
if (!name.includes("-")) return name;
|
|
8952
|
+
try {
|
|
8953
|
+
const roster = (init_employees(), __toCommonJS(employees_exports)).loadEmployeesSync();
|
|
8954
|
+
if (roster.length > 0) {
|
|
8955
|
+
const sortedNames = roster.map((e) => e.name).sort((a, b) => b.length - a.length);
|
|
8956
|
+
for (const agentName of sortedNames) {
|
|
8957
|
+
const escaped = agentName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
8958
|
+
const regex = new RegExp(`^${escaped}\\d*-(.+)$`);
|
|
8959
|
+
const match = name.match(regex);
|
|
8960
|
+
if (match) {
|
|
8961
|
+
return extractRootExe(match[1]);
|
|
8962
|
+
}
|
|
8963
|
+
}
|
|
8964
|
+
}
|
|
8965
|
+
} catch {
|
|
8966
|
+
}
|
|
8823
8967
|
const parts = name.split("-").filter(Boolean);
|
|
8824
8968
|
return parts.length > 0 ? parts[parts.length - 1] : null;
|
|
8825
8969
|
}
|
|
@@ -8838,6 +8982,10 @@ function registerParentExe(sessionKey, parentExe, dispatchedBy) {
|
|
|
8838
8982
|
function getParentExe(sessionKey) {
|
|
8839
8983
|
try {
|
|
8840
8984
|
const data = JSON.parse(readFileSync12(path20.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`), "utf8"));
|
|
8985
|
+
if (data.registeredAt) {
|
|
8986
|
+
const age = Date.now() - new Date(data.registeredAt).getTime();
|
|
8987
|
+
if (age > PARENT_EXE_CACHE_TTL_MS) return null;
|
|
8988
|
+
}
|
|
8841
8989
|
return data.parentExe || null;
|
|
8842
8990
|
} catch {
|
|
8843
8991
|
return null;
|
|
@@ -9386,7 +9534,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
9386
9534
|
sessionContextFlag = ` --append-system-prompt-file ${ctxFile}`;
|
|
9387
9535
|
} catch {
|
|
9388
9536
|
}
|
|
9389
|
-
let envPrefix = `EXE_SESSION=${exeSession} EXE_SESSION_NAME=${sessionName}`;
|
|
9537
|
+
let envPrefix = `EXE_SESSION=${exeSession} EXE_SESSION_NAME=${sessionName} EXE_SESSION_START_ISO=${(/* @__PURE__ */ new Date()).toISOString()}`;
|
|
9390
9538
|
if (ccProvider !== DEFAULT_PROVIDER) {
|
|
9391
9539
|
const cfg = PROVIDER_TABLE[ccProvider];
|
|
9392
9540
|
if (cfg?.apiKeyEnv) {
|
|
@@ -9523,7 +9671,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
9523
9671
|
releaseSpawnLock2(sessionName);
|
|
9524
9672
|
return { sessionName };
|
|
9525
9673
|
}
|
|
9526
|
-
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;
|
|
9674
|
+
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;
|
|
9527
9675
|
var init_tmux_routing = __esm({
|
|
9528
9676
|
"src/lib/tmux-routing.ts"() {
|
|
9529
9677
|
"use strict";
|
|
@@ -9543,6 +9691,7 @@ var init_tmux_routing = __esm({
|
|
|
9543
9691
|
SESSION_CACHE = path20.join(os12.homedir(), ".exe-os", "session-cache");
|
|
9544
9692
|
BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
|
|
9545
9693
|
VALID_SESSION_NAME = /^[a-z]+\d*-[a-zA-Z0-9_]+$/;
|
|
9694
|
+
PARENT_EXE_CACHE_TTL_MS = 4 * 60 * 60 * 1e3;
|
|
9546
9695
|
VERIFY_PANE_LINES = 200;
|
|
9547
9696
|
INTERCOM_DEBOUNCE_MS = 3e4;
|
|
9548
9697
|
CODEX_DEBOUNCE_MS = 12e4;
|
|
@@ -9626,7 +9775,21 @@ function tryAcquireWorkerSlot() {
|
|
|
9626
9775
|
for (const f of files) {
|
|
9627
9776
|
if (!f.endsWith(".pid")) continue;
|
|
9628
9777
|
if (f.startsWith("res-")) {
|
|
9629
|
-
|
|
9778
|
+
const resParts = f.replace(".pid", "").split("-");
|
|
9779
|
+
const resPid = parseInt(resParts[1] ?? "", 10);
|
|
9780
|
+
if (!isNaN(resPid) && resPid > 0) {
|
|
9781
|
+
try {
|
|
9782
|
+
process.kill(resPid, 0);
|
|
9783
|
+
alive++;
|
|
9784
|
+
} catch {
|
|
9785
|
+
try {
|
|
9786
|
+
unlinkSync9(path22.join(WORKER_PID_DIR, f));
|
|
9787
|
+
} catch {
|
|
9788
|
+
}
|
|
9789
|
+
}
|
|
9790
|
+
} else {
|
|
9791
|
+
alive++;
|
|
9792
|
+
}
|
|
9630
9793
|
continue;
|
|
9631
9794
|
}
|
|
9632
9795
|
const dashIdx = f.lastIndexOf("-");
|
package/dist/bin/exe-cloud.js
CHANGED
|
@@ -302,7 +302,7 @@ async function getMasterKey() {
|
|
|
302
302
|
b64Value = content;
|
|
303
303
|
}
|
|
304
304
|
const key = Buffer.from(b64Value, "base64");
|
|
305
|
-
if (
|
|
305
|
+
if (isRootOnlyTrustedServerKeyFile(keyPath)) {
|
|
306
306
|
return key;
|
|
307
307
|
}
|
|
308
308
|
const migrated = macKeychainSet(b64Value) || linuxSecretSet(b64Value);
|
|
@@ -637,6 +637,17 @@ function normalizeOrchestration(raw) {
|
|
|
637
637
|
const userOrg = raw.orchestration ?? {};
|
|
638
638
|
raw.orchestration = { ...defaultOrg, ...userOrg };
|
|
639
639
|
}
|
|
640
|
+
function normalizeCloudEndpoint(raw) {
|
|
641
|
+
const cloud = raw.cloud;
|
|
642
|
+
if (!cloud?.endpoint) return;
|
|
643
|
+
const ep = String(cloud.endpoint);
|
|
644
|
+
if (ep === "https://askexe.com/cloud" || ep === "https://askexe.com/cloud/") {
|
|
645
|
+
cloud.endpoint = "https://cloud.askexe.com";
|
|
646
|
+
process.stderr.write(
|
|
647
|
+
"[config] Auto-migrated cloud endpoint: askexe.com/cloud \u2192 cloud.askexe.com\n"
|
|
648
|
+
);
|
|
649
|
+
}
|
|
650
|
+
}
|
|
640
651
|
async function loadConfig() {
|
|
641
652
|
const dir = process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? EXE_AI_DIR;
|
|
642
653
|
await ensurePrivateDir(dir);
|
|
@@ -662,6 +673,7 @@ async function loadConfig() {
|
|
|
662
673
|
normalizeSessionLifecycle(migratedCfg);
|
|
663
674
|
normalizeAutoUpdate(migratedCfg);
|
|
664
675
|
normalizeOrchestration(migratedCfg);
|
|
676
|
+
normalizeCloudEndpoint(migratedCfg);
|
|
665
677
|
const config = { ...DEFAULT_CONFIG, dbPath: path2.join(dir, "memories.db"), ...migratedCfg };
|
|
666
678
|
if (config.dbPath.startsWith("~")) {
|
|
667
679
|
config.dbPath = config.dbPath.replace(/^~/, os2.homedir());
|