triflux 8.9.2 → 8.10.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "triflux",
3
- "version": "8.9.2",
3
+ "version": "8.10.0",
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": {
@@ -0,0 +1,17 @@
1
+ # mcp-cleanup.ps1 — Claude Code Stop hook: MCP 고아 프로세스 정리
2
+ # Windows에서 Claude Code 세션 종료 시 남는 MCP 서버 고아 프로세스를 정리한다.
3
+ # 원인: Claude Code가 stdio MCP 자식 프로세스 트리를 Windows에서 제대로 kill하지 못함
4
+ # (GitHub Issues #1935, #15211, #28126)
5
+ $ErrorActionPreference = 'SilentlyContinue'
6
+
7
+ # npx MCP servers (brave, notion, context7, exa, tavily, jira, playwright, etc.)
8
+ # + oh-my-codex MCP servers (team/code-intel/memory/trace/state)
9
+ # + omc bridge
10
+ Get-CimInstance Win32_Process -Filter "Name='node.exe' OR Name='cmd.exe'" |
11
+ Where-Object { $_.CommandLine -match 'npx-cli|oh-my-codex[\\/]dist[\\/]mcp|omc.*bridge.*mcp-server' } |
12
+ ForEach-Object { taskkill /F /PID $_.ProcessId 2>$null }
13
+
14
+ # serena (uvx) + python MCP orphans
15
+ Get-CimInstance Win32_Process -Filter "Name='python.exe' OR Name='uvx.exe'" |
16
+ Where-Object { $_.CommandLine -match 'serena|uv[\\/](cache|python)' } |
17
+ ForEach-Object { taskkill /F /PID $_.ProcessId 2>$null }
package/scripts/setup.mjs CHANGED
@@ -144,6 +144,11 @@ const SYNC_MAP = [
144
144
  dst: join(CLAUDE_DIR, "scripts", "hub", "workers", "factory.mjs"),
145
145
  label: "hub/workers/factory.mjs",
146
146
  },
147
+ {
148
+ src: join(PLUGIN_ROOT, "scripts", "mcp-cleanup.ps1"),
149
+ dst: join(CLAUDE_DIR, "scripts", "mcp-cleanup.ps1"),
150
+ label: "mcp-cleanup.ps1",
151
+ },
147
152
  {
148
153
  src: join(PLUGIN_ROOT, "hud", "hud-qos-status.mjs"),
149
154
  dst: join(CLAUDE_DIR, "hud", "hud-qos-status.mjs"),
@@ -580,6 +585,44 @@ function applyHooks(s) {
580
585
  changed = true;
581
586
  }
582
587
 
588
+ // ── Stop 훅: MCP 고아 프로세스 정리 (Windows 전용) ──
589
+ if (process.platform === "win32") {
590
+ if (!Array.isArray(s.hooks.Stop)) s.hooks.Stop = [];
591
+
592
+ const cleanupScriptPath = join(CLAUDE_DIR, "scripts", "mcp-cleanup.ps1").replace(/\\/g, "/");
593
+ const hasCleanupHook = s.hooks.Stop.some((entry) =>
594
+ Array.isArray(entry.hooks) &&
595
+ entry.hooks.some((h) => typeof h.command === "string" && h.command.includes("mcp-cleanup")),
596
+ );
597
+
598
+ if (!hasCleanupHook && existsSync(cleanupScriptPath.replace(/\//g, "\\"))) {
599
+ // 기존 Stop 엔트리가 있으면 거기에 추가, 없으면 새 엔트리 생성
600
+ const existingEntry = s.hooks.Stop.find((entry) => entry.matcher === "*" && Array.isArray(entry.hooks));
601
+ const cleanupHook = {
602
+ type: "command",
603
+ command: `powershell -NoProfile -WindowStyle Hidden -ExecutionPolicy Bypass -File "${cleanupScriptPath}"`,
604
+ timeout: 8,
605
+ };
606
+
607
+ if (existingEntry) {
608
+ existingEntry.hooks.push(cleanupHook);
609
+ } else {
610
+ s.hooks.Stop.push({ matcher: "*", hooks: [cleanupHook] });
611
+ }
612
+ changed = true;
613
+ } else if (hasCleanupHook) {
614
+ for (const entry of s.hooks.Stop) {
615
+ if (!Array.isArray(entry.hooks)) continue;
616
+ for (const h of entry.hooks) {
617
+ if (typeof h.command === "string" && h.command.includes("mcp-cleanup") && !h.command.includes(cleanupScriptPath)) {
618
+ h.command = `powershell -NoProfile -WindowStyle Hidden -ExecutionPolicy Bypass -File "${cleanupScriptPath}"`;
619
+ changed = true;
620
+ }
621
+ }
622
+ }
623
+ }
624
+ }
625
+
583
626
  // ── PreToolUse 훅: headless-guard (auto-route) ──
584
627
  if (!Array.isArray(s.hooks.PreToolUse)) s.hooks.PreToolUse = [];
585
628
 
@@ -337,7 +337,49 @@ options:
337
337
 
338
338
  저장 후 결과 보고.
339
339
 
340
- **2-8. 후속 작업**
340
+ **2-8. MCP 고아 프로세스 정리 훅 배포 (Windows 원격 호스트)**
341
+
342
+ 원격 호스트가 Windows인 경우, MCP 고아 프로세스 정리 훅을 자동 배포한다.
343
+ Claude Code 세션 종료 시 MCP 서버 프로세스가 정리되지 않는 Windows 고유 버그 대응.
344
+ (GitHub Issues #1935, #15211, #28126)
345
+
346
+ ```bash
347
+ # mcp-cleanup.ps1 배포
348
+ scp "$(npm root -g)/triflux/scripts/mcp-cleanup.ps1" {host}:~/.claude/scripts/mcp-cleanup.ps1
349
+ ```
350
+
351
+ 배포 후 원격 호스트의 `~/.claude/settings.json`에 Stop 훅을 등록한다:
352
+
353
+ ```bash
354
+ ssh {host} "node -e \"
355
+ const fs = require('fs');
356
+ const p = require('path').join(require('os').homedir(), '.claude', 'settings.json');
357
+ const s = JSON.parse(fs.readFileSync(p, 'utf8'));
358
+ if (!s.hooks) s.hooks = {};
359
+ if (!Array.isArray(s.hooks.Stop)) s.hooks.Stop = [];
360
+ const has = s.hooks.Stop.some(e => e.hooks?.some(h => h.command?.includes('mcp-cleanup')));
361
+ if (!has) {
362
+ const script = require('path').join(require('os').homedir(), '.claude/scripts/mcp-cleanup.ps1').replace(/\\\\\\\\/g, '/');
363
+ const entry = s.hooks.Stop.find(e => e.matcher === '*' && Array.isArray(e.hooks));
364
+ const hook = { type: 'command', command: 'powershell -NoProfile -WindowStyle Hidden -ExecutionPolicy Bypass -File \\\"' + script + '\\\"', timeout: 8 };
365
+ if (entry) entry.hooks.push(hook); else s.hooks.Stop.push({ matcher: '*', hooks: [hook] });
366
+ fs.writeFileSync(p, JSON.stringify(s, null, 2) + '\\n');
367
+ console.log('mcp-cleanup hook registered');
368
+ } else { console.log('mcp-cleanup hook already exists'); }
369
+ \""
370
+ ```
371
+
372
+ macOS/Linux 원격 호스트에서는 이 단계를 건너뛴다 (PGID 기반 kill이 정상 동작).
373
+
374
+ 프로브 결과에서 OS를 확인하여 자동 판단:
375
+ - Windows → 배포 실행
376
+ - macOS/Linux → 건너뛰기 (표시만)
377
+
378
+ ```
379
+ "{host}는 Windows입니다. MCP 고아 프로세스 정리 훅을 배포합니다."
380
+ ```
381
+
382
+ **2-9. 후속 작업**
341
383
 
342
384
  ```
343
385
  question: "호스트가 등록되었습니다. 추가 작업이 있습니까?"