@askexenow/exe-os 0.8.65 → 0.8.69
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 +204 -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 +84 -19
- 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-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/index.js
CHANGED
|
@@ -1538,9 +1538,10 @@ var init_config = __esm({
|
|
|
1538
1538
|
|
|
1539
1539
|
// src/lib/employees.ts
|
|
1540
1540
|
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
1541
|
-
import { existsSync as existsSync4, symlinkSync, readlinkSync, readFileSync as readFileSync4 } from "fs";
|
|
1541
|
+
import { existsSync as existsSync4, symlinkSync, readlinkSync, readFileSync as readFileSync4, renameSync as renameSync3, unlinkSync, writeFileSync as writeFileSync3 } from "fs";
|
|
1542
1542
|
import { execSync as execSync4 } from "child_process";
|
|
1543
1543
|
import path5 from "path";
|
|
1544
|
+
import os5 from "os";
|
|
1544
1545
|
function loadEmployeesSync(employeesPath = EMPLOYEES_PATH) {
|
|
1545
1546
|
if (!existsSync4(employeesPath)) return [];
|
|
1546
1547
|
try {
|
|
@@ -1569,7 +1570,7 @@ var init_employees = __esm({
|
|
|
1569
1570
|
});
|
|
1570
1571
|
|
|
1571
1572
|
// src/lib/license.ts
|
|
1572
|
-
import { readFileSync as readFileSync5, writeFileSync as
|
|
1573
|
+
import { readFileSync as readFileSync5, writeFileSync as writeFileSync4, existsSync as existsSync5, mkdirSync as mkdirSync3 } from "fs";
|
|
1573
1574
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
1574
1575
|
import path6 from "path";
|
|
1575
1576
|
import { jwtVerify, importSPKI } from "jose";
|
|
@@ -1672,11 +1673,11 @@ var init_plan_limits = __esm({
|
|
|
1672
1673
|
// src/lib/notifications.ts
|
|
1673
1674
|
import crypto from "crypto";
|
|
1674
1675
|
import path8 from "path";
|
|
1675
|
-
import
|
|
1676
|
+
import os6 from "os";
|
|
1676
1677
|
import {
|
|
1677
1678
|
readFileSync as readFileSync7,
|
|
1678
1679
|
readdirSync,
|
|
1679
|
-
unlinkSync,
|
|
1680
|
+
unlinkSync as unlinkSync2,
|
|
1680
1681
|
existsSync as existsSync7,
|
|
1681
1682
|
rmdirSync
|
|
1682
1683
|
} from "fs";
|
|
@@ -2257,7 +2258,7 @@ var init_tasks_crud = __esm({
|
|
|
2257
2258
|
|
|
2258
2259
|
// src/lib/tasks-review.ts
|
|
2259
2260
|
import path10 from "path";
|
|
2260
|
-
import { existsSync as existsSync9, readdirSync as readdirSync2, unlinkSync as
|
|
2261
|
+
import { existsSync as existsSync9, readdirSync as readdirSync2, unlinkSync as unlinkSync3 } from "fs";
|
|
2261
2262
|
async function countPendingReviews(sessionScope) {
|
|
2262
2263
|
const client = getClient();
|
|
2263
2264
|
if (sessionScope) {
|
|
@@ -2442,7 +2443,7 @@ async function cleanupReviewFile(row, taskFile, _baseDir) {
|
|
|
2442
2443
|
if (existsSync9(cacheDir)) {
|
|
2443
2444
|
for (const f of readdirSync2(cacheDir)) {
|
|
2444
2445
|
if (f.startsWith("review-notified-")) {
|
|
2445
|
-
|
|
2446
|
+
unlinkSync3(path10.join(cacheDir, f));
|
|
2446
2447
|
}
|
|
2447
2448
|
}
|
|
2448
2449
|
}
|
|
@@ -3110,7 +3111,7 @@ __export(tasks_exports, {
|
|
|
3110
3111
|
writeCheckpoint: () => writeCheckpoint
|
|
3111
3112
|
});
|
|
3112
3113
|
import path13 from "path";
|
|
3113
|
-
import { writeFileSync as
|
|
3114
|
+
import { writeFileSync as writeFileSync5, mkdirSync as mkdirSync4, unlinkSync as unlinkSync4 } from "fs";
|
|
3114
3115
|
async function createTask(input) {
|
|
3115
3116
|
const result = await createTaskCore(input);
|
|
3116
3117
|
if (!input.skipDispatch && result.status !== "blocked" && !process.env.VITEST) {
|
|
@@ -3133,10 +3134,10 @@ async function updateTask(input) {
|
|
|
3133
3134
|
const cachePath = path13.join(cacheDir, `current-task-${agent}.json`);
|
|
3134
3135
|
if (input.status === "in_progress") {
|
|
3135
3136
|
mkdirSync4(cacheDir, { recursive: true });
|
|
3136
|
-
|
|
3137
|
+
writeFileSync5(cachePath, JSON.stringify({ taskId, title: String(row.title) }));
|
|
3137
3138
|
} else if (input.status === "done" || input.status === "blocked" || input.status === "cancelled") {
|
|
3138
3139
|
try {
|
|
3139
|
-
|
|
3140
|
+
unlinkSync4(cachePath);
|
|
3140
3141
|
} catch {
|
|
3141
3142
|
}
|
|
3142
3143
|
}
|
|
@@ -3578,11 +3579,11 @@ __export(tmux_routing_exports, {
|
|
|
3578
3579
|
verifyPaneAtCapacity: () => verifyPaneAtCapacity
|
|
3579
3580
|
});
|
|
3580
3581
|
import { execFileSync as execFileSync2, execSync as execSync7 } from "child_process";
|
|
3581
|
-
import { readFileSync as readFileSync9, writeFileSync as
|
|
3582
|
+
import { readFileSync as readFileSync9, writeFileSync as writeFileSync6, mkdirSync as mkdirSync5, existsSync as existsSync10, appendFileSync } from "fs";
|
|
3582
3583
|
import path14 from "path";
|
|
3583
|
-
import
|
|
3584
|
+
import os7 from "os";
|
|
3584
3585
|
import { fileURLToPath } from "url";
|
|
3585
|
-
import { unlinkSync as
|
|
3586
|
+
import { unlinkSync as unlinkSync5 } from "fs";
|
|
3586
3587
|
function spawnLockPath(sessionName) {
|
|
3587
3588
|
return path14.join(SPAWN_LOCK_DIR, `${sessionName}.lock`);
|
|
3588
3589
|
}
|
|
@@ -3609,12 +3610,12 @@ function acquireSpawnLock(sessionName) {
|
|
|
3609
3610
|
} catch {
|
|
3610
3611
|
}
|
|
3611
3612
|
}
|
|
3612
|
-
|
|
3613
|
+
writeFileSync6(lockFile, JSON.stringify({ pid: process.pid, timestamp: Date.now() }));
|
|
3613
3614
|
return true;
|
|
3614
3615
|
}
|
|
3615
3616
|
function releaseSpawnLock(sessionName) {
|
|
3616
3617
|
try {
|
|
3617
|
-
|
|
3618
|
+
unlinkSync5(spawnLockPath(sessionName));
|
|
3618
3619
|
} catch {
|
|
3619
3620
|
}
|
|
3620
3621
|
}
|
|
@@ -3696,7 +3697,7 @@ function registerParentExe(sessionKey, parentExe, dispatchedBy) {
|
|
|
3696
3697
|
}
|
|
3697
3698
|
const rootExe = extractRootExe(parentExe) ?? parentExe;
|
|
3698
3699
|
const filePath = path14.join(SESSION_CACHE, `parent-exe-${sessionKey}.json`);
|
|
3699
|
-
|
|
3700
|
+
writeFileSync6(filePath, JSON.stringify({
|
|
3700
3701
|
parentExe: rootExe,
|
|
3701
3702
|
dispatchedBy: dispatchedBy || rootExe,
|
|
3702
3703
|
registeredAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
@@ -3783,7 +3784,7 @@ function readDebounceState() {
|
|
|
3783
3784
|
function writeDebounceState(state) {
|
|
3784
3785
|
try {
|
|
3785
3786
|
if (!existsSync10(SESSION_CACHE)) mkdirSync5(SESSION_CACHE, { recursive: true });
|
|
3786
|
-
|
|
3787
|
+
writeFileSync6(DEBOUNCE_FILE, JSON.stringify(state));
|
|
3787
3788
|
} catch {
|
|
3788
3789
|
}
|
|
3789
3790
|
}
|
|
@@ -3972,7 +3973,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3972
3973
|
const transport = getTransport();
|
|
3973
3974
|
const sessionName = employeeSessionName(employeeName, exeSession, opts?.instance);
|
|
3974
3975
|
const instanceLabel = opts?.instance != null && opts.instance > 0 ? `${employeeName}${opts.instance}` : employeeName;
|
|
3975
|
-
const logDir = path14.join(
|
|
3976
|
+
const logDir = path14.join(os7.homedir(), ".exe-os", "session-logs");
|
|
3976
3977
|
const logFile = path14.join(logDir, `${instanceLabel}-${Date.now()}.log`);
|
|
3977
3978
|
if (!existsSync10(logDir)) {
|
|
3978
3979
|
mkdirSync5(logDir, { recursive: true });
|
|
@@ -3988,7 +3989,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3988
3989
|
} catch {
|
|
3989
3990
|
}
|
|
3990
3991
|
try {
|
|
3991
|
-
const claudeJsonPath = path14.join(
|
|
3992
|
+
const claudeJsonPath = path14.join(os7.homedir(), ".claude.json");
|
|
3992
3993
|
let claudeJson = {};
|
|
3993
3994
|
try {
|
|
3994
3995
|
claudeJson = JSON.parse(readFileSync9(claudeJsonPath, "utf8"));
|
|
@@ -3999,11 +4000,11 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
3999
4000
|
const trustDir = opts?.cwd ?? projectDir;
|
|
4000
4001
|
if (!projects[trustDir]) projects[trustDir] = {};
|
|
4001
4002
|
projects[trustDir].hasTrustDialogAccepted = true;
|
|
4002
|
-
|
|
4003
|
+
writeFileSync6(claudeJsonPath, JSON.stringify(claudeJson, null, 2) + "\n");
|
|
4003
4004
|
} catch {
|
|
4004
4005
|
}
|
|
4005
4006
|
try {
|
|
4006
|
-
const settingsDir = path14.join(
|
|
4007
|
+
const settingsDir = path14.join(os7.homedir(), ".claude", "projects");
|
|
4007
4008
|
const normalizedKey = (opts?.cwd ?? projectDir).replace(/\//g, "-").replace(/^-/, "");
|
|
4008
4009
|
const projSettingsDir = path14.join(settingsDir, normalizedKey);
|
|
4009
4010
|
const settingsPath = path14.join(projSettingsDir, "settings.json");
|
|
@@ -4038,7 +4039,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
4038
4039
|
perms.allow = allow;
|
|
4039
4040
|
settings.permissions = perms;
|
|
4040
4041
|
mkdirSync5(projSettingsDir, { recursive: true });
|
|
4041
|
-
|
|
4042
|
+
writeFileSync6(settingsPath, JSON.stringify(settings, null, 2) + "\n");
|
|
4042
4043
|
}
|
|
4043
4044
|
} catch {
|
|
4044
4045
|
}
|
|
@@ -4051,7 +4052,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
4051
4052
|
let legacyFallbackWarned = false;
|
|
4052
4053
|
if (!useExeAgent && !useBinSymlink) {
|
|
4053
4054
|
const identityPath = path14.join(
|
|
4054
|
-
|
|
4055
|
+
os7.homedir(),
|
|
4055
4056
|
".exe-os",
|
|
4056
4057
|
"identity",
|
|
4057
4058
|
`${employeeName}.md`
|
|
@@ -4081,7 +4082,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
4081
4082
|
}
|
|
4082
4083
|
let sessionContextFlag = "";
|
|
4083
4084
|
try {
|
|
4084
|
-
const ctxDir = path14.join(
|
|
4085
|
+
const ctxDir = path14.join(os7.homedir(), ".exe-os", "session-cache");
|
|
4085
4086
|
mkdirSync5(ctxDir, { recursive: true });
|
|
4086
4087
|
const ctxFile = path14.join(ctxDir, `session-context-${sessionName}.md`);
|
|
4087
4088
|
const ctxContent = [
|
|
@@ -4090,7 +4091,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
4090
4091
|
`Your parent exe session is ${exeSession}.`,
|
|
4091
4092
|
`Your employees (if any) use the -${exeSession} suffix (e.g., tom-${exeSession}).`
|
|
4092
4093
|
].join("\n");
|
|
4093
|
-
|
|
4094
|
+
writeFileSync6(ctxFile, ctxContent);
|
|
4094
4095
|
sessionContextFlag = ` --append-system-prompt-file ${ctxFile}`;
|
|
4095
4096
|
} catch {
|
|
4096
4097
|
}
|
|
@@ -4129,7 +4130,7 @@ function spawnEmployee(employeeName, exeSession, projectDir, opts) {
|
|
|
4129
4130
|
try {
|
|
4130
4131
|
const mySession = getMySession();
|
|
4131
4132
|
const dispatchInfo = path14.join(SESSION_CACHE, `dispatch-info-${sessionName}.json`);
|
|
4132
|
-
|
|
4133
|
+
writeFileSync6(dispatchInfo, JSON.stringify({
|
|
4133
4134
|
dispatchedBy: mySession,
|
|
4134
4135
|
rootExe: exeSession,
|
|
4135
4136
|
provider: useBinSymlink ? ccProvider : useExeAgent ? opts.provider : "anthropic",
|
|
@@ -4192,13 +4193,13 @@ var init_tmux_routing = __esm({
|
|
|
4192
4193
|
init_provider_table();
|
|
4193
4194
|
init_intercom_queue();
|
|
4194
4195
|
init_plan_limits();
|
|
4195
|
-
SPAWN_LOCK_DIR = path14.join(
|
|
4196
|
-
SESSION_CACHE = path14.join(
|
|
4196
|
+
SPAWN_LOCK_DIR = path14.join(os7.homedir(), ".exe-os", "spawn-locks");
|
|
4197
|
+
SESSION_CACHE = path14.join(os7.homedir(), ".exe-os", "session-cache");
|
|
4197
4198
|
BEHAVIORS_EXPORT_TIMEOUT_MS = 1e4;
|
|
4198
4199
|
VALID_SESSION_NAME = /^[a-z]+\d*-[a-zA-Z0-9_]+$/;
|
|
4199
4200
|
VERIFY_PANE_LINES = 200;
|
|
4200
4201
|
INTERCOM_DEBOUNCE_MS = 3e4;
|
|
4201
|
-
INTERCOM_LOG2 = path14.join(
|
|
4202
|
+
INTERCOM_LOG2 = path14.join(os7.homedir(), ".exe-os", "intercom.log");
|
|
4202
4203
|
DEBOUNCE_FILE = path14.join(SESSION_CACHE, "intercom-debounce.json");
|
|
4203
4204
|
DEBOUNCE_CLEANUP_AGE_MS = 5 * 60 * 1e3;
|
|
4204
4205
|
BUSY_PATTERN = /[✻✽✶✳·].*…|Running…/;
|
|
@@ -4218,9 +4219,9 @@ var init_memory = __esm({
|
|
|
4218
4219
|
import { readFile as readFile4, writeFile as writeFile5, unlink, mkdir as mkdir4, chmod as chmod2 } from "fs/promises";
|
|
4219
4220
|
import { existsSync as existsSync11 } from "fs";
|
|
4220
4221
|
import path15 from "path";
|
|
4221
|
-
import
|
|
4222
|
+
import os8 from "os";
|
|
4222
4223
|
function getKeyDir() {
|
|
4223
|
-
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path15.join(
|
|
4224
|
+
return process.env.EXE_OS_DIR ?? process.env.EXE_MEM_DIR ?? path15.join(os8.homedir(), ".exe-os");
|
|
4224
4225
|
}
|
|
4225
4226
|
function getKeyPath() {
|
|
4226
4227
|
return path15.join(getKeyDir(), "master.key");
|
|
@@ -5780,7 +5781,7 @@ var init_crm_bridge = __esm({
|
|
|
5780
5781
|
import net from "net";
|
|
5781
5782
|
import { spawn } from "child_process";
|
|
5782
5783
|
import { randomUUID as randomUUID6 } from "crypto";
|
|
5783
|
-
import { existsSync as existsSync13, unlinkSync as
|
|
5784
|
+
import { existsSync as existsSync13, unlinkSync as unlinkSync6, readFileSync as readFileSync10, openSync, closeSync, statSync } from "fs";
|
|
5784
5785
|
import path17 from "path";
|
|
5785
5786
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
5786
5787
|
function handleData(chunk) {
|
|
@@ -5820,11 +5821,11 @@ function cleanupStaleFiles() {
|
|
|
5820
5821
|
} catch {
|
|
5821
5822
|
}
|
|
5822
5823
|
try {
|
|
5823
|
-
|
|
5824
|
+
unlinkSync6(PID_PATH);
|
|
5824
5825
|
} catch {
|
|
5825
5826
|
}
|
|
5826
5827
|
try {
|
|
5827
|
-
|
|
5828
|
+
unlinkSync6(SOCKET_PATH);
|
|
5828
5829
|
} catch {
|
|
5829
5830
|
}
|
|
5830
5831
|
}
|
|
@@ -5886,7 +5887,7 @@ function acquireSpawnLock2() {
|
|
|
5886
5887
|
const stat = statSync(SPAWN_LOCK_PATH);
|
|
5887
5888
|
if (Date.now() - stat.mtimeMs > SPAWN_LOCK_STALE_MS) {
|
|
5888
5889
|
try {
|
|
5889
|
-
|
|
5890
|
+
unlinkSync6(SPAWN_LOCK_PATH);
|
|
5890
5891
|
} catch {
|
|
5891
5892
|
}
|
|
5892
5893
|
try {
|
|
@@ -5903,7 +5904,7 @@ function acquireSpawnLock2() {
|
|
|
5903
5904
|
}
|
|
5904
5905
|
function releaseSpawnLock2() {
|
|
5905
5906
|
try {
|
|
5906
|
-
|
|
5907
|
+
unlinkSync6(SPAWN_LOCK_PATH);
|
|
5907
5908
|
} catch {
|
|
5908
5909
|
}
|
|
5909
5910
|
}
|
|
@@ -6034,11 +6035,11 @@ function killAndRespawnDaemon() {
|
|
|
6034
6035
|
_connected = false;
|
|
6035
6036
|
_buffer = "";
|
|
6036
6037
|
try {
|
|
6037
|
-
|
|
6038
|
+
unlinkSync6(PID_PATH);
|
|
6038
6039
|
} catch {
|
|
6039
6040
|
}
|
|
6040
6041
|
try {
|
|
6041
|
-
|
|
6042
|
+
unlinkSync6(SOCKET_PATH);
|
|
6042
6043
|
} catch {
|
|
6043
6044
|
}
|
|
6044
6045
|
spawnDaemon();
|
|
@@ -11648,12 +11649,12 @@ var SlackAdapter = class {
|
|
|
11648
11649
|
// src/gateway/adapters/imessage.ts
|
|
11649
11650
|
import { execFile } from "child_process";
|
|
11650
11651
|
import { promisify } from "util";
|
|
11651
|
-
import
|
|
11652
|
+
import os9 from "os";
|
|
11652
11653
|
import path18 from "path";
|
|
11653
11654
|
var execFileAsync = promisify(execFile);
|
|
11654
11655
|
var POLL_INTERVAL_MS = 5e3;
|
|
11655
11656
|
var MESSAGES_DB_PATH = path18.join(
|
|
11656
|
-
process.env.HOME ??
|
|
11657
|
+
process.env.HOME ?? os9.homedir(),
|
|
11657
11658
|
"Library/Messages/chat.db"
|
|
11658
11659
|
);
|
|
11659
11660
|
var IMessageAdapter = class {
|
|
@@ -12496,11 +12497,11 @@ async function ensureCRMContact(info) {
|
|
|
12496
12497
|
}
|
|
12497
12498
|
|
|
12498
12499
|
// src/automation/trigger-engine.ts
|
|
12499
|
-
import { readFileSync as readFileSync12, writeFileSync as
|
|
12500
|
+
import { readFileSync as readFileSync12, writeFileSync as writeFileSync7, existsSync as existsSync14, mkdirSync as mkdirSync8 } from "fs";
|
|
12500
12501
|
import { randomUUID as randomUUID15 } from "crypto";
|
|
12501
12502
|
import path19 from "path";
|
|
12502
|
-
import
|
|
12503
|
-
var TRIGGERS_PATH = path19.join(
|
|
12503
|
+
import os10 from "os";
|
|
12504
|
+
var TRIGGERS_PATH = path19.join(os10.homedir(), ".exe-os", "triggers.json");
|
|
12504
12505
|
var GRAPH_API_VERSION = "v21.0";
|
|
12505
12506
|
function substituteTemplate(template, record) {
|
|
12506
12507
|
return template.replace(
|
package/dist/lib/cloud-sync.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/lib/cloud-sync.ts
|
|
2
|
-
import { readFileSync as readFileSync4, writeFileSync as
|
|
2
|
+
import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, existsSync as existsSync4, readdirSync, mkdirSync as mkdirSync2, appendFileSync, unlinkSync as unlinkSync2, openSync, closeSync } from "fs";
|
|
3
3
|
import crypto2 from "crypto";
|
|
4
4
|
import path4 from "path";
|
|
5
5
|
import { homedir } from "os";
|
|
@@ -188,9 +188,10 @@ function loadDeviceId() {
|
|
|
188
188
|
|
|
189
189
|
// src/lib/employees.ts
|
|
190
190
|
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
191
|
-
import { existsSync as existsSync3, symlinkSync, readlinkSync, readFileSync as readFileSync3 } from "fs";
|
|
191
|
+
import { existsSync as existsSync3, symlinkSync, readlinkSync, readFileSync as readFileSync3, renameSync as renameSync2, unlinkSync, writeFileSync as writeFileSync2 } from "fs";
|
|
192
192
|
import { execSync } from "child_process";
|
|
193
193
|
import path3 from "path";
|
|
194
|
+
import os2 from "os";
|
|
194
195
|
var EMPLOYEES_PATH = path3.join(EXE_AI_DIR, "exe-employees.json");
|
|
195
196
|
async function loadEmployees(employeesPath = EMPLOYEES_PATH) {
|
|
196
197
|
if (!existsSync3(employeesPath)) {
|
|
@@ -269,7 +270,7 @@ async function withRosterLock(fn) {
|
|
|
269
270
|
try {
|
|
270
271
|
const fd = openSync(ROSTER_LOCK_PATH, "wx");
|
|
271
272
|
closeSync(fd);
|
|
272
|
-
|
|
273
|
+
writeFileSync3(ROSTER_LOCK_PATH, String(Date.now()));
|
|
273
274
|
} catch (err) {
|
|
274
275
|
if (err.code === "EEXIST") {
|
|
275
276
|
try {
|
|
@@ -277,10 +278,10 @@ async function withRosterLock(fn) {
|
|
|
277
278
|
if (Date.now() - ts < LOCK_STALE_MS) {
|
|
278
279
|
throw new Error("Roster merge already in progress \u2014 another sync is running");
|
|
279
280
|
}
|
|
280
|
-
|
|
281
|
+
unlinkSync2(ROSTER_LOCK_PATH);
|
|
281
282
|
const fd = openSync(ROSTER_LOCK_PATH, "wx");
|
|
282
283
|
closeSync(fd);
|
|
283
|
-
|
|
284
|
+
writeFileSync3(ROSTER_LOCK_PATH, String(Date.now()));
|
|
284
285
|
} catch (retryErr) {
|
|
285
286
|
if (retryErr instanceof Error && retryErr.message.includes("already in progress")) throw retryErr;
|
|
286
287
|
throw new Error("Roster merge already in progress \u2014 another sync is running");
|
|
@@ -293,7 +294,7 @@ async function withRosterLock(fn) {
|
|
|
293
294
|
return await fn();
|
|
294
295
|
} finally {
|
|
295
296
|
try {
|
|
296
|
-
|
|
297
|
+
unlinkSync2(ROSTER_LOCK_PATH);
|
|
297
298
|
} catch {
|
|
298
299
|
}
|
|
299
300
|
}
|
|
@@ -594,13 +595,13 @@ function recordRosterDeletion(name) {
|
|
|
594
595
|
} catch {
|
|
595
596
|
}
|
|
596
597
|
if (!deletions.includes(name)) deletions.push(name);
|
|
597
|
-
|
|
598
|
+
writeFileSync3(ROSTER_DELETIONS_PATH, JSON.stringify(deletions));
|
|
598
599
|
}
|
|
599
600
|
function consumeRosterDeletions() {
|
|
600
601
|
try {
|
|
601
602
|
if (!existsSync4(ROSTER_DELETIONS_PATH)) return [];
|
|
602
603
|
const deletions = JSON.parse(readFileSync4(ROSTER_DELETIONS_PATH, "utf-8"));
|
|
603
|
-
|
|
604
|
+
writeFileSync3(ROSTER_DELETIONS_PATH, "[]");
|
|
604
605
|
return deletions;
|
|
605
606
|
} catch {
|
|
606
607
|
return [];
|
|
@@ -716,7 +717,7 @@ function mergeConfig(remoteConfig, configPath) {
|
|
|
716
717
|
const merged = { ...remoteConfig, ...local };
|
|
717
718
|
const dir = path4.dirname(cfgPath);
|
|
718
719
|
if (!existsSync4(dir)) mkdirSync2(dir, { recursive: true });
|
|
719
|
-
|
|
720
|
+
writeFileSync3(cfgPath, JSON.stringify(merged, null, 2), "utf-8");
|
|
720
721
|
}
|
|
721
722
|
async function mergeRosterFromRemote(remote, paths) {
|
|
722
723
|
return withRosterLock(async () => {
|
|
@@ -736,7 +737,11 @@ async function mergeRosterFromRemote(remote, paths) {
|
|
|
736
737
|
} catch {
|
|
737
738
|
}
|
|
738
739
|
}
|
|
739
|
-
const
|
|
740
|
+
const lookupKey = `${remoteEmp.name}.md`;
|
|
741
|
+
const matchedKey = Object.keys(remote.identities).find(
|
|
742
|
+
(k) => k.toLowerCase() === lookupKey.toLowerCase()
|
|
743
|
+
) ?? lookupKey;
|
|
744
|
+
const remoteIdentity = remote.identities[matchedKey];
|
|
740
745
|
if (remoteIdentity) {
|
|
741
746
|
if (!existsSync4(identityDir)) mkdirSync2(identityDir, { recursive: true });
|
|
742
747
|
const idPath = path4.join(identityDir, `${remoteEmp.name}.md`);
|
|
@@ -746,7 +751,7 @@ async function mergeRosterFromRemote(remote, paths) {
|
|
|
746
751
|
} catch {
|
|
747
752
|
}
|
|
748
753
|
if (localIdentity !== remoteIdentity) {
|
|
749
|
-
|
|
754
|
+
writeFileSync3(idPath, remoteIdentity, "utf-8");
|
|
750
755
|
identitiesUpdated++;
|
|
751
756
|
}
|
|
752
757
|
}
|
package/dist/lib/employees.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
// src/lib/employees.ts
|
|
2
2
|
import { readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
3
|
-
import { existsSync as existsSync2, symlinkSync, readlinkSync, readFileSync as readFileSync2 } from "fs";
|
|
3
|
+
import { existsSync as existsSync2, symlinkSync, readlinkSync, readFileSync as readFileSync2, renameSync as renameSync2, unlinkSync, writeFileSync } from "fs";
|
|
4
4
|
import { execSync } from "child_process";
|
|
5
5
|
import path2 from "path";
|
|
6
|
+
import os2 from "os";
|
|
6
7
|
|
|
7
8
|
// src/lib/config.ts
|
|
8
9
|
import { readFile, writeFile, mkdir, chmod } from "fs/promises";
|
|
@@ -165,6 +166,36 @@ function addEmployee(employees, employee) {
|
|
|
165
166
|
}
|
|
166
167
|
return [...employees, normalized];
|
|
167
168
|
}
|
|
169
|
+
async function normalizeRosterCase(rosterPath) {
|
|
170
|
+
const employees = await loadEmployees(rosterPath);
|
|
171
|
+
let changed = false;
|
|
172
|
+
for (const emp of employees) {
|
|
173
|
+
if (emp.name !== emp.name.toLowerCase()) {
|
|
174
|
+
const oldName = emp.name;
|
|
175
|
+
emp.name = emp.name.toLowerCase();
|
|
176
|
+
changed = true;
|
|
177
|
+
try {
|
|
178
|
+
const identityDir = path2.join(os2.homedir(), ".exe-os", "identity");
|
|
179
|
+
const oldPath = path2.join(identityDir, `${oldName}.md`);
|
|
180
|
+
const newPath = path2.join(identityDir, `${emp.name}.md`);
|
|
181
|
+
if (existsSync2(oldPath) && !existsSync2(newPath)) {
|
|
182
|
+
renameSync2(oldPath, newPath);
|
|
183
|
+
} else if (existsSync2(oldPath) && oldPath !== newPath) {
|
|
184
|
+
const content = readFileSync2(oldPath, "utf-8");
|
|
185
|
+
writeFileSync(newPath, content, "utf-8");
|
|
186
|
+
if (oldPath.toLowerCase() !== newPath.toLowerCase()) {
|
|
187
|
+
unlinkSync(oldPath);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
} catch {
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
if (changed) {
|
|
195
|
+
await saveEmployees(employees, rosterPath);
|
|
196
|
+
}
|
|
197
|
+
return changed;
|
|
198
|
+
}
|
|
168
199
|
function findExeBin() {
|
|
169
200
|
try {
|
|
170
201
|
return execSync(process.platform === "win32" ? "where exe-os" : "which exe-os", { encoding: "utf8" }).trim();
|
|
@@ -215,6 +246,7 @@ export {
|
|
|
215
246
|
isMultiInstance,
|
|
216
247
|
loadEmployees,
|
|
217
248
|
loadEmployeesSync,
|
|
249
|
+
normalizeRosterCase,
|
|
218
250
|
registerBinSymlinks,
|
|
219
251
|
saveEmployees,
|
|
220
252
|
validateEmployeeName
|