@askexenow/exe-os 0.9.123 → 0.9.125
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/lib/exe-daemon.js +83 -1
- package/package.json +1 -1
package/dist/lib/exe-daemon.js
CHANGED
|
@@ -18913,6 +18913,56 @@ function startServer() {
|
|
|
18913
18913
|
});
|
|
18914
18914
|
_mcpHttpReady = startMcpHttpServer();
|
|
18915
18915
|
}
|
|
18916
|
+
var FIXED_MCP_PORT = 48739;
|
|
18917
|
+
async function resolveAndClaimPort() {
|
|
18918
|
+
if (process.env.EXE_MCP_PORT) {
|
|
18919
|
+
const envPort = parseInt(process.env.EXE_MCP_PORT, 10);
|
|
18920
|
+
if (envPort > 0) return envPort;
|
|
18921
|
+
}
|
|
18922
|
+
const targetPort = FIXED_MCP_PORT;
|
|
18923
|
+
try {
|
|
18924
|
+
const http = await import("http");
|
|
18925
|
+
const isHealthy = await new Promise((resolve) => {
|
|
18926
|
+
const req = http.request(
|
|
18927
|
+
{ hostname: "127.0.0.1", port: targetPort, path: "/health", method: "GET", timeout: 2e3 },
|
|
18928
|
+
(res) => {
|
|
18929
|
+
resolve(res.statusCode === 200);
|
|
18930
|
+
}
|
|
18931
|
+
);
|
|
18932
|
+
req.on("error", () => resolve(false));
|
|
18933
|
+
req.on("timeout", () => {
|
|
18934
|
+
req.destroy();
|
|
18935
|
+
resolve(false);
|
|
18936
|
+
});
|
|
18937
|
+
req.end();
|
|
18938
|
+
});
|
|
18939
|
+
if (isHealthy) {
|
|
18940
|
+
process.stderr.write(`[exed] Port ${targetPort} has a healthy daemon \u2014 exiting (not a duplicate)
|
|
18941
|
+
`);
|
|
18942
|
+
process.exit(0);
|
|
18943
|
+
}
|
|
18944
|
+
} catch {
|
|
18945
|
+
}
|
|
18946
|
+
try {
|
|
18947
|
+
const { execSync: execSync14 } = await import("child_process");
|
|
18948
|
+
const pids = execSync14(`lsof -ti :${targetPort} 2>/dev/null`, { encoding: "utf8" }).trim();
|
|
18949
|
+
if (pids) {
|
|
18950
|
+
process.stderr.write(`[exed] Port ${targetPort} held by PID(s) ${pids.replace(/\n/g, ",")} \u2014 killing
|
|
18951
|
+
`);
|
|
18952
|
+
for (const pid of pids.split("\n").filter(Boolean)) {
|
|
18953
|
+
try {
|
|
18954
|
+
process.kill(parseInt(pid, 10), "SIGTERM");
|
|
18955
|
+
} catch {
|
|
18956
|
+
}
|
|
18957
|
+
}
|
|
18958
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
18959
|
+
}
|
|
18960
|
+
} catch {
|
|
18961
|
+
}
|
|
18962
|
+
process.stderr.write(`[exed] Using fixed MCP port ${targetPort}
|
|
18963
|
+
`);
|
|
18964
|
+
return targetPort;
|
|
18965
|
+
}
|
|
18916
18966
|
async function startMcpHttpServer() {
|
|
18917
18967
|
process.stderr.write("[exed] MCP HTTP: starting setup...\n");
|
|
18918
18968
|
try {
|
|
@@ -19018,7 +19068,7 @@ async function startMcpHttpServer() {
|
|
|
19018
19068
|
`);
|
|
19019
19069
|
});
|
|
19020
19070
|
const transports = /* @__PURE__ */ new Map();
|
|
19021
|
-
const MCP_HTTP_PORT =
|
|
19071
|
+
const MCP_HTTP_PORT = await resolveAndClaimPort();
|
|
19022
19072
|
const MCP_SESSION_TTL_MS = parseDurationMs2(process.env.EXE_MCP_SESSION_TTL_MS, 30 * 60 * 1e3, { allowZero: true });
|
|
19023
19073
|
const MCP_SESSION_SWEEP_MS = parseDurationMs2(process.env.EXE_MCP_SESSION_SWEEP_MS, 60 * 1e3);
|
|
19024
19074
|
const sessionLastSeen = /* @__PURE__ */ new Map();
|
|
@@ -19138,6 +19188,38 @@ async function startMcpHttpServer() {
|
|
|
19138
19188
|
const wrappedMcp = wrapServerWithTelemetry2(sessionMcp);
|
|
19139
19189
|
registerAllTools(wrappedMcp, gateState.license, gateState.hasKey);
|
|
19140
19190
|
await sessionMcp.connect(transport);
|
|
19191
|
+
} else if (sessionId && !transports.has(sessionId) && req.method === "POST") {
|
|
19192
|
+
process.stderr.write(
|
|
19193
|
+
`[exed] MCP session ${sessionId.slice(0, 8)}\u2026 stale \u2014 auto-recovering with new session
|
|
19194
|
+
`
|
|
19195
|
+
);
|
|
19196
|
+
transport = new StreamableHTTPServerTransport({
|
|
19197
|
+
sessionIdGenerator: () => randomUUID5(),
|
|
19198
|
+
onsessioninitialized: (sid) => {
|
|
19199
|
+
transports.set(sid, transport);
|
|
19200
|
+
sessionLastSeen.set(sid, Date.now());
|
|
19201
|
+
sessionDetails.set(sid, { agentId, agentRole, runtime, sessionHint });
|
|
19202
|
+
recordMcpHttpEvent({
|
|
19203
|
+
level: "info",
|
|
19204
|
+
message: "session_recovered",
|
|
19205
|
+
sessionId: sid,
|
|
19206
|
+
agentId,
|
|
19207
|
+
agentRole,
|
|
19208
|
+
runtime,
|
|
19209
|
+
activeSessions: transports.size
|
|
19210
|
+
});
|
|
19211
|
+
}
|
|
19212
|
+
});
|
|
19213
|
+
transport.onclose = () => {
|
|
19214
|
+
const sid = Array.from(transports.entries()).find(([, t]) => t === transport)?.[0];
|
|
19215
|
+
if (sid) closeMcpSession2(sid, "session_closed");
|
|
19216
|
+
};
|
|
19217
|
+
const sessionMcp = new McpServer({ name: "exe-os", version: "1.3.0" });
|
|
19218
|
+
const gateState = getCachedLicenseGate2();
|
|
19219
|
+
const { wrapServerWithTelemetry: wrapServerWithTelemetry2 } = await Promise.resolve().then(() => (init_tool_telemetry(), tool_telemetry_exports));
|
|
19220
|
+
const wrappedMcp = wrapServerWithTelemetry2(sessionMcp);
|
|
19221
|
+
registerAllTools(wrappedMcp, gateState.license, gateState.hasKey);
|
|
19222
|
+
await sessionMcp.connect(transport);
|
|
19141
19223
|
} else {
|
|
19142
19224
|
const message = sessionId ? "Bad Request: MCP session is stale or unknown; reconnect MCP client" : "Bad Request: missing MCP session; initialize before tool calls";
|
|
19143
19225
|
sendJsonRpcError2(res, 400, message, getJsonRpcId2(parsedBody), {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@askexenow/exe-os",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.125",
|
|
4
4
|
"description": "AI employee operating system — persistent memory, task management, and multi-agent coordination for Claude Code.",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE",
|
|
6
6
|
"type": "module",
|