@askexenow/exe-os 0.8.51 → 0.8.53
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/install.js +57 -11
- package/dist/lib/exe-daemon.js +87 -1
- package/package.json +1 -1
package/dist/bin/install.js
CHANGED
|
@@ -672,24 +672,70 @@ function summarizeSymlinkResults(results) {
|
|
|
672
672
|
}
|
|
673
673
|
|
|
674
674
|
// src/bin/install.ts
|
|
675
|
-
import { existsSync as existsSync5, readFileSync as readFileSync4, unlinkSync } from "fs";
|
|
675
|
+
import { existsSync as existsSync5, readFileSync as readFileSync4, unlinkSync, openSync, closeSync } from "fs";
|
|
676
|
+
import { spawn } from "child_process";
|
|
676
677
|
import path5 from "path";
|
|
677
678
|
import { homedir } from "os";
|
|
678
|
-
|
|
679
|
+
var EXE_DIR = path5.join(homedir(), ".exe-os");
|
|
680
|
+
function restartDaemon() {
|
|
681
|
+
const pidPath = path5.join(EXE_DIR, "exed.pid");
|
|
682
|
+
const sockPath = path5.join(EXE_DIR, "exed.sock");
|
|
679
683
|
try {
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
684
|
+
if (existsSync5(pidPath)) {
|
|
685
|
+
const pid = parseInt(readFileSync4(pidPath, "utf8").trim(), 10);
|
|
686
|
+
if (!isNaN(pid) && pid > 0) {
|
|
687
|
+
try {
|
|
688
|
+
process.kill(pid, "SIGTERM");
|
|
689
|
+
} catch {
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
try {
|
|
693
|
+
unlinkSync(pidPath);
|
|
694
|
+
} catch {
|
|
695
|
+
}
|
|
696
|
+
}
|
|
685
697
|
try {
|
|
686
|
-
unlinkSync(
|
|
698
|
+
unlinkSync(sockPath);
|
|
687
699
|
} catch {
|
|
688
700
|
}
|
|
689
|
-
process.stderr.write(`exe-os: restarted daemon (PID ${pid}) for new version
|
|
690
|
-
`);
|
|
691
701
|
} catch {
|
|
692
702
|
}
|
|
703
|
+
try {
|
|
704
|
+
const pkgRoot = resolvePackageRoot();
|
|
705
|
+
const daemonPath = path5.join(pkgRoot, "dist", "lib", "exe-daemon.js");
|
|
706
|
+
if (!existsSync5(daemonPath)) {
|
|
707
|
+
process.stderr.write(`exe-os: daemon not found at ${daemonPath} \u2014 skipping respawn
|
|
708
|
+
`);
|
|
709
|
+
return;
|
|
710
|
+
}
|
|
711
|
+
const logPath = path5.join(EXE_DIR, "exed.log");
|
|
712
|
+
let stderrFd = "ignore";
|
|
713
|
+
try {
|
|
714
|
+
stderrFd = openSync(logPath, "a");
|
|
715
|
+
} catch {
|
|
716
|
+
}
|
|
717
|
+
const child = spawn(process.execPath, [daemonPath], {
|
|
718
|
+
detached: true,
|
|
719
|
+
stdio: ["ignore", "ignore", stderrFd],
|
|
720
|
+
env: {
|
|
721
|
+
...process.env,
|
|
722
|
+
EXE_DAEMON_SOCK: sockPath,
|
|
723
|
+
EXE_DAEMON_PID: pidPath
|
|
724
|
+
}
|
|
725
|
+
});
|
|
726
|
+
child.unref();
|
|
727
|
+
if (typeof stderrFd === "number") {
|
|
728
|
+
try {
|
|
729
|
+
closeSync(stderrFd);
|
|
730
|
+
} catch {
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
process.stderr.write(`exe-os: daemon restarted (new PID spawned)
|
|
734
|
+
`);
|
|
735
|
+
} catch (err) {
|
|
736
|
+
process.stderr.write(`exe-os: daemon respawn failed: ${err instanceof Error ? err.message : String(err)}
|
|
737
|
+
`);
|
|
738
|
+
}
|
|
693
739
|
}
|
|
694
740
|
var args = process.argv.slice(2);
|
|
695
741
|
if (args.includes("--commands-only")) {
|
|
@@ -707,7 +753,7 @@ if (args.includes("--commands-only")) {
|
|
|
707
753
|
} else if (args.includes("--global")) {
|
|
708
754
|
try {
|
|
709
755
|
await runInstaller();
|
|
710
|
-
|
|
756
|
+
restartDaemon();
|
|
711
757
|
} catch (err) {
|
|
712
758
|
console.error(
|
|
713
759
|
"Installation failed:",
|
package/dist/lib/exe-daemon.js
CHANGED
|
@@ -5854,15 +5854,18 @@ var daemon_orchestration_exports = {};
|
|
|
5854
5854
|
__export(daemon_orchestration_exports, {
|
|
5855
5855
|
IDLE_KILL_INTERCOM_ACK_WINDOW_MS: () => IDLE_KILL_INTERCOM_ACK_WINDOW_MS,
|
|
5856
5856
|
IDLE_NUDGE_DEDUP_MS: () => IDLE_NUDGE_DEDUP_MS,
|
|
5857
|
+
REVIEW_NUDGE_COOLDOWN_MS: () => REVIEW_NUDGE_COOLDOWN_MS,
|
|
5857
5858
|
SESSION_CONTEXT_THRESHOLD_PCT: () => SESSION_CONTEXT_THRESHOLD_PCT,
|
|
5858
5859
|
SESSION_TTL_HOURS: () => SESSION_TTL_HOURS,
|
|
5859
5860
|
checkSessionTTL: () => checkSessionTTL,
|
|
5860
5861
|
classifyTtlKillReason: () => classifyTtlKillReason,
|
|
5861
5862
|
createIdleKillRealDeps: () => createIdleKillRealDeps,
|
|
5862
5863
|
createIdleNudgeRealDeps: () => createIdleNudgeRealDeps,
|
|
5864
|
+
createReviewNudgeRealDeps: () => createReviewNudgeRealDeps,
|
|
5863
5865
|
createSessionTTLRealDeps: () => createSessionTTLRealDeps,
|
|
5864
5866
|
pollIdleEmployees: () => pollIdleEmployees,
|
|
5865
5867
|
pollIdleKill: () => pollIdleKill,
|
|
5868
|
+
pollReviewNudge: () => pollReviewNudge,
|
|
5866
5869
|
shouldKillIdleSession: () => shouldKillIdleSession,
|
|
5867
5870
|
shouldKillSession: () => shouldKillSession,
|
|
5868
5871
|
shouldNudgeEmployee: () => shouldNudgeEmployee
|
|
@@ -6011,6 +6014,64 @@ async function pollIdleKill(deps, idleTickCounts, opts) {
|
|
|
6011
6014
|
}
|
|
6012
6015
|
return killed;
|
|
6013
6016
|
}
|
|
6017
|
+
async function pollReviewNudge(deps, state) {
|
|
6018
|
+
let sessions;
|
|
6019
|
+
try {
|
|
6020
|
+
sessions = deps.listTmuxSessions().filter((s) => /^exe\d+$/.test(s));
|
|
6021
|
+
} catch {
|
|
6022
|
+
return [];
|
|
6023
|
+
}
|
|
6024
|
+
if (sessions.length === 0) return [];
|
|
6025
|
+
const nudged = [];
|
|
6026
|
+
const now = Date.now();
|
|
6027
|
+
for (const exeSession of sessions) {
|
|
6028
|
+
const prev = state.lastNudge.get(exeSession);
|
|
6029
|
+
if (prev && now - prev.at < REVIEW_NUDGE_COOLDOWN_MS) continue;
|
|
6030
|
+
const sessionState = deps.getSessionState(exeSession);
|
|
6031
|
+
if (sessionState !== "idle") continue;
|
|
6032
|
+
let count;
|
|
6033
|
+
try {
|
|
6034
|
+
count = await deps.countReviewsForScope(exeSession);
|
|
6035
|
+
} catch {
|
|
6036
|
+
continue;
|
|
6037
|
+
}
|
|
6038
|
+
if (count === 0) continue;
|
|
6039
|
+
if (prev && prev.count === count) continue;
|
|
6040
|
+
try {
|
|
6041
|
+
deps.sendNudge(exeSession);
|
|
6042
|
+
state.lastNudge.set(exeSession, { at: now, count });
|
|
6043
|
+
nudged.push(exeSession);
|
|
6044
|
+
} catch {
|
|
6045
|
+
}
|
|
6046
|
+
}
|
|
6047
|
+
return nudged;
|
|
6048
|
+
}
|
|
6049
|
+
function createReviewNudgeRealDeps(getClient2) {
|
|
6050
|
+
return {
|
|
6051
|
+
listTmuxSessions: () => {
|
|
6052
|
+
const { listTmuxSessions: listTmuxSessions2 } = (init_tmux_status(), __toCommonJS(tmux_status_exports));
|
|
6053
|
+
return listTmuxSessions2();
|
|
6054
|
+
},
|
|
6055
|
+
getSessionState: (sessionName) => {
|
|
6056
|
+
const { getSessionState: getSessionState2 } = (init_tmux_routing(), __toCommonJS(tmux_routing_exports));
|
|
6057
|
+
return getSessionState2(sessionName);
|
|
6058
|
+
},
|
|
6059
|
+
countReviewsForScope: async (sessionScope) => {
|
|
6060
|
+
const client = getClient2();
|
|
6061
|
+
const result = await client.execute({
|
|
6062
|
+
sql: `SELECT COUNT(*) as cnt FROM tasks
|
|
6063
|
+
WHERE status = 'needs_review'
|
|
6064
|
+
AND (session_scope = ? OR session_scope IS NULL)`,
|
|
6065
|
+
args: [sessionScope]
|
|
6066
|
+
});
|
|
6067
|
+
return Number(result.rows[0]?.cnt ?? 0);
|
|
6068
|
+
},
|
|
6069
|
+
sendNudge: (sessionName) => {
|
|
6070
|
+
const { getTransport: getTransport2 } = (init_transport(), __toCommonJS(transport_exports));
|
|
6071
|
+
getTransport2().sendKeys(sessionName, "check reviews");
|
|
6072
|
+
}
|
|
6073
|
+
};
|
|
6074
|
+
}
|
|
6014
6075
|
function createIdleNudgeRealDeps(getClient2) {
|
|
6015
6076
|
return {
|
|
6016
6077
|
listRegisteredSessions: () => {
|
|
@@ -6108,7 +6169,7 @@ function createIdleKillRealDeps(getClient2, intercomAckWindowMs) {
|
|
|
6108
6169
|
}
|
|
6109
6170
|
};
|
|
6110
6171
|
}
|
|
6111
|
-
var IDLE_NUDGE_DEDUP_MS, SESSION_TTL_HOURS, SESSION_CONTEXT_THRESHOLD_PCT, IDLE_KILL_INTERCOM_ACK_WINDOW_MS;
|
|
6172
|
+
var IDLE_NUDGE_DEDUP_MS, SESSION_TTL_HOURS, SESSION_CONTEXT_THRESHOLD_PCT, IDLE_KILL_INTERCOM_ACK_WINDOW_MS, REVIEW_NUDGE_COOLDOWN_MS;
|
|
6112
6173
|
var init_daemon_orchestration = __esm({
|
|
6113
6174
|
"src/lib/daemon-orchestration.ts"() {
|
|
6114
6175
|
"use strict";
|
|
@@ -6117,6 +6178,7 @@ var init_daemon_orchestration = __esm({
|
|
|
6117
6178
|
SESSION_TTL_HOURS = 4;
|
|
6118
6179
|
SESSION_CONTEXT_THRESHOLD_PCT = 50;
|
|
6119
6180
|
IDLE_KILL_INTERCOM_ACK_WINDOW_MS = 1e4;
|
|
6181
|
+
REVIEW_NUDGE_COOLDOWN_MS = 3e5;
|
|
6120
6182
|
}
|
|
6121
6183
|
});
|
|
6122
6184
|
|
|
@@ -8557,6 +8619,29 @@ function startIdleNudge() {
|
|
|
8557
8619
|
process.stderr.write(`[exed] Idle nudge started (every ${REVIEW_POLL_INTERVAL_MS / 6e4}m)
|
|
8558
8620
|
`);
|
|
8559
8621
|
}
|
|
8622
|
+
var _reviewNudgeState = { lastNudge: /* @__PURE__ */ new Map() };
|
|
8623
|
+
function startReviewNudge() {
|
|
8624
|
+
const tick = async () => {
|
|
8625
|
+
if (!await ensureStoreForPolling()) return;
|
|
8626
|
+
try {
|
|
8627
|
+
const { getClient: getClient2 } = await Promise.resolve().then(() => (init_database(), database_exports));
|
|
8628
|
+
const { pollReviewNudge: pollReviewNudge2, createReviewNudgeRealDeps: createReviewNudgeRealDeps2 } = await Promise.resolve().then(() => (init_daemon_orchestration(), daemon_orchestration_exports));
|
|
8629
|
+
const deps = createReviewNudgeRealDeps2(getClient2);
|
|
8630
|
+
const nudged = await pollReviewNudge2(deps, _reviewNudgeState);
|
|
8631
|
+
for (const s of nudged) {
|
|
8632
|
+
process.stderr.write(`[exed] Review nudge: sent "check reviews" to ${s}
|
|
8633
|
+
`);
|
|
8634
|
+
}
|
|
8635
|
+
} catch (err) {
|
|
8636
|
+
process.stderr.write(`[exed] Review nudge error: ${err instanceof Error ? err.message : String(err)}
|
|
8637
|
+
`);
|
|
8638
|
+
}
|
|
8639
|
+
};
|
|
8640
|
+
const timer = setInterval(() => void tick(), REVIEW_POLL_INTERVAL_MS);
|
|
8641
|
+
timer.unref();
|
|
8642
|
+
process.stderr.write(`[exed] Review nudge started (every ${REVIEW_POLL_INTERVAL_MS / 6e4}m)
|
|
8643
|
+
`);
|
|
8644
|
+
}
|
|
8560
8645
|
var SESSION_TTL_INTERVAL_MS = 5 * 60 * 1e3;
|
|
8561
8646
|
function startSessionTTL() {
|
|
8562
8647
|
const tick = async () => {
|
|
@@ -8921,6 +9006,7 @@ try {
|
|
|
8921
9006
|
startServer();
|
|
8922
9007
|
startReviewPolling();
|
|
8923
9008
|
startIdleNudge();
|
|
9009
|
+
startReviewNudge();
|
|
8924
9010
|
startSessionTTL();
|
|
8925
9011
|
startIdleKill();
|
|
8926
9012
|
startConsolidation();
|
package/package.json
CHANGED