@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.
@@ -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 = parseInt(process.env.EXE_MCP_PORT || "48739", 10);
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.123",
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",