@askexenow/exe-os 0.8.64 → 0.8.68
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/cleanup-stale-review-tasks.js +8 -7
- package/dist/bin/cli.js +215 -120
- package/dist/bin/exe-assign.js +11 -10
- package/dist/bin/exe-boot.js +83 -78
- package/dist/bin/exe-call.js +33 -1
- package/dist/bin/exe-cloud.js +3 -2
- package/dist/bin/exe-dispatch.js +31 -30
- package/dist/bin/exe-gateway.js +33 -32
- package/dist/bin/exe-heartbeat.js +21 -20
- package/dist/bin/exe-launch-agent.js +48 -16
- package/dist/bin/exe-link.js +16 -11
- package/dist/bin/exe-new-employee.js +20 -19
- package/dist/bin/exe-pending-messages.js +7 -6
- package/dist/bin/exe-pending-reviews.js +16 -15
- package/dist/bin/exe-rename.js +12 -11
- package/dist/bin/exe-review.js +4 -3
- package/dist/bin/exe-session-cleanup.js +20 -19
- package/dist/bin/exe-settings.js +3 -2
- package/dist/bin/exe-start.sh +2 -2
- package/dist/bin/exe-status.js +16 -15
- package/dist/bin/exe-team.js +4 -3
- package/dist/bin/git-sweep.js +31 -30
- package/dist/bin/install.js +284 -113
- package/dist/bin/scan-tasks.js +33 -32
- package/dist/bin/setup.js +114 -30
- package/dist/gateway/index.js +32 -31
- package/dist/hooks/bug-report-worker.js +58 -26
- package/dist/hooks/commit-complete.js +31 -30
- package/dist/hooks/ingest-worker.js +58 -57
- package/dist/hooks/post-compact.js +10 -9
- package/dist/hooks/pre-compact.js +31 -30
- package/dist/hooks/pre-tool-use.js +46 -14
- package/dist/hooks/prompt-ingest-worker.js +15 -14
- package/dist/hooks/prompt-submit.js +15 -14
- package/dist/hooks/response-ingest-worker.js +8 -7
- package/dist/hooks/session-end.js +14 -13
- package/dist/hooks/session-start.js +10 -9
- package/dist/hooks/stop.js +10 -9
- package/dist/hooks/subagent-stop.js +10 -9
- package/dist/hooks/summary-worker.js +41 -36
- package/dist/index.js +43 -42
- package/dist/lib/cloud-sync.js +16 -11
- package/dist/lib/employees.js +33 -1
- package/dist/lib/exe-daemon.js +56 -55
- package/dist/lib/messaging.js +9 -8
- package/dist/lib/tasks.js +27 -26
- package/dist/lib/tmux-routing.js +29 -28
- package/dist/mcp/server.js +94 -62
- package/dist/mcp/tools/create-task.js +60 -28
- package/dist/mcp/tools/list-tasks.js +10 -9
- package/dist/mcp/tools/send-message.js +11 -10
- package/dist/mcp/tools/update-task.js +21 -20
- package/dist/runtime/index.js +31 -30
- package/dist/tui/App.js +67 -35
- package/package.json +1 -1
package/dist/bin/scan-tasks.js
CHANGED
|
@@ -1438,9 +1438,10 @@ var init_config = __esm({
|
|
|
1438
1438
|
|
|
1439
1439
|
// src/lib/employees.ts
|
|
1440
1440
|
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
1441
|
-
import { existsSync as existsSync4, symlinkSync, readlinkSync, readFileSync as readFileSync4 } from "fs";
|
|
1441
|
+
import { existsSync as existsSync4, symlinkSync, readlinkSync, readFileSync as readFileSync4, renameSync as renameSync3, unlinkSync, writeFileSync as writeFileSync3 } from "fs";
|
|
1442
1442
|
import { execSync as execSync3 } from "child_process";
|
|
1443
1443
|
import path4 from "path";
|
|
1444
|
+
import os4 from "os";
|
|
1444
1445
|
function loadEmployeesSync(employeesPath = EMPLOYEES_PATH) {
|
|
1445
1446
|
if (!existsSync4(employeesPath)) return [];
|
|
1446
1447
|
try {
|
|
@@ -1469,7 +1470,7 @@ var init_employees = __esm({
|
|
|
1469
1470
|
});
|
|
1470
1471
|
|
|
1471
1472
|
// src/lib/license.ts
|
|
1472
|
-
import { readFileSync as readFileSync5, writeFileSync as
|
|
1473
|
+
import { readFileSync as readFileSync5, writeFileSync as writeFileSync4, existsSync as existsSync5, mkdirSync as mkdirSync3 } from "fs";
|
|
1473
1474
|
import { randomUUID } from "crypto";
|
|
1474
1475
|
import path5 from "path";
|
|
1475
1476
|
import { jwtVerify, importSPKI } from "jose";
|
|
@@ -1572,11 +1573,11 @@ var init_plan_limits = __esm({
|
|
|
1572
1573
|
// src/lib/notifications.ts
|
|
1573
1574
|
import crypto from "crypto";
|
|
1574
1575
|
import path7 from "path";
|
|
1575
|
-
import
|
|
1576
|
+
import os5 from "os";
|
|
1576
1577
|
import {
|
|
1577
1578
|
readFileSync as readFileSync7,
|
|
1578
1579
|
readdirSync,
|
|
1579
|
-
unlinkSync,
|
|
1580
|
+
unlinkSync as unlinkSync2,
|
|
1580
1581
|
existsSync as existsSync7,
|
|
1581
1582
|
rmdirSync
|
|
1582
1583
|
} from "fs";
|
|
@@ -2128,7 +2129,7 @@ var init_tasks_crud = __esm({
|
|
|
2128
2129
|
|
|
2129
2130
|
// src/lib/tasks-review.ts
|
|
2130
2131
|
import path9 from "path";
|
|
2131
|
-
import { existsSync as existsSync9, readdirSync as readdirSync2, unlinkSync as
|
|
2132
|
+
import { existsSync as existsSync9, readdirSync as readdirSync2, unlinkSync as unlinkSync3 } from "fs";
|
|
2132
2133
|
async function countPendingReviews(sessionScope) {
|
|
2133
2134
|
const client = getClient();
|
|
2134
2135
|
if (sessionScope) {
|
|
@@ -2313,7 +2314,7 @@ async function cleanupReviewFile(row, taskFile, _baseDir) {
|
|
|
2313
2314
|
if (existsSync9(cacheDir)) {
|
|
2314
2315
|
for (const f of readdirSync2(cacheDir)) {
|
|
2315
2316
|
if (f.startsWith("review-notified-")) {
|
|
2316
|
-
|
|
2317
|
+
unlinkSync3(path9.join(cacheDir, f));
|
|
2317
2318
|
}
|
|
2318
2319
|
}
|
|
2319
2320
|
}
|
|
@@ -2928,7 +2929,7 @@ __export(tasks_exports, {
|
|
|
2928
2929
|
writeCheckpoint: () => writeCheckpoint
|
|
2929
2930
|
});
|
|
2930
2931
|
import path12 from "path";
|
|
2931
|
-
import { writeFileSync as
|
|
2932
|
+
import { writeFileSync as writeFileSync5, mkdirSync as mkdirSync4, unlinkSync as unlinkSync4 } from "fs";
|
|
2932
2933
|
async function createTask(input) {
|
|
2933
2934
|
const result = await createTaskCore(input);
|
|
2934
2935
|
if (!input.skipDispatch && result.status !== "blocked" && !process.env.VITEST) {
|
|
@@ -2951,10 +2952,10 @@ async function updateTask(input) {
|
|
|
2951
2952
|
const cachePath = path12.join(cacheDir, `current-task-${agent}.json`);
|
|
2952
2953
|
if (input.status === "in_progress") {
|
|
2953
2954
|
mkdirSync4(cacheDir, { recursive: true });
|
|
2954
|
-
|
|
2955
|
+
writeFileSync5(cachePath, JSON.stringify({ taskId, title: String(row.title) }));
|
|
2955
2956
|
} else if (input.status === "done" || input.status === "blocked" || input.status === "cancelled") {
|
|
2956
2957
|
try {
|
|
2957
|
-
|
|
2958
|
+
unlinkSync4(cachePath);
|
|
2958
2959
|
} catch {
|
|
2959
2960
|
}
|
|
2960
2961
|
}
|
|
@@ -3396,11 +3397,11 @@ __export(tmux_routing_exports, {
|
|
|
3396
3397
|
verifyPaneAtCapacity: () => verifyPaneAtCapacity
|
|
3397
3398
|
});
|
|
3398
3399
|
import { execFileSync as execFileSync2, execSync as execSync6 } from "child_process";
|
|
3399
|
-
import { readFileSync as readFileSync9, writeFileSync as
|
|
3400
|
+
import { readFileSync as readFileSync9, writeFileSync as writeFileSync6, mkdirSync as mkdirSync5, existsSync as existsSync10, appendFileSync } from "fs";
|
|
3400
3401
|
import path13 from "path";
|
|
3401
|
-
import
|
|
3402
|
+
import os6 from "os";
|
|
3402
3403
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
3403
|
-
import { unlinkSync as
|
|
3404
|
+
import { unlinkSync as unlinkSync5 } from "fs";
|
|
3404
3405
|
function spawnLockPath(sessionName) {
|
|
3405
3406
|
return path13.join(SPAWN_LOCK_DIR, `${sessionName}.lock`);
|
|
3406
3407
|
}
|
|
@@ -3427,12 +3428,12 @@ function acquireSpawnLock(sessionName) {
|
|
|
3427
3428
|
} catch {
|
|
3428
3429
|
}
|
|
3429
3430
|
}
|
|
3430
|
-
|
|
3431
|
+
writeFileSync6(lockFile, JSON.stringify({ pid: process.pid, timestamp: Date.now() }));
|
|
3431
3432
|
return true;
|
|
3432
3433
|
}
|
|
3433
3434
|
function releaseSpawnLock(sessionName) {
|
|
3434
3435
|
try {
|
|
3435
|
-
|
|
3436
|
+
unlinkSync5(spawnLockPath(sessionName));
|
|
3436
3437
|
} catch {
|
|
3437
3438
|
}
|
|
3438
3439
|
}
|
|
@@ -3514,7 +3515,7 @@ function registerParentExe(sessionKey, parentExe, dispatchedBy) {
|
|
|
3514
3515
|
}
|
|
3515
3516
|
const rootExe = extractRootExe(parentExe) ?? parentExe;
|
|
3516
3517
|
const filePath = path13.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`);
|
|
3517
|
-
|
|
3518
|
+
writeFileSync6(filePath, JSON.stringify({
|
|
3518
3519
|
parentExe: rootExe,
|
|
3519
3520
|
dispatchedBy: dispatchedBy || rootExe,
|
|
3520
3521
|
registeredAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -3601,7 +3602,7 @@ function readDebounceState() {
|
|
|
3601
3602
|
function writeDebounceState(state) {
|
|
3602
3603
|
try {
|
|
3603
3604
|
if (!existsSync10(SESSION_CACHE)) mkdirSync5(SESSION_CACHE, { recursive: true });
|
|
3604
|
-
|
|
3605
|
+
writeFileSync6(DEBOUNCE_FILE, JSON.stringify(state));
|
|
3605
3606
|
} catch {
|
|
3606
3607
|
}
|
|
3607
3608
|
}
|
|
@@ -3790,7 +3791,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3790
3791
|
const transport = getTransport();
|
|
3791
3792
|
const sessionName = employeeSessionName(employeeName, exeSession, opts?.instance);
|
|
3792
3793
|
const instanceLabel = opts?.instance != null && opts.instance > 0 ? `${employeeName}${opts.instance}` : employeeName;
|
|
3793
|
-
const logDir = path13.join(
|
|
3794
|
+
const logDir = path13.join(os6.homedir(), ".exe-os", "session-logs");
|
|
3794
3795
|
const logFile = path13.join(logDir, `${instanceLabel}-${Date.now()}.log`);
|
|
3795
3796
|
if (!existsSync10(logDir)) {
|
|
3796
3797
|
mkdirSync5(logDir, { recursive: true });
|
|
@@ -3806,7 +3807,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3806
3807
|
} catch {
|
|
3807
3808
|
}
|
|
3808
3809
|
try {
|
|
3809
|
-
const claudeJsonPath = path13.join(
|
|
3810
|
+
const claudeJsonPath = path13.join(os6.homedir(), ".claude.json");
|
|
3810
3811
|
let claudeJson = {};
|
|
3811
3812
|
try {
|
|
3812
3813
|
claudeJson = JSON.parse(readFileSync9(claudeJsonPath, "utf8"));
|
|
@@ -3817,11 +3818,11 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3817
3818
|
const trustDir = opts?.cwd ?? projectDir;
|
|
3818
3819
|
if (!projects[trustDir]) projects[trustDir] = {};
|
|
3819
3820
|
projects[trustDir].hasTrustDialogAccepted = true;
|
|
3820
|
-
|
|
3821
|
+
writeFileSync6(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
|
|
3821
3822
|
} catch {
|
|
3822
3823
|
}
|
|
3823
3824
|
try {
|
|
3824
|
-
const settingsDir = path13.join(
|
|
3825
|
+
const settingsDir = path13.join(os6.homedir(), ".claude", "projects");
|
|
3825
3826
|
const normalizedKey = (opts?.cwd ?? projectDir).replace(/\//g, "-").replace(/^-/, "");
|
|
3826
3827
|
const projSettingsDir = path13.join(settingsDir, normalizedKey);
|
|
3827
3828
|
const settingsPath = path13.join(projSettingsDir, "settings.json");
|
|
@@ -3856,7 +3857,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3856
3857
|
perms.allow = allow;
|
|
3857
3858
|
settings.permissions = perms;
|
|
3858
3859
|
mkdirSync5(projSettingsDir, { recursive: true });
|
|
3859
|
-
|
|
3860
|
+
writeFileSync6(settingsPath, JSON.stringify(settings, null, 2) + "\n");
|
|
3860
3861
|
}
|
|
3861
3862
|
} catch {
|
|
3862
3863
|
}
|
|
@@ -3869,7 +3870,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3869
3870
|
let legacyFallbackWarned = false;
|
|
3870
3871
|
if (!useExeAgent && !useBinSymlink) {
|
|
3871
3872
|
const identityPath = path13.join(
|
|
3872
|
-
|
|
3873
|
+
os6.homedir(),
|
|
3873
3874
|
".exe-os",
|
|
3874
3875
|
"identity",
|
|
3875
3876
|
`${employeeName}.md`
|
|
@@ -3899,7 +3900,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3899
3900
|
}
|
|
3900
3901
|
let sessionContextFlag = "";
|
|
3901
3902
|
try {
|
|
3902
|
-
const ctxDir = path13.join(
|
|
3903
|
+
const ctxDir = path13.join(os6.homedir(), ".exe-os", "session-cache");
|
|
3903
3904
|
mkdirSync5(ctxDir, { recursive: true });
|
|
3904
3905
|
const ctxFile = path13.join(ctxDir, `session-context-${sessionName}.md`);
|
|
3905
3906
|
const ctxContent = [
|
|
@@ -3908,7 +3909,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3908
3909
|
`Your parent exe session is ${exeSession}.`,
|
|
3909
3910
|
`Your employees (if any) use the -${exeSession} suffix (e.g., tom-${exeSession}).`
|
|
3910
3911
|
].join("\n");
|
|
3911
|
-
|
|
3912
|
+
writeFileSync6(ctxFile, ctxContent);
|
|
3912
3913
|
sessionContextFlag = ` --append-system-prompt-file ${ctxFile}`;
|
|
3913
3914
|
} catch {
|
|
3914
3915
|
}
|
|
@@ -3947,7 +3948,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3947
3948
|
try {
|
|
3948
3949
|
const mySession = getMySession();
|
|
3949
3950
|
const dispatchInfo = path13.join(SESSION_CACHE, `dispatch-info-${sessionName}.json`);
|
|
3950
|
-
|
|
3951
|
+
writeFileSync6(dispatchInfo, JSON.stringify({
|
|
3951
3952
|
dispatchedBy: mySession,
|
|
3952
3953
|
rootExe: exeSession,
|
|
3953
3954
|
provider: useBinSymlink ? ccProvider : useExeAgent ? opts.provider : "anthropic",
|
|
@@ -4010,13 +4011,13 @@ var init_tmux_routing = __esm({
|
|
|
4010
4011
|
init_provider_table();
|
|
4011
4012
|
init_intercom_queue();
|
|
4012
4013
|
init_plan_limits();
|
|
4013
|
-
SPAWN_LOCK_DIR = path13.join(
|
|
4014
|
-
SESSION_CACHE = path13.join(
|
|
4014
|
+
SPAWN_LOCK_DIR = path13.join(os6.homedir(), ".exe-os", "spawn-locks");
|
|
4015
|
+
SESSION_CACHE = path13.join(os6.homedir(), ".exe-os", "session-cache");
|
|
4015
4016
|
BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
|
|
4016
4017
|
VALID_SESSION_NAME = /^[a-z]+\d*-[a-zA-Z0-9_]+$/;
|
|
4017
4018
|
VERIFY_PANE_LINES = 200;
|
|
4018
4019
|
INTERCOM_DEBOUNCE_MS = 3e4;
|
|
4019
|
-
INTERCOM_LOG2 = path13.join(
|
|
4020
|
+
INTERCOM_LOG2 = path13.join(os6.homedir(), ".exe-os", "intercom.log");
|
|
4020
4021
|
DEBOUNCE_FILE = path13.join(SESSION_CACHE, "intercom-debounce.json");
|
|
4021
4022
|
DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
|
|
4022
4023
|
BUSY_PATTERN = /[✻✽✶✳·].*…|Running…/;
|
|
@@ -4060,9 +4061,9 @@ var init_memory = __esm({
|
|
|
4060
4061
|
import { readFile as readFile4, writeFile as writeFile5, unlink, mkdir as mkdir4, chmod as chmod2 } from "fs/promises";
|
|
4061
4062
|
import { existsSync as existsSync11 } from "fs";
|
|
4062
4063
|
import path14 from "path";
|
|
4063
|
-
import
|
|
4064
|
+
import os7 from "os";
|
|
4064
4065
|
function getKeyDir() {
|
|
4065
|
-
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path14.join(
|
|
4066
|
+
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path14.join(os7.homedir(), ".exe-os");
|
|
4066
4067
|
}
|
|
4067
4068
|
function getKeyPath() {
|
|
4068
4069
|
return path14.join(getKeyDir(), "master.key");
|
|
@@ -5018,7 +5019,7 @@ var init_store = __esm({
|
|
|
5018
5019
|
// src/bin/scan-tasks.ts
|
|
5019
5020
|
import { existsSync as existsSync13, readFileSync as readFileSync10 } from "fs";
|
|
5020
5021
|
import path16 from "path";
|
|
5021
|
-
import
|
|
5022
|
+
import os8 from "os";
|
|
5022
5023
|
|
|
5023
5024
|
// src/lib/is-main.ts
|
|
5024
5025
|
import { realpathSync } from "fs";
|
|
@@ -5038,7 +5039,7 @@ function isMainModule(importMetaUrl) {
|
|
|
5038
5039
|
init_task_scope();
|
|
5039
5040
|
function checkMcpHealth() {
|
|
5040
5041
|
try {
|
|
5041
|
-
const claudeJson = path16.join(
|
|
5042
|
+
const claudeJson = path16.join(os8.homedir(), ".claude.json");
|
|
5042
5043
|
if (!existsSync13(claudeJson)) {
|
|
5043
5044
|
process.stderr.write(
|
|
5044
5045
|
"\u26A0\uFE0F MCP config missing (~/.claude.json not found) \u2014 close_task won't work. Run /exe-setup\n"
|
package/dist/bin/setup.js
CHANGED
|
@@ -1298,14 +1298,16 @@ __export(employees_exports, {
|
|
|
1298
1298
|
isMultiInstance: () => isMultiInstance,
|
|
1299
1299
|
loadEmployees: () => loadEmployees,
|
|
1300
1300
|
loadEmployeesSync: () => loadEmployeesSync,
|
|
1301
|
+
normalizeRosterCase: () => normalizeRosterCase,
|
|
1301
1302
|
registerBinSymlinks: () => registerBinSymlinks,
|
|
1302
1303
|
saveEmployees: () => saveEmployees,
|
|
1303
1304
|
validateEmployeeName: () => validateEmployeeName
|
|
1304
1305
|
});
|
|
1305
1306
|
import { readFile as readFile3, writeFile as writeFile3, mkdir as mkdir4 } from "fs/promises";
|
|
1306
|
-
import { existsSync as existsSync6, symlinkSync, readlinkSync, readFileSync as readFileSync4 } from "fs";
|
|
1307
|
+
import { existsSync as existsSync6, symlinkSync, readlinkSync, readFileSync as readFileSync4, renameSync as renameSync3, unlinkSync as unlinkSync3, writeFileSync as writeFileSync2 } from "fs";
|
|
1307
1308
|
import { execSync } from "child_process";
|
|
1308
1309
|
import path6 from "path";
|
|
1310
|
+
import os3 from "os";
|
|
1309
1311
|
function validateEmployeeName(name) {
|
|
1310
1312
|
if (!name) {
|
|
1311
1313
|
return { valid: false, error: "Name is required" };
|
|
@@ -1373,6 +1375,36 @@ function addEmployee(employees, employee) {
|
|
|
1373
1375
|
}
|
|
1374
1376
|
return [...employees, normalized];
|
|
1375
1377
|
}
|
|
1378
|
+
async function normalizeRosterCase(rosterPath) {
|
|
1379
|
+
const employees = await loadEmployees(rosterPath);
|
|
1380
|
+
let changed = false;
|
|
1381
|
+
for (const emp of employees) {
|
|
1382
|
+
if (emp.name !== emp.name.toLowerCase()) {
|
|
1383
|
+
const oldName = emp.name;
|
|
1384
|
+
emp.name = emp.name.toLowerCase();
|
|
1385
|
+
changed = true;
|
|
1386
|
+
try {
|
|
1387
|
+
const identityDir = path6.join(os3.homedir(), ".exe-os", "identity");
|
|
1388
|
+
const oldPath = path6.join(identityDir, `${oldName}.md`);
|
|
1389
|
+
const newPath = path6.join(identityDir, `${emp.name}.md`);
|
|
1390
|
+
if (existsSync6(oldPath) && !existsSync6(newPath)) {
|
|
1391
|
+
renameSync3(oldPath, newPath);
|
|
1392
|
+
} else if (existsSync6(oldPath) && oldPath !== newPath) {
|
|
1393
|
+
const content = readFileSync4(oldPath, "utf-8");
|
|
1394
|
+
writeFileSync2(newPath, content, "utf-8");
|
|
1395
|
+
if (oldPath.toLowerCase() !== newPath.toLowerCase()) {
|
|
1396
|
+
unlinkSync3(oldPath);
|
|
1397
|
+
}
|
|
1398
|
+
}
|
|
1399
|
+
} catch {
|
|
1400
|
+
}
|
|
1401
|
+
}
|
|
1402
|
+
}
|
|
1403
|
+
if (changed) {
|
|
1404
|
+
await saveEmployees(employees, rosterPath);
|
|
1405
|
+
}
|
|
1406
|
+
return changed;
|
|
1407
|
+
}
|
|
1376
1408
|
function findExeBin() {
|
|
1377
1409
|
try {
|
|
1378
1410
|
return execSync(process.platform === "win32" ? "where exe-os" : "which exe-os", { encoding: "utf8" }).trim();
|
|
@@ -1451,7 +1483,7 @@ __export(cloud_sync_exports, {
|
|
|
1451
1483
|
mergeRosterFromRemote: () => mergeRosterFromRemote,
|
|
1452
1484
|
recordRosterDeletion: () => recordRosterDeletion
|
|
1453
1485
|
});
|
|
1454
|
-
import { readFileSync as readFileSync5, writeFileSync as
|
|
1486
|
+
import { readFileSync as readFileSync5, writeFileSync as writeFileSync3, existsSync as existsSync7, readdirSync, mkdirSync as mkdirSync2, appendFileSync, unlinkSync as unlinkSync4, openSync as openSync2, closeSync as closeSync2 } from "fs";
|
|
1455
1487
|
import crypto2 from "crypto";
|
|
1456
1488
|
import path7 from "path";
|
|
1457
1489
|
import { homedir } from "os";
|
|
@@ -1470,7 +1502,7 @@ async function withRosterLock(fn) {
|
|
|
1470
1502
|
try {
|
|
1471
1503
|
const fd = openSync2(ROSTER_LOCK_PATH, "wx");
|
|
1472
1504
|
closeSync2(fd);
|
|
1473
|
-
|
|
1505
|
+
writeFileSync3(ROSTER_LOCK_PATH, String(Date.now()));
|
|
1474
1506
|
} catch (err) {
|
|
1475
1507
|
if (err.code === "EEXIST") {
|
|
1476
1508
|
try {
|
|
@@ -1478,10 +1510,10 @@ async function withRosterLock(fn) {
|
|
|
1478
1510
|
if (Date.now() - ts < LOCK_STALE_MS) {
|
|
1479
1511
|
throw new Error("Roster merge already in progress \u2014 another sync is running");
|
|
1480
1512
|
}
|
|
1481
|
-
|
|
1513
|
+
unlinkSync4(ROSTER_LOCK_PATH);
|
|
1482
1514
|
const fd = openSync2(ROSTER_LOCK_PATH, "wx");
|
|
1483
1515
|
closeSync2(fd);
|
|
1484
|
-
|
|
1516
|
+
writeFileSync3(ROSTER_LOCK_PATH, String(Date.now()));
|
|
1485
1517
|
} catch (retryErr) {
|
|
1486
1518
|
if (retryErr instanceof Error && retryErr.message.includes("already in progress")) throw retryErr;
|
|
1487
1519
|
throw new Error("Roster merge already in progress \u2014 another sync is running");
|
|
@@ -1494,7 +1526,7 @@ async function withRosterLock(fn) {
|
|
|
1494
1526
|
return await fn();
|
|
1495
1527
|
} finally {
|
|
1496
1528
|
try {
|
|
1497
|
-
|
|
1529
|
+
unlinkSync4(ROSTER_LOCK_PATH);
|
|
1498
1530
|
} catch {
|
|
1499
1531
|
}
|
|
1500
1532
|
}
|
|
@@ -1794,13 +1826,13 @@ function recordRosterDeletion(name) {
|
|
|
1794
1826
|
} catch {
|
|
1795
1827
|
}
|
|
1796
1828
|
if (!deletions.includes(name)) deletions.push(name);
|
|
1797
|
-
|
|
1829
|
+
writeFileSync3(ROSTER_DELETIONS_PATH, JSON.stringify(deletions));
|
|
1798
1830
|
}
|
|
1799
1831
|
function consumeRosterDeletions() {
|
|
1800
1832
|
try {
|
|
1801
1833
|
if (!existsSync7(ROSTER_DELETIONS_PATH)) return [];
|
|
1802
1834
|
const deletions = JSON.parse(readFileSync5(ROSTER_DELETIONS_PATH, "utf-8"));
|
|
1803
|
-
|
|
1835
|
+
writeFileSync3(ROSTER_DELETIONS_PATH, "[]");
|
|
1804
1836
|
return deletions;
|
|
1805
1837
|
} catch {
|
|
1806
1838
|
return [];
|
|
@@ -1916,7 +1948,7 @@ function mergeConfig(remoteConfig, configPath) {
|
|
|
1916
1948
|
const merged = { ...remoteConfig, ...local };
|
|
1917
1949
|
const dir = path7.dirname(cfgPath);
|
|
1918
1950
|
if (!existsSync7(dir)) mkdirSync2(dir, { recursive: true });
|
|
1919
|
-
|
|
1951
|
+
writeFileSync3(cfgPath, JSON.stringify(merged, null, 2), "utf-8");
|
|
1920
1952
|
}
|
|
1921
1953
|
async function mergeRosterFromRemote(remote, paths) {
|
|
1922
1954
|
return withRosterLock(async () => {
|
|
@@ -1936,7 +1968,11 @@ async function mergeRosterFromRemote(remote, paths) {
|
|
|
1936
1968
|
} catch {
|
|
1937
1969
|
}
|
|
1938
1970
|
}
|
|
1939
|
-
const
|
|
1971
|
+
const lookupKey = `${remoteEmp.name}.md`;
|
|
1972
|
+
const matchedKey = Object.keys(remote.identities).find(
|
|
1973
|
+
(k) => k.toLowerCase() === lookupKey.toLowerCase()
|
|
1974
|
+
) ?? lookupKey;
|
|
1975
|
+
const remoteIdentity = remote.identities[matchedKey];
|
|
1940
1976
|
if (remoteIdentity) {
|
|
1941
1977
|
if (!existsSync7(identityDir)) mkdirSync2(identityDir, { recursive: true });
|
|
1942
1978
|
const idPath = path7.join(identityDir, `${remoteEmp.name}.md`);
|
|
@@ -1946,7 +1982,7 @@ async function mergeRosterFromRemote(remote, paths) {
|
|
|
1946
1982
|
} catch {
|
|
1947
1983
|
}
|
|
1948
1984
|
if (localIdentity !== remoteIdentity) {
|
|
1949
|
-
|
|
1985
|
+
writeFileSync3(idPath, remoteIdentity, "utf-8");
|
|
1950
1986
|
identitiesUpdated++;
|
|
1951
1987
|
}
|
|
1952
1988
|
}
|
|
@@ -3170,7 +3206,7 @@ __export(identity_exports, {
|
|
|
3170
3206
|
listIdentities: () => listIdentities,
|
|
3171
3207
|
updateIdentity: () => updateIdentity
|
|
3172
3208
|
});
|
|
3173
|
-
import { existsSync as existsSync8, mkdirSync as mkdirSync3, readFileSync as readFileSync6, writeFileSync as
|
|
3209
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync3, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "fs";
|
|
3174
3210
|
import { readdirSync as readdirSync2 } from "fs";
|
|
3175
3211
|
import path8 from "path";
|
|
3176
3212
|
import { createHash as createHash2 } from "crypto";
|
|
@@ -3236,7 +3272,7 @@ async function updateIdentity(agentId, content, updatedBy) {
|
|
|
3236
3272
|
ensureDir();
|
|
3237
3273
|
const filePath = identityPath(agentId);
|
|
3238
3274
|
const hash = contentHash(content);
|
|
3239
|
-
|
|
3275
|
+
writeFileSync4(filePath, content, "utf-8");
|
|
3240
3276
|
try {
|
|
3241
3277
|
const client = getClient();
|
|
3242
3278
|
await client.execute({
|
|
@@ -3834,11 +3870,11 @@ __export(session_wrappers_exports, {
|
|
|
3834
3870
|
import {
|
|
3835
3871
|
existsSync as existsSync9,
|
|
3836
3872
|
readFileSync as readFileSync7,
|
|
3837
|
-
writeFileSync as
|
|
3873
|
+
writeFileSync as writeFileSync5,
|
|
3838
3874
|
mkdirSync as mkdirSync4,
|
|
3839
3875
|
chmodSync,
|
|
3840
3876
|
readdirSync as readdirSync3,
|
|
3841
|
-
unlinkSync as
|
|
3877
|
+
unlinkSync as unlinkSync5
|
|
3842
3878
|
} from "fs";
|
|
3843
3879
|
import path9 from "path";
|
|
3844
3880
|
import { homedir as homedir2 } from "os";
|
|
@@ -3854,7 +3890,7 @@ function generateSessionWrappers(packageRoot, homeDir) {
|
|
|
3854
3890
|
];
|
|
3855
3891
|
for (const src of candidates) {
|
|
3856
3892
|
if (existsSync9(src)) {
|
|
3857
|
-
|
|
3893
|
+
writeFileSync5(exeStartDst, readFileSync7(src));
|
|
3858
3894
|
chmodSync(exeStartDst, 493);
|
|
3859
3895
|
break;
|
|
3860
3896
|
}
|
|
@@ -3875,7 +3911,7 @@ function generateSessionWrappers(packageRoot, homeDir) {
|
|
|
3875
3911
|
try {
|
|
3876
3912
|
const content = readFileSync7(fPath, "utf8");
|
|
3877
3913
|
if (content.includes("exe-start")) {
|
|
3878
|
-
|
|
3914
|
+
unlinkSync5(fPath);
|
|
3879
3915
|
}
|
|
3880
3916
|
} catch {
|
|
3881
3917
|
}
|
|
@@ -3889,7 +3925,7 @@ exec "${exeStartDst}" "$0" "$@"
|
|
|
3889
3925
|
for (const emp of employees) {
|
|
3890
3926
|
for (let n = 1; n <= MAX_N; n++) {
|
|
3891
3927
|
const wrapperPath = path9.join(binDir, `${emp.name}${n}`);
|
|
3892
|
-
|
|
3928
|
+
writeFileSync5(wrapperPath, wrapperContent);
|
|
3893
3929
|
chmodSync(wrapperPath, 493);
|
|
3894
3930
|
created++;
|
|
3895
3931
|
}
|
|
@@ -3925,7 +3961,7 @@ export PATH="${binDir}:$PATH"
|
|
|
3925
3961
|
if (content.includes(".exe-os/bin")) {
|
|
3926
3962
|
return false;
|
|
3927
3963
|
}
|
|
3928
|
-
|
|
3964
|
+
writeFileSync5(profilePath, content + exportLine);
|
|
3929
3965
|
return true;
|
|
3930
3966
|
} catch {
|
|
3931
3967
|
continue;
|
|
@@ -3945,8 +3981,8 @@ var init_session_wrappers = __esm({
|
|
|
3945
3981
|
init_config();
|
|
3946
3982
|
init_keychain();
|
|
3947
3983
|
import crypto3 from "crypto";
|
|
3948
|
-
import { existsSync as existsSync10, mkdirSync as mkdirSync5, readFileSync as readFileSync8, writeFileSync as
|
|
3949
|
-
import
|
|
3984
|
+
import { existsSync as existsSync10, mkdirSync as mkdirSync5, readFileSync as readFileSync8, writeFileSync as writeFileSync6, unlinkSync as unlinkSync6 } from "fs";
|
|
3985
|
+
import os4 from "os";
|
|
3950
3986
|
import path10 from "path";
|
|
3951
3987
|
import { createInterface } from "readline";
|
|
3952
3988
|
|
|
@@ -4054,7 +4090,7 @@ function findPackageRoot2() {
|
|
|
4054
4090
|
}
|
|
4055
4091
|
return null;
|
|
4056
4092
|
}
|
|
4057
|
-
var SETUP_STATE_PATH = path10.join(
|
|
4093
|
+
var SETUP_STATE_PATH = path10.join(os4.homedir(), ".exe-os", "setup-state.json");
|
|
4058
4094
|
function loadSetupState() {
|
|
4059
4095
|
try {
|
|
4060
4096
|
return JSON.parse(readFileSync8(SETUP_STATE_PATH, "utf8"));
|
|
@@ -4064,11 +4100,11 @@ function loadSetupState() {
|
|
|
4064
4100
|
}
|
|
4065
4101
|
function saveSetupState(state) {
|
|
4066
4102
|
mkdirSync5(path10.dirname(SETUP_STATE_PATH), { recursive: true });
|
|
4067
|
-
|
|
4103
|
+
writeFileSync6(SETUP_STATE_PATH, JSON.stringify(state, null, 2));
|
|
4068
4104
|
}
|
|
4069
4105
|
function clearSetupState() {
|
|
4070
4106
|
try {
|
|
4071
|
-
|
|
4107
|
+
unlinkSync6(SETUP_STATE_PATH);
|
|
4072
4108
|
} catch {
|
|
4073
4109
|
}
|
|
4074
4110
|
}
|
|
@@ -4274,7 +4310,7 @@ async function runSetupWizard(opts = {}) {
|
|
|
4274
4310
|
await saveConfig(config);
|
|
4275
4311
|
log("");
|
|
4276
4312
|
try {
|
|
4277
|
-
const claudeJsonPath = path10.join(
|
|
4313
|
+
const claudeJsonPath = path10.join(os4.homedir(), ".claude.json");
|
|
4278
4314
|
let claudeJson = {};
|
|
4279
4315
|
try {
|
|
4280
4316
|
claudeJson = JSON.parse(readFileSync8(claudeJsonPath, "utf8"));
|
|
@@ -4282,11 +4318,11 @@ async function runSetupWizard(opts = {}) {
|
|
|
4282
4318
|
}
|
|
4283
4319
|
if (!claudeJson.projects) claudeJson.projects = {};
|
|
4284
4320
|
const projects = claudeJson.projects;
|
|
4285
|
-
for (const dir of [process.cwd(),
|
|
4321
|
+
for (const dir of [process.cwd(), os4.homedir()]) {
|
|
4286
4322
|
if (!projects[dir]) projects[dir] = {};
|
|
4287
4323
|
projects[dir].hasTrustDialogAccepted = true;
|
|
4288
4324
|
}
|
|
4289
|
-
|
|
4325
|
+
writeFileSync6(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
|
|
4290
4326
|
} catch {
|
|
4291
4327
|
}
|
|
4292
4328
|
state.completedSteps.push(5);
|
|
@@ -4322,6 +4358,54 @@ async function runSetupWizard(opts = {}) {
|
|
|
4322
4358
|
log(`Team: ${teamList}`);
|
|
4323
4359
|
createdEmployees.push(...roster.map((e) => ({ name: e.name, role: e.role })));
|
|
4324
4360
|
}
|
|
4361
|
+
let missingIdentities = [];
|
|
4362
|
+
for (const emp of roster) {
|
|
4363
|
+
const idPath = identityPath2(emp.name);
|
|
4364
|
+
if (!existsSync10(idPath)) {
|
|
4365
|
+
missingIdentities.push(emp.name);
|
|
4366
|
+
}
|
|
4367
|
+
}
|
|
4368
|
+
if (missingIdentities.length > 0) {
|
|
4369
|
+
log("");
|
|
4370
|
+
log(`\u26A0 Identity files missing for: ${missingIdentities.join(", ")}`);
|
|
4371
|
+
log(" Your main device needs to push them to cloud first.");
|
|
4372
|
+
log("");
|
|
4373
|
+
log(" On your MAIN device, run: exe-os cloud sync");
|
|
4374
|
+
log(" Then come back here and press Enter to retry the pull.");
|
|
4375
|
+
log("");
|
|
4376
|
+
await ask(rl, "Press Enter after syncing from your main device... ");
|
|
4377
|
+
try {
|
|
4378
|
+
const { initSyncCrypto: retryInitCrypto } = await Promise.resolve().then(() => (init_crypto(), crypto_exports));
|
|
4379
|
+
const { cloudPullRoster: retryPull } = await Promise.resolve().then(() => (init_cloud_sync(), cloud_sync_exports));
|
|
4380
|
+
const retryKey = await getMasterKey();
|
|
4381
|
+
if (retryKey) {
|
|
4382
|
+
retryInitCrypto(retryKey);
|
|
4383
|
+
const retryConfig = await loadConfig();
|
|
4384
|
+
if (retryConfig.cloud?.apiKey && retryConfig.cloud?.endpoint) {
|
|
4385
|
+
const retryResult = await retryPull({
|
|
4386
|
+
apiKey: retryConfig.cloud.apiKey,
|
|
4387
|
+
endpoint: retryConfig.cloud.endpoint
|
|
4388
|
+
});
|
|
4389
|
+
if (retryResult.identitiesUpdated && retryResult.identitiesUpdated > 0) {
|
|
4390
|
+
log(`Pulled ${retryResult.identitiesUpdated} identity file(s) from cloud.`);
|
|
4391
|
+
}
|
|
4392
|
+
}
|
|
4393
|
+
}
|
|
4394
|
+
missingIdentities = [];
|
|
4395
|
+
for (const emp of roster) {
|
|
4396
|
+
if (!existsSync10(identityPath2(emp.name))) {
|
|
4397
|
+
missingIdentities.push(emp.name);
|
|
4398
|
+
}
|
|
4399
|
+
}
|
|
4400
|
+
if (missingIdentities.length > 0) {
|
|
4401
|
+
log(`\u26A0 Still missing: ${missingIdentities.join(", ")}. Identities will sync on next daemon cycle.`);
|
|
4402
|
+
} else {
|
|
4403
|
+
log("All identity files synced successfully.");
|
|
4404
|
+
}
|
|
4405
|
+
} catch {
|
|
4406
|
+
log("Retry pull failed \u2014 identities will sync when the daemon starts.");
|
|
4407
|
+
}
|
|
4408
|
+
}
|
|
4325
4409
|
for (const emp of roster) {
|
|
4326
4410
|
registerBinSymlinks2(emp.name);
|
|
4327
4411
|
}
|
|
@@ -4367,7 +4451,7 @@ async function runSetupWizard(opts = {}) {
|
|
|
4367
4451
|
const cooIdPath = identityPath2(cooName);
|
|
4368
4452
|
mkdirSync5(path10.dirname(cooIdPath), { recursive: true });
|
|
4369
4453
|
const replaced = cooIdentityContent.replace(/agent_id:\s*exe/g, `agent_id: ${cooName}`).replace(/\$\{agent_id\}/g, cooName);
|
|
4370
|
-
|
|
4454
|
+
writeFileSync6(cooIdPath, replaced, "utf-8");
|
|
4371
4455
|
}
|
|
4372
4456
|
registerBinSymlinks2(cooName);
|
|
4373
4457
|
createdEmployees.push({ name: cooName, role: "COO" });
|
|
@@ -4468,7 +4552,7 @@ async function runSetupWizard(opts = {}) {
|
|
|
4468
4552
|
const ctoIdPath = identityPath2(ctoName);
|
|
4469
4553
|
mkdirSync5(path10.dirname(ctoIdPath), { recursive: true });
|
|
4470
4554
|
const replaced = ctoIdentityContent.replace(/agent_id:\s*\w+/g, `agent_id: ${ctoName}`).replace(/\$\{agent_id\}/g, ctoName);
|
|
4471
|
-
|
|
4555
|
+
writeFileSync6(ctoIdPath, replaced, "utf-8");
|
|
4472
4556
|
}
|
|
4473
4557
|
registerBinSymlinks2(ctoName);
|
|
4474
4558
|
createdEmployees.push({ name: ctoName, role: "CTO" });
|
|
@@ -4496,7 +4580,7 @@ async function runSetupWizard(opts = {}) {
|
|
|
4496
4580
|
const cmoIdPath = identityPath2(cmoName);
|
|
4497
4581
|
mkdirSync5(path10.dirname(cmoIdPath), { recursive: true });
|
|
4498
4582
|
const replaced = cmoIdentityContent.replace(/agent_id:\s*\w+/g, `agent_id: ${cmoName}`).replace(/\$\{agent_id\}/g, cmoName);
|
|
4499
|
-
|
|
4583
|
+
writeFileSync6(cmoIdPath, replaced, "utf-8");
|
|
4500
4584
|
}
|
|
4501
4585
|
registerBinSymlinks2(cmoName);
|
|
4502
4586
|
createdEmployees.push({ name: cmoName, role: "CMO" });
|