triflux 10.17.1 → 10.17.3
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.
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
{
|
|
10
10
|
"name": "triflux",
|
|
11
11
|
"description": "Tri-CLI orchestrator for Claude Code. Routes tasks across Claude + Codex + Gemini with consensus intelligence, natural language routing, 42 skills, and cross-model review.",
|
|
12
|
-
"version": "10.17.
|
|
12
|
+
"version": "10.17.3",
|
|
13
13
|
"author": {
|
|
14
14
|
"name": "tellang"
|
|
15
15
|
},
|
|
@@ -30,5 +30,5 @@
|
|
|
30
30
|
]
|
|
31
31
|
}
|
|
32
32
|
],
|
|
33
|
-
"version": "10.17.
|
|
33
|
+
"version": "10.17.3"
|
|
34
34
|
}
|
|
@@ -233,6 +233,29 @@ function hasLiveAncestorChain(pid, procMap, protectedPids) {
|
|
|
233
233
|
return false;
|
|
234
234
|
}
|
|
235
235
|
|
|
236
|
+
function hasLiveCliDescendant(pid, procMap) {
|
|
237
|
+
const children = new Map();
|
|
238
|
+
for (const proc of procMap.values()) {
|
|
239
|
+
if (!Number.isFinite(proc.ppid) || proc.ppid <= 0) continue;
|
|
240
|
+
const list = children.get(proc.ppid) || [];
|
|
241
|
+
list.push(proc);
|
|
242
|
+
children.set(proc.ppid, list);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
const visited = new Set();
|
|
246
|
+
const stack = [...(children.get(pid) || [])];
|
|
247
|
+
while (stack.length > 0) {
|
|
248
|
+
const proc = stack.pop();
|
|
249
|
+
if (!proc || visited.has(proc.pid)) continue;
|
|
250
|
+
visited.add(proc.pid);
|
|
251
|
+
if (LIVE_CLI_SESSION_ROOT_NAMES.has(normalizeName(proc.name))) {
|
|
252
|
+
return true;
|
|
253
|
+
}
|
|
254
|
+
stack.push(...(children.get(proc.pid) || []));
|
|
255
|
+
}
|
|
256
|
+
return false;
|
|
257
|
+
}
|
|
258
|
+
|
|
236
259
|
/**
|
|
237
260
|
* Legacy wrapper for scoped orphan node runtime cleanup.
|
|
238
261
|
* @param {Parameters<typeof cleanupOrphanRuntimeProcesses>[0]} opts
|
|
@@ -808,7 +831,8 @@ export function cleanupOrphanRuntimeProcesses({
|
|
|
808
831
|
if (legacy) {
|
|
809
832
|
if (
|
|
810
833
|
LEGACY_ORPHAN_KILLABLE_NAMES.has(name) &&
|
|
811
|
-
!hasLiveAncestorChain(proc.pid, procMap, protectedSet)
|
|
834
|
+
!hasLiveAncestorChain(proc.pid, procMap, protectedSet) &&
|
|
835
|
+
!hasLiveCliDescendant(proc.pid, procMap)
|
|
812
836
|
) {
|
|
813
837
|
shouldKill = true;
|
|
814
838
|
killReason = "legacy_orphan_ancestor_chain_dead";
|
|
@@ -816,7 +840,8 @@ export function cleanupOrphanRuntimeProcesses({
|
|
|
816
840
|
} else if (name === "bun.exe") {
|
|
817
841
|
if (
|
|
818
842
|
hasExactGbrainServe(proc.commandLine) &&
|
|
819
|
-
!hasLiveAncestorChain(proc.pid, procMap, protectedSet)
|
|
843
|
+
!hasLiveAncestorChain(proc.pid, procMap, protectedSet) &&
|
|
844
|
+
!hasLiveCliDescendant(proc.pid, procMap)
|
|
820
845
|
) {
|
|
821
846
|
shouldKill = true;
|
|
822
847
|
killReason = "bun_gbrain_serve_orphan";
|
package/hub/server.mjs
CHANGED
|
@@ -962,6 +962,38 @@ export async function startHub({
|
|
|
962
962
|
const tools = createTools(store, router, hitl, pipe);
|
|
963
963
|
const transports = new Map();
|
|
964
964
|
|
|
965
|
+
async function closeMcpTransportSession(sid, session, reason) {
|
|
966
|
+
if (!sid) return;
|
|
967
|
+
if (!session) {
|
|
968
|
+
transports.delete(sid);
|
|
969
|
+
return;
|
|
970
|
+
}
|
|
971
|
+
if (session.closing) {
|
|
972
|
+
transports.delete(sid);
|
|
973
|
+
return;
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
session.closing = true;
|
|
977
|
+
transports.delete(sid);
|
|
978
|
+
|
|
979
|
+
try {
|
|
980
|
+
await session.mcp.close();
|
|
981
|
+
} catch (error) {
|
|
982
|
+
hubLog.debug(
|
|
983
|
+
{ sid, reason, err: String(error?.message || error) },
|
|
984
|
+
"hub.mcp_session_close_mcp_failed",
|
|
985
|
+
);
|
|
986
|
+
}
|
|
987
|
+
try {
|
|
988
|
+
await session.transport.close();
|
|
989
|
+
} catch (error) {
|
|
990
|
+
hubLog.debug(
|
|
991
|
+
{ sid, reason, err: String(error?.message || error) },
|
|
992
|
+
"hub.mcp_session_close_transport_failed",
|
|
993
|
+
);
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
|
|
965
997
|
function createMcpForSession() {
|
|
966
998
|
const mcp = new Server(
|
|
967
999
|
{ name: "tfx-hub", version: "1.0.0" },
|
|
@@ -1705,19 +1737,17 @@ export async function startHub({
|
|
|
1705
1737
|
sessionIdGenerator: () => randomUUID(),
|
|
1706
1738
|
onsessioninitialized: (sid) => {
|
|
1707
1739
|
transport._lastActivity = Date.now();
|
|
1708
|
-
transports.set(sid, { transport, mcp });
|
|
1740
|
+
transports.set(sid, { transport, mcp, closing: false });
|
|
1709
1741
|
},
|
|
1710
1742
|
});
|
|
1711
1743
|
transport.onclose = () => {
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
transports.delete(transport.sessionId);
|
|
1720
|
-
}
|
|
1744
|
+
const sid = transport.sessionId;
|
|
1745
|
+
if (sid)
|
|
1746
|
+
void closeMcpTransportSession(
|
|
1747
|
+
sid,
|
|
1748
|
+
transports.get(sid),
|
|
1749
|
+
"transport.onclose",
|
|
1750
|
+
);
|
|
1721
1751
|
};
|
|
1722
1752
|
const mcp = createMcpForSession();
|
|
1723
1753
|
await mcp.connect(transport);
|
|
@@ -1808,13 +1838,7 @@ export async function startHub({
|
|
|
1808
1838
|
for (const [sid, session] of transports) {
|
|
1809
1839
|
if (now - (session.transport._lastActivity || 0) <= SESSION_TTL_MS)
|
|
1810
1840
|
continue;
|
|
1811
|
-
|
|
1812
|
-
session.mcp.close();
|
|
1813
|
-
} catch {}
|
|
1814
|
-
try {
|
|
1815
|
-
session.transport.close();
|
|
1816
|
-
} catch {}
|
|
1817
|
-
transports.delete(sid);
|
|
1841
|
+
void closeMcpTransportSession(sid, session, "session_ttl");
|
|
1818
1842
|
}
|
|
1819
1843
|
}, 60000);
|
|
1820
1844
|
sessionTimer.unref();
|
|
@@ -2058,13 +2082,8 @@ export async function startHub({
|
|
|
2058
2082
|
if (idleTimer) {
|
|
2059
2083
|
clearInterval(idleTimer);
|
|
2060
2084
|
}
|
|
2061
|
-
for (const [, session] of transports) {
|
|
2062
|
-
|
|
2063
|
-
await session.mcp.close();
|
|
2064
|
-
} catch {}
|
|
2065
|
-
try {
|
|
2066
|
-
await session.transport.close();
|
|
2067
|
-
} catch {}
|
|
2085
|
+
for (const [sid, session] of Array.from(transports)) {
|
|
2086
|
+
await closeMcpTransportSession(sid, session, "hub.stop");
|
|
2068
2087
|
}
|
|
2069
2088
|
transports.clear();
|
|
2070
2089
|
await pipe.stop();
|
package/package.json
CHANGED
|
@@ -90,6 +90,27 @@ function hasProtectedAncestor(pid, procMap) {
|
|
|
90
90
|
return false;
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
+
function hasProtectedDescendant(pid, procMap) {
|
|
94
|
+
const children = new Map();
|
|
95
|
+
for (const proc of procMap.values()) {
|
|
96
|
+
if (!Number.isFinite(proc.ppid) || proc.ppid <= 0) continue;
|
|
97
|
+
const list = children.get(proc.ppid) || [];
|
|
98
|
+
list.push(proc);
|
|
99
|
+
children.set(proc.ppid, list);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const seen = new Set();
|
|
103
|
+
const stack = [...(children.get(Number(pid)) || [])];
|
|
104
|
+
while (stack.length > 0) {
|
|
105
|
+
const proc = stack.pop();
|
|
106
|
+
if (!proc || seen.has(proc.pid)) continue;
|
|
107
|
+
seen.add(proc.pid);
|
|
108
|
+
if (PROTECTED_ANCESTOR_NAMES.has(proc.name)) return true;
|
|
109
|
+
stack.push(...(children.get(proc.pid) || []));
|
|
110
|
+
}
|
|
111
|
+
return false;
|
|
112
|
+
}
|
|
113
|
+
|
|
93
114
|
export function shouldKillTrackedPid({
|
|
94
115
|
pid,
|
|
95
116
|
pidFileMtimeMs,
|
|
@@ -110,6 +131,7 @@ export function shouldKillTrackedPid({
|
|
|
110
131
|
}
|
|
111
132
|
|
|
112
133
|
if (hasProtectedAncestor(pid, procMap)) return false;
|
|
134
|
+
if (hasProtectedDescendant(pid, procMap)) return false;
|
|
113
135
|
|
|
114
136
|
return true;
|
|
115
137
|
}
|