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 +1 -1
- package/scripts/mcp-cleanup.ps1 +17 -0
- package/scripts/setup.mjs +43 -0
- package/skills/tfx-remote-setup/SKILL.md +43 -1
package/package.json
CHANGED
|
@@ -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: "호스트가 등록되었습니다. 추가 작업이 있습니까?"
|