triflux 8.2.1 → 8.2.2

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/bin/triflux.mjs CHANGED
@@ -1382,7 +1382,7 @@ async function cmdDoctor(options = {}) {
1382
1382
  if (process.platform === "win32") {
1383
1383
  try {
1384
1384
  const { cleanupOrphanNodeProcesses } = await import("../hub/lib/process-utils.mjs");
1385
- if (autoFix) {
1385
+ if (fix) {
1386
1386
  const { killed, remaining } = cleanupOrphanNodeProcesses();
1387
1387
  if (killed > 0) {
1388
1388
  warn(`고아 node.exe ${killed}개 정리 완료 (남은 프로세스: ${remaining})`);
@@ -2,10 +2,14 @@
2
2
  // 프로세스 관련 공유 유틸리티
3
3
 
4
4
  import { execSync } from "node:child_process";
5
- import { existsSync, readFileSync } from "node:fs";
6
- import { homedir } from "node:os";
5
+ import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
6
+ import { homedir, tmpdir } from "node:os";
7
7
  import { join } from "node:path";
8
8
 
9
+ const CLEANUP_SCRIPT_DIR = join(tmpdir(), "tfx-process-utils");
10
+ const CLEANUP_SCRIPT_PATH = join(CLEANUP_SCRIPT_DIR, "cleanup-orphans.ps1");
11
+ const TREE_SCRIPT_PATH = join(CLEANUP_SCRIPT_DIR, "get-ancestor-tree.ps1");
12
+
9
13
  /**
10
14
  * 주어진 PID의 프로세스가 살아있는지 확인한다.
11
15
  * EPERM: 프로세스는 존재하지만 signal 권한 없음 → alive
@@ -24,6 +28,37 @@ export function isPidAlive(pid) {
24
28
  }
25
29
  }
26
30
 
31
+ /**
32
+ * PowerShell 헬퍼 스크립트를 임시 디렉토리에 생성한다.
33
+ * bash의 $_ 이스케이핑 문제를 피하기 위해 -File로 실행.
34
+ */
35
+ function ensureHelperScripts() {
36
+ mkdirSync(CLEANUP_SCRIPT_DIR, { recursive: true });
37
+
38
+ if (!existsSync(TREE_SCRIPT_PATH)) {
39
+ writeFileSync(TREE_SCRIPT_PATH, `
40
+ param([int]$StartPid)
41
+ $p = $StartPid
42
+ for ($i = 0; $i -lt 10; $i++) {
43
+ if ($p -le 0) { break }
44
+ Write-Output $p
45
+ $parent = (Get-CimInstance Win32_Process -Filter "ProcessId=$p" -ErrorAction SilentlyContinue).ParentProcessId
46
+ if ($null -eq $parent -or $parent -le 0) { break }
47
+ $p = $parent
48
+ }
49
+ `, "utf8");
50
+ }
51
+
52
+ if (!existsSync(CLEANUP_SCRIPT_PATH)) {
53
+ writeFileSync(CLEANUP_SCRIPT_PATH, `
54
+ $ErrorActionPreference = 'SilentlyContinue'
55
+ Get-CimInstance Win32_Process -Filter "Name='node.exe'" | ForEach-Object {
56
+ Write-Output "$($_.ProcessId),$($_.ParentProcessId)"
57
+ }
58
+ `, "utf8");
59
+ }
60
+ }
61
+
27
62
  /**
28
63
  * 부모 프로세스가 죽은 고아 node.exe 프로세스를 정리한다.
29
64
  * Windows 전용 — Agent 서브프로세스가 MCP 서버를 남기는 문제 대응.
@@ -34,6 +69,8 @@ export function isPidAlive(pid) {
34
69
  export function cleanupOrphanNodeProcesses() {
35
70
  if (process.platform !== "win32") return { killed: 0, remaining: 0 };
36
71
 
72
+ ensureHelperScripts();
73
+
37
74
  const myPid = process.pid;
38
75
 
39
76
  // Hub PID 보호
@@ -54,7 +91,7 @@ export function cleanupOrphanNodeProcesses() {
54
91
  try {
55
92
  // 현재 프로세스의 조상 트리를 보호 목록에 추가
56
93
  const treeOutput = execSync(
57
- `powershell -NoProfile -Command "$p=${myPid}; for($i=0;$i -lt 10;$i++){if($p -le 0){break}; Write-Output $p; $p=(Get-CimInstance Win32_Process -Filter \\"ProcessId=$p\\").ParentProcessId}"`,
94
+ `powershell -NoProfile -ExecutionPolicy Bypass -File "${TREE_SCRIPT_PATH}" -StartPid ${myPid}`,
58
95
  { encoding: "utf8", timeout: 8000, stdio: ["pipe", "pipe", "pipe"] },
59
96
  );
60
97
  for (const line of treeOutput.split(/\r?\n/)) {
@@ -65,14 +102,14 @@ export function cleanupOrphanNodeProcesses() {
65
102
 
66
103
  let killed = 0;
67
104
  try {
68
- // 부모가 죽은 고아 node.exe 찾기
105
+ // 부모가 죽은 고아 node.exe 찾기 — PS 스크립트로 실행 (bash $_ 이스케이핑 회피)
69
106
  const output = execSync(
70
- `powershell -NoProfile -Command "Get-CimInstance Win32_Process -Filter \\"Name='node.exe'\\" | Select-Object ProcessId,ParentProcessId | ForEach-Object { Write-Output \\"\\"$($_.ProcessId),$($_.ParentProcessId)\\" }"`,
107
+ `powershell -NoProfile -ExecutionPolicy Bypass -File "${CLEANUP_SCRIPT_PATH}"`,
71
108
  { encoding: "utf8", timeout: 15000, stdio: ["pipe", "pipe", "pipe"] },
72
109
  );
73
110
 
74
111
  for (const line of output.split(/\r?\n/)) {
75
- const trimmed = line.trim().replace(/^"|"$/g, "");
112
+ const trimmed = line.trim();
76
113
  if (!trimmed) continue;
77
114
  const [pidStr, ppidStr] = trimmed.split(",");
78
115
  const pid = Number.parseInt(pidStr, 10);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "triflux",
3
- "version": "8.2.1",
3
+ "version": "8.2.2",
4
4
  "description": "CLI-first multi-model orchestrator for Claude Code — route tasks to Codex, Gemini, and Claude",
5
5
  "type": "module",
6
6
  "bin": {