triflux 10.9.29 → 10.9.30
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/.claude-plugin/marketplace.json +34 -0
- package/.claude-plugin/plugin.json +22 -0
- package/bin/triflux.mjs +80 -1
- package/config/mcp-registry.json +29 -0
- package/hooks/error-context.mjs +1 -1
- package/hooks/safety-guard.mjs +42 -4
- package/hub/account-broker.mjs +405 -28
- package/hub/bridge.mjs +8 -2
- package/hub/cli-adapter-base.mjs +4 -1
- package/hub/codex-adapter.mjs +3 -1
- package/hub/lib/env-detect.mjs +7 -1
- package/hub/platform.mjs +6 -0
- package/hub/server.mjs +435 -192
- package/hub/team/backend.mjs +5 -1
- package/hub/team/conductor.mjs +82 -4
- package/hub/team/dashboard-open.mjs +41 -10
- package/hub/team/headless.mjs +12 -14
- package/hub/team/launcher-template.mjs +2 -0
- package/hub/team/notify.mjs +21 -2
- package/hub/team/process-cleanup.mjs +1 -1
- package/hub/team/psmux.mjs +432 -63
- package/hub/team/runtime-strategy.mjs +70 -0
- package/hub/team/swarm-cli.mjs +188 -0
- package/hub/team/swarm-hypervisor.mjs +67 -14
- package/hub/team/worktree-lifecycle.mjs +103 -36
- package/hub/workers/codex-app-server-worker.mjs +1019 -0
- package/hub/workers/delegator-mcp.mjs +4 -1
- package/hub/workers/factory.mjs +78 -1
- package/hub/workers/gemini-worker.mjs +3 -0
- package/hub/workers/interface.mjs +17 -1
- package/hub/workers/lib/jsonrpc-stdio.mjs +464 -0
- package/package.json +62 -21
- package/scripts/hub-watchdog.mjs +86 -0
- package/scripts/preinstall.mjs +4 -1
- package/scripts/sync-codex-auth.mjs +71 -0
- package/scripts/sync-hub-mcp-settings.mjs +185 -0
- package/scripts/tfx-route.sh +15 -3
- package/skills/tfx-auto/SKILL.md +45 -20
- package/skills/tfx-panel/SKILL.md +1 -1
- package/skills/tfx-panel/SKILL.md.tmpl +1 -1
- package/skills/tfx-prune/SKILL.md +1 -1
- package/skills/tfx-prune/SKILL.md.tmpl +1 -1
- package/tui/codex-profile.mjs +457 -0
- package/tui/core.mjs +266 -0
- package/tui/doctor.mjs +375 -0
- package/tui/gemini-profile.mjs +299 -0
- package/tui/monitor-data.mjs +152 -0
- package/tui/monitor.mjs +330 -0
- package/tui/setup.mjs +598 -0
- package/CLAUDE.md +0 -212
- package/references/hosts.json +0 -46
- package/skills/tfx-workspace/async-tests/run-tests.sh +0 -203
- package/skills/tfx-workspace/evals/evals.json +0 -79
- package/skills/tfx-workspace/iteration-1/benchmark.json +0 -524
- package/skills/tfx-workspace/iteration-1/codex-gemini-remap/eval_metadata.json +0 -11
- package/skills/tfx-workspace/iteration-1/codex-gemini-remap/old_skill/grading.json +0 -25
- package/skills/tfx-workspace/iteration-1/codex-gemini-remap/old_skill/outputs/analysis.md +0 -154
- package/skills/tfx-workspace/iteration-1/codex-gemini-remap/old_skill/timing.json +0 -5
- package/skills/tfx-workspace/iteration-1/codex-gemini-remap/with_skill/grading.json +0 -25
- package/skills/tfx-workspace/iteration-1/codex-gemini-remap/with_skill/outputs/analysis.md +0 -126
- package/skills/tfx-workspace/iteration-1/codex-gemini-remap/with_skill/timing.json +0 -5
- package/skills/tfx-workspace/iteration-1/doctor-diagnosis/eval_metadata.json +0 -11
- package/skills/tfx-workspace/iteration-1/doctor-diagnosis/old_skill/grading.json +0 -25
- package/skills/tfx-workspace/iteration-1/doctor-diagnosis/old_skill/outputs/analysis.md +0 -119
- package/skills/tfx-workspace/iteration-1/doctor-diagnosis/old_skill/timing.json +0 -5
- package/skills/tfx-workspace/iteration-1/doctor-diagnosis/with_skill/grading.json +0 -25
- package/skills/tfx-workspace/iteration-1/doctor-diagnosis/with_skill/outputs/analysis.md +0 -115
- package/skills/tfx-workspace/iteration-1/doctor-diagnosis/with_skill/timing.json +0 -5
- package/skills/tfx-workspace/iteration-1/hub-start-sequence/eval_metadata.json +0 -10
- package/skills/tfx-workspace/iteration-1/hub-start-sequence/old_skill/grading.json +0 -20
- package/skills/tfx-workspace/iteration-1/hub-start-sequence/old_skill/outputs/analysis.md +0 -86
- package/skills/tfx-workspace/iteration-1/hub-start-sequence/old_skill/timing.json +0 -5
- package/skills/tfx-workspace/iteration-1/hub-start-sequence/with_skill/grading.json +0 -20
- package/skills/tfx-workspace/iteration-1/hub-start-sequence/with_skill/outputs/analysis.md +0 -81
- package/skills/tfx-workspace/iteration-1/hub-start-sequence/with_skill/timing.json +0 -5
- package/skills/tfx-workspace/iteration-1/multi-team-creation/eval_metadata.json +0 -12
- package/skills/tfx-workspace/iteration-1/multi-team-creation/old_skill/grading.json +0 -30
- package/skills/tfx-workspace/iteration-1/multi-team-creation/old_skill/outputs/analysis.md +0 -316
- package/skills/tfx-workspace/iteration-1/multi-team-creation/old_skill/timing.json +0 -5
- package/skills/tfx-workspace/iteration-1/multi-team-creation/with_skill/grading.json +0 -30
- package/skills/tfx-workspace/iteration-1/multi-team-creation/with_skill/outputs/analysis.md +0 -352
- package/skills/tfx-workspace/iteration-1/multi-team-creation/with_skill/timing.json +0 -5
- package/skills/tfx-workspace/iteration-1/review.html +0 -1325
- package/skills/tfx-workspace/iteration-1/routing-implement-shortcut/eval_metadata.json +0 -12
- package/skills/tfx-workspace/iteration-1/routing-implement-shortcut/old_skill/grading.json +0 -30
- package/skills/tfx-workspace/iteration-1/routing-implement-shortcut/old_skill/outputs/analysis.md +0 -97
- package/skills/tfx-workspace/iteration-1/routing-implement-shortcut/old_skill/timing.json +0 -5
- package/skills/tfx-workspace/iteration-1/routing-implement-shortcut/with_skill/grading.json +0 -30
- package/skills/tfx-workspace/iteration-1/routing-implement-shortcut/with_skill/outputs/analysis.md +0 -94
- package/skills/tfx-workspace/iteration-1/routing-implement-shortcut/with_skill/timing.json +0 -5
- package/skills/tfx-workspace/iteration-1/routing-multi-task-triage/eval_metadata.json +0 -12
- package/skills/tfx-workspace/iteration-1/routing-multi-task-triage/old_skill/grading.json +0 -30
- package/skills/tfx-workspace/iteration-1/routing-multi-task-triage/old_skill/outputs/analysis.md +0 -209
- package/skills/tfx-workspace/iteration-1/routing-multi-task-triage/old_skill/timing.json +0 -5
- package/skills/tfx-workspace/iteration-1/routing-multi-task-triage/with_skill/grading.json +0 -30
- package/skills/tfx-workspace/iteration-1/routing-multi-task-triage/with_skill/outputs/analysis.md +0 -193
- package/skills/tfx-workspace/iteration-1/routing-multi-task-triage/with_skill/timing.json +0 -5
- package/skills/tfx-workspace/iteration-2/benchmark.json +0 -144
- package/skills/tfx-workspace/iteration-2/multi-team-creation-refactored/eval_metadata.json +0 -13
- package/skills/tfx-workspace/iteration-2/multi-team-creation-refactored/old_skill/grading.json +0 -35
- package/skills/tfx-workspace/iteration-2/multi-team-creation-refactored/old_skill/outputs/analysis.md +0 -382
- package/skills/tfx-workspace/iteration-2/multi-team-creation-refactored/old_skill/timing.json +0 -5
- package/skills/tfx-workspace/iteration-2/multi-team-creation-refactored/with_skill/grading.json +0 -35
- package/skills/tfx-workspace/iteration-2/multi-team-creation-refactored/with_skill/outputs/analysis.md +0 -333
- package/skills/tfx-workspace/iteration-2/multi-team-creation-refactored/with_skill/timing.json +0 -5
- package/skills/tfx-workspace/iteration-2/review.html +0 -1325
- package/skills/tfx-workspace/skill-snapshot/tfx-auto/SKILL.md +0 -217
- package/skills/tfx-workspace/skill-snapshot/tfx-auto-codex/SKILL.md +0 -77
- package/skills/tfx-workspace/skill-snapshot/tfx-codex/SKILL.md +0 -65
- package/skills/tfx-workspace/skill-snapshot/tfx-doctor/SKILL.md +0 -94
- package/skills/tfx-workspace/skill-snapshot/tfx-gemini/SKILL.md +0 -82
- package/skills/tfx-workspace/skill-snapshot/tfx-hub/SKILL.md +0 -133
- package/skills/tfx-workspace/skill-snapshot/tfx-multi/SKILL.md +0 -426
- package/skills/tfx-workspace/skill-snapshot/tfx-setup/SKILL.md +0 -101
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://anthropic.com/claude-code/marketplace.schema.json",
|
|
3
|
+
"name": "triflux",
|
|
4
|
+
"description": "CLI-first multi-model orchestrator — Codex/Gemini/Claude routing with DAG execution, auto-triage, and cost optimization",
|
|
5
|
+
"owner": {
|
|
6
|
+
"name": "tellang"
|
|
7
|
+
},
|
|
8
|
+
"plugins": [
|
|
9
|
+
{
|
|
10
|
+
"name": "triflux",
|
|
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.9.30",
|
|
13
|
+
"author": {
|
|
14
|
+
"name": "tellang"
|
|
15
|
+
},
|
|
16
|
+
"source": {
|
|
17
|
+
"source": "npm",
|
|
18
|
+
"package": "triflux"
|
|
19
|
+
},
|
|
20
|
+
"category": "productivity",
|
|
21
|
+
"homepage": "https://github.com/tellang/triflux",
|
|
22
|
+
"tags": [
|
|
23
|
+
"multi-model",
|
|
24
|
+
"codex",
|
|
25
|
+
"gemini",
|
|
26
|
+
"cli-routing",
|
|
27
|
+
"orchestration",
|
|
28
|
+
"cost-optimization",
|
|
29
|
+
"dag-execution"
|
|
30
|
+
]
|
|
31
|
+
}
|
|
32
|
+
],
|
|
33
|
+
"version": "10.9.30"
|
|
34
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "triflux",
|
|
3
|
+
"version": "10.9.30",
|
|
4
|
+
"description": "CLI-first multi-model orchestrator for Claude Code — route tasks to Codex, Gemini, and Claude",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "tellang"
|
|
7
|
+
},
|
|
8
|
+
"repository": "https://github.com/tellang/triflux",
|
|
9
|
+
"homepage": "https://github.com/tellang/triflux",
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"keywords": [
|
|
12
|
+
"claude-code",
|
|
13
|
+
"plugin",
|
|
14
|
+
"codex",
|
|
15
|
+
"gemini",
|
|
16
|
+
"cli-routing",
|
|
17
|
+
"orchestration",
|
|
18
|
+
"multi-model"
|
|
19
|
+
],
|
|
20
|
+
"skills": "./skills/",
|
|
21
|
+
"hooks": "./hooks/hooks.json"
|
|
22
|
+
}
|
package/bin/triflux.mjs
CHANGED
|
@@ -308,6 +308,42 @@ const CLI_COMMAND_SCHEMAS = Object.freeze({
|
|
|
308
308
|
},
|
|
309
309
|
],
|
|
310
310
|
},
|
|
311
|
+
swarm: {
|
|
312
|
+
usage: "tfx swarm <prd-path> [--dry-run|--json|--filter <shard>]",
|
|
313
|
+
description: "PRD 기반 멀티모델 x 멀티기기 스웜 실행 (#93)",
|
|
314
|
+
subcommands: {
|
|
315
|
+
plan: "tfx swarm plan <prd-path> [--json] — 실행 없이 계획만 출력",
|
|
316
|
+
list: "tfx swarm list [--json] — 활성 스웜 세션 조회 (synapse status)",
|
|
317
|
+
status: "tfx swarm status [--json] — list alias",
|
|
318
|
+
},
|
|
319
|
+
options: [
|
|
320
|
+
{
|
|
321
|
+
name: "--dry-run",
|
|
322
|
+
type: "boolean",
|
|
323
|
+
description: "PRD 분석만 수행, shard를 실행하지 않음",
|
|
324
|
+
},
|
|
325
|
+
{
|
|
326
|
+
name: "--json",
|
|
327
|
+
type: "boolean",
|
|
328
|
+
description: "구조화된 JSON 출력",
|
|
329
|
+
},
|
|
330
|
+
{
|
|
331
|
+
name: "--filter",
|
|
332
|
+
type: "string",
|
|
333
|
+
description: "특정 shard만 실행 (이름 매칭)",
|
|
334
|
+
},
|
|
335
|
+
{
|
|
336
|
+
name: "--max-restarts",
|
|
337
|
+
type: "number",
|
|
338
|
+
description: "shard별 최대 재시작 횟수 (기본 2)",
|
|
339
|
+
},
|
|
340
|
+
{
|
|
341
|
+
name: "--logs-dir",
|
|
342
|
+
type: "string",
|
|
343
|
+
description: "이벤트 로그 출력 디렉토리 오버라이드",
|
|
344
|
+
},
|
|
345
|
+
],
|
|
346
|
+
},
|
|
311
347
|
why: {
|
|
312
348
|
usage: "tfx why <path> [--json]",
|
|
313
349
|
description: "해당 경로의 마지막 커밋에서 X-Intent 트레일러 추출",
|
|
@@ -525,6 +561,10 @@ function whichInShell(cmd, shell) {
|
|
|
525
561
|
["-c", `source ~/.bashrc 2>/dev/null && command -v "${cmd}" 2>/dev/null`],
|
|
526
562
|
],
|
|
527
563
|
cmd: ["cmd", ["/c", "where", cmd]],
|
|
564
|
+
zsh: [
|
|
565
|
+
"zsh",
|
|
566
|
+
["-c", `source ~/.zshrc 2>/dev/null && command -v "${cmd}" 2>/dev/null`],
|
|
567
|
+
],
|
|
528
568
|
pwsh: [
|
|
529
569
|
"pwsh",
|
|
530
570
|
[
|
|
@@ -852,7 +892,7 @@ function getClaudeRoutingSyncSummary(results) {
|
|
|
852
892
|
|
|
853
893
|
function checkCliCrossShell(cmd, installHint) {
|
|
854
894
|
const shells =
|
|
855
|
-
process.platform === "win32" ? ["bash", "cmd", "pwsh"] : ["bash"];
|
|
895
|
+
process.platform === "win32" ? ["bash", "cmd", "pwsh"] : ["bash", "zsh"];
|
|
856
896
|
let anyFound = false;
|
|
857
897
|
let bashMissing = false;
|
|
858
898
|
const shellResults = [];
|
|
@@ -1186,6 +1226,21 @@ function cmdSetup(options = {}) {
|
|
|
1186
1226
|
}
|
|
1187
1227
|
}
|
|
1188
1228
|
|
|
1229
|
+
// ── tmux 기본 셸 확인 (macOS/Linux) ──
|
|
1230
|
+
if (process.platform !== "win32" && which("tmux")) {
|
|
1231
|
+
try {
|
|
1232
|
+
const shellOut = execSync("tmux show-options -g default-shell 2>/dev/null", {
|
|
1233
|
+
encoding: "utf8",
|
|
1234
|
+
timeout: 3000,
|
|
1235
|
+
}).trim();
|
|
1236
|
+
if (shellOut) {
|
|
1237
|
+
ok(`tmux 기본 셸: ${shellOut.split(/\s+/).pop() || "확인 완료"}`);
|
|
1238
|
+
}
|
|
1239
|
+
} catch {
|
|
1240
|
+
/* tmux 서버 미실행 — 무시 */
|
|
1241
|
+
}
|
|
1242
|
+
}
|
|
1243
|
+
|
|
1189
1244
|
// ── 결과 추적 ──
|
|
1190
1245
|
const summary = [];
|
|
1191
1246
|
|
|
@@ -5356,6 +5411,30 @@ async function main() {
|
|
|
5356
5411
|
await cmdSynapseStatus(cmdArgs.slice(1), { json: JSON_OUTPUT });
|
|
5357
5412
|
return;
|
|
5358
5413
|
}
|
|
5414
|
+
case "swarm": {
|
|
5415
|
+
await checkHubRunning();
|
|
5416
|
+
const { cmdSwarmRun, cmdSwarmPlan, cmdSwarmList } = await import(
|
|
5417
|
+
"../hub/team/swarm-cli.mjs"
|
|
5418
|
+
);
|
|
5419
|
+
const sub = cmdArgs[0] || "";
|
|
5420
|
+
if (sub === "list" || sub === "status") {
|
|
5421
|
+
await cmdSwarmList(cmdArgs.slice(1), { json: JSON_OUTPUT });
|
|
5422
|
+
return;
|
|
5423
|
+
}
|
|
5424
|
+
if (sub === "plan") {
|
|
5425
|
+
await cmdSwarmPlan(cmdArgs.slice(1), { json: JSON_OUTPUT });
|
|
5426
|
+
return;
|
|
5427
|
+
}
|
|
5428
|
+
if (!sub || sub.startsWith("--")) {
|
|
5429
|
+
throw createCliError("PRD 경로가 필요합니다", {
|
|
5430
|
+
exitCode: EXIT_ARG_ERROR,
|
|
5431
|
+
reason: "argError",
|
|
5432
|
+
fix: "tfx swarm <prd-path> [--dry-run|--json|--filter <shard>]",
|
|
5433
|
+
});
|
|
5434
|
+
}
|
|
5435
|
+
await cmdSwarmRun(cmdArgs, { json: JSON_OUTPUT });
|
|
5436
|
+
return;
|
|
5437
|
+
}
|
|
5359
5438
|
case "why": {
|
|
5360
5439
|
const { cmdSynapseWhy } = await import("../hub/team/synapse-cli.mjs");
|
|
5361
5440
|
await cmdSynapseWhy(cmdArgs, { json: JSON_OUTPUT });
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "mcp-registry-schema",
|
|
3
|
+
"version": 1,
|
|
4
|
+
"description": "MCP 서버 중앙 레지스트리 — 진실의 원천",
|
|
5
|
+
"defaults": {
|
|
6
|
+
"transport": "hub-url",
|
|
7
|
+
"hub_base": "http://127.0.0.1:27888"
|
|
8
|
+
},
|
|
9
|
+
"servers": {
|
|
10
|
+
"tfx-hub": {
|
|
11
|
+
"transport": "hub-url",
|
|
12
|
+
"url": "http://127.0.0.1:27888/mcp",
|
|
13
|
+
"safe": true,
|
|
14
|
+
"targets": ["claude", "gemini", "codex"],
|
|
15
|
+
"description": "triflux Hub MCP 서버"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"policies": {
|
|
19
|
+
"stdio_action": "replace-with-hub",
|
|
20
|
+
"unknown_server_action": "warn",
|
|
21
|
+
"watched_paths": [
|
|
22
|
+
"~/.gemini/settings.json",
|
|
23
|
+
"~/.codex/config.toml",
|
|
24
|
+
"~/.claude/settings.json",
|
|
25
|
+
"~/.claude/settings.local.json",
|
|
26
|
+
".mcp.json"
|
|
27
|
+
]
|
|
28
|
+
}
|
|
29
|
+
}
|
package/hooks/error-context.mjs
CHANGED
package/hooks/safety-guard.mjs
CHANGED
|
@@ -11,6 +11,22 @@
|
|
|
11
11
|
import { existsSync, readFileSync } from "node:fs";
|
|
12
12
|
import { join } from "node:path";
|
|
13
13
|
|
|
14
|
+
// ── 로컬 우회 플래그 ──────────────────────────────────────────
|
|
15
|
+
// LOCAL ONLY — Issue #89 대안 API 구현 전까지 psmux kill 시리즈 우회용.
|
|
16
|
+
// 활성 조건 (OR):
|
|
17
|
+
// 1) env: TFX_CLEANUP_BYPASS=1
|
|
18
|
+
// 2) 파일: .claude/cleanup-bypass 존재 (repo root)
|
|
19
|
+
// 파일 방식은 Claude Code Bash 도구가 훅에 env 전달 못하는 경우에도 동작.
|
|
20
|
+
// 정식 해결: hub/team/psmux.mjs 에 listSessions/killSessionByTitle/pruneStale 노출.
|
|
21
|
+
const CLEANUP_BYPASS = (() => {
|
|
22
|
+
if (process.env.TFX_CLEANUP_BYPASS === "1") return true;
|
|
23
|
+
try {
|
|
24
|
+
return existsSync(join(process.cwd(), ".claude", "cleanup-bypass"));
|
|
25
|
+
} catch {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
})();
|
|
29
|
+
|
|
14
30
|
// ── 차단 규칙 ──────────────────────────────────────────────
|
|
15
31
|
const BLOCK_RULES = [
|
|
16
32
|
{
|
|
@@ -44,14 +60,16 @@ const BLOCK_RULES = [
|
|
|
44
60
|
{
|
|
45
61
|
pattern: /\bpsmux\s+kill-session\b/i,
|
|
46
62
|
reason:
|
|
47
|
-
"raw psmux kill-session 차단 — WT ConPTY 프리징 위험.
|
|
63
|
+
"raw psmux kill-session 차단 — WT ConPTY 프리징 위험. 대안: listSessions()/killSessionByTitle()/pruneStale() 또는 node hub/team/psmux.mjs --internal kill-by-title <prefix|/regex/> (또는 TFX_CLEANUP_BYPASS=1/.claude/cleanup-bypass)",
|
|
48
64
|
skipIfGit: true,
|
|
65
|
+
cleanupBypass: true,
|
|
49
66
|
},
|
|
50
67
|
{
|
|
51
68
|
pattern: /\bpsmux\s+kill-server\b/i,
|
|
52
69
|
reason:
|
|
53
|
-
"psmux kill-server 차단 — 모든 세션이 즉시 종료됩니다. node hub/team/psmux.mjs kill-swarm 사용",
|
|
70
|
+
"psmux kill-server 차단 — 모든 세션이 즉시 종료됩니다. node hub/team/psmux.mjs kill-swarm 사용 (또는 TFX_CLEANUP_BYPASS=1)",
|
|
54
71
|
skipIfGit: true,
|
|
72
|
+
cleanupBypass: true,
|
|
55
73
|
},
|
|
56
74
|
];
|
|
57
75
|
|
|
@@ -70,8 +88,11 @@ const WT_DIRECT_BLOCK_MESSAGE =
|
|
|
70
88
|
" wt.createTab({ title, command, profile, cwd }) — 새 탭\n" +
|
|
71
89
|
" wt.splitPane({ direction: 'H'|'V', title, command }) — 패인 분할\n" +
|
|
72
90
|
" wt.applySplitLayout([{ title, command, direction }]) — 다중 배치\n" +
|
|
73
|
-
|
|
91
|
+
"사용법: node -e \"import('./hub/team/wt-manager.mjs').then(m => { const wt = m.createWtManager(); wt.createTab({ title: '제목', command: 'pwsh' }); })\"";
|
|
74
92
|
|
|
93
|
+
const PSMUX_INTERNAL_WRAPPER_PATTERNS = [
|
|
94
|
+
/node(?:\.exe)?\s+.*hub[\\/]+team[\\/]+psmux\.mjs\s+--internal\s+(?:list|kill-by-title|prune-stale)\b/i,
|
|
95
|
+
];
|
|
75
96
|
|
|
76
97
|
// ── SSH+PowerShell bash 문법 차단 ────────────────────────────
|
|
77
98
|
// 원격 기본 셸이 PowerShell인 호스트에 bash redirect/glob을 보내면 오동작
|
|
@@ -261,6 +282,10 @@ function main() {
|
|
|
261
282
|
return hasSegmentInvocation(cmd, [/\bpsmux\s+kill-(session|server)\b/i]);
|
|
262
283
|
}
|
|
263
284
|
|
|
285
|
+
function isAllowedPsmuxWrapperInvocation(cmd) {
|
|
286
|
+
return hasSegmentInvocation(cmd, PSMUX_INTERNAL_WRAPPER_PATTERNS);
|
|
287
|
+
}
|
|
288
|
+
|
|
264
289
|
function isWtDirectInvocation(cmd) {
|
|
265
290
|
return hasSegmentInvocation(cmd, WT_DIRECT_PATTERNS);
|
|
266
291
|
}
|
|
@@ -269,6 +294,10 @@ function main() {
|
|
|
269
294
|
blockCommand(WT_DIRECT_BLOCK_MESSAGE, command);
|
|
270
295
|
}
|
|
271
296
|
|
|
297
|
+
if (isAllowedPsmuxWrapperInvocation(command)) {
|
|
298
|
+
process.exit(0);
|
|
299
|
+
}
|
|
300
|
+
|
|
272
301
|
// 0.1. reflexion 적응형 패널티 — 이전 세션에서 차단된 패턴 사전 경고
|
|
273
302
|
const penalties = loadReflexionPenalties();
|
|
274
303
|
if (penalties.length > 0) {
|
|
@@ -299,7 +328,10 @@ function main() {
|
|
|
299
328
|
|
|
300
329
|
// 0.5. SSH → Windows(PowerShell) 호스트에만 bash 문법 전달 차단
|
|
301
330
|
// macOS/Linux 대상은 bash/zsh이므로 허용. hosts.json OS로 판별.
|
|
302
|
-
if (
|
|
331
|
+
if (
|
|
332
|
+
hasSegmentInvocation(command, [/^\s*ssh\s+/i]) &&
|
|
333
|
+
isSshTargetWindows(command)
|
|
334
|
+
) {
|
|
303
335
|
const segments = command.split(/\s*(?:&&|;|\|\||\|)\s*/);
|
|
304
336
|
for (const seg of segments) {
|
|
305
337
|
const sshMatch = seg.trim().match(/^ssh\s+\S+\s+(.*)/s);
|
|
@@ -317,12 +349,18 @@ function main() {
|
|
|
317
349
|
|
|
318
350
|
// 1. BLOCK 체크 — exit 2로 차단
|
|
319
351
|
for (const rule of BLOCK_RULES) {
|
|
352
|
+
if (rule.cleanupBypass && CLEANUP_BYPASS) continue;
|
|
320
353
|
if (rule.skipIfGit && !isPsmuxInvocation(command)) continue;
|
|
321
354
|
if (rule.pattern.test(command)) {
|
|
322
355
|
blockCommand(`[triflux safety-guard] BLOCKED: ${rule.reason}`, command);
|
|
323
356
|
}
|
|
324
357
|
}
|
|
325
358
|
|
|
359
|
+
// wt 정리 명령 우회 (TFX_CLEANUP_BYPASS=1 한정). new-tab/split-pane만 차단 유지하려면 아래 조건 세분화.
|
|
360
|
+
if (CLEANUP_BYPASS) {
|
|
361
|
+
// bypass 모드에서는 아래 wt 검사를 이미 통과한 상태. 추가 작업 없음.
|
|
362
|
+
}
|
|
363
|
+
|
|
326
364
|
// 2. WARN 체크 — allow + additionalContext
|
|
327
365
|
const warnings = [];
|
|
328
366
|
for (const rule of WARN_RULES) {
|