triflux 4.0.5 → 4.1.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/bin/triflux.mjs +60 -20
- package/hub/tray.mjs +38 -12
- package/package.json +1 -1
- package/scripts/setup.mjs +25 -0
package/bin/triflux.mjs
CHANGED
|
@@ -218,7 +218,7 @@ function handleFatalError(error, { json = false } = {}) {
|
|
|
218
218
|
function which(cmd) {
|
|
219
219
|
try {
|
|
220
220
|
const result = process.platform === "win32"
|
|
221
|
-
? execFileSync("where", [cmd], { encoding: "utf8", timeout: 5000, stdio: ["pipe", "pipe", "ignore"] })
|
|
221
|
+
? execFileSync("where", [cmd], { encoding: "utf8", timeout: 5000, stdio: ["pipe", "pipe", "ignore"], windowsHide: true })
|
|
222
222
|
: execFileSync("which", [cmd], { encoding: "utf8", timeout: 5000, stdio: ["pipe", "pipe", "ignore"] });
|
|
223
223
|
return result.trim().split(/\r?\n/)[0] || null;
|
|
224
224
|
} catch { return null; }
|
|
@@ -237,6 +237,7 @@ function whichInShell(cmd, shell) {
|
|
|
237
237
|
encoding: "utf8",
|
|
238
238
|
timeout: 8000,
|
|
239
239
|
stdio: ["pipe", "pipe", "ignore"],
|
|
240
|
+
windowsHide: true,
|
|
240
241
|
}).trim();
|
|
241
242
|
return result.split(/\r?\n/)[0] || null;
|
|
242
243
|
} catch { return null; }
|
|
@@ -590,6 +591,56 @@ function getSetupSyncTargets() {
|
|
|
590
591
|
dst: join(CLAUDE_DIR, "scripts", "tfx-batch-stats.mjs"),
|
|
591
592
|
label: "tfx-batch-stats.mjs",
|
|
592
593
|
},
|
|
594
|
+
{
|
|
595
|
+
src: join(PKG_ROOT, "scripts", "lib", "mcp-filter.mjs"),
|
|
596
|
+
dst: join(CLAUDE_DIR, "scripts", "lib", "mcp-filter.mjs"),
|
|
597
|
+
label: "lib/mcp-filter.mjs",
|
|
598
|
+
},
|
|
599
|
+
{
|
|
600
|
+
src: join(PKG_ROOT, "scripts", "lib", "mcp-server-catalog.mjs"),
|
|
601
|
+
dst: join(CLAUDE_DIR, "scripts", "lib", "mcp-server-catalog.mjs"),
|
|
602
|
+
label: "lib/mcp-server-catalog.mjs",
|
|
603
|
+
},
|
|
604
|
+
{
|
|
605
|
+
src: join(PKG_ROOT, "scripts", "lib", "keyword-rules.mjs"),
|
|
606
|
+
dst: join(CLAUDE_DIR, "scripts", "lib", "keyword-rules.mjs"),
|
|
607
|
+
label: "lib/keyword-rules.mjs",
|
|
608
|
+
},
|
|
609
|
+
{
|
|
610
|
+
src: join(PKG_ROOT, "scripts", "tfx-route-worker.mjs"),
|
|
611
|
+
dst: join(CLAUDE_DIR, "scripts", "tfx-route-worker.mjs"),
|
|
612
|
+
label: "tfx-route-worker.mjs",
|
|
613
|
+
},
|
|
614
|
+
{
|
|
615
|
+
src: join(PKG_ROOT, "hub", "workers", "codex-mcp.mjs"),
|
|
616
|
+
dst: join(CLAUDE_DIR, "scripts", "hub", "workers", "codex-mcp.mjs"),
|
|
617
|
+
label: "hub/workers/codex-mcp.mjs",
|
|
618
|
+
},
|
|
619
|
+
{
|
|
620
|
+
src: join(PKG_ROOT, "hub", "workers", "delegator-mcp.mjs"),
|
|
621
|
+
dst: join(CLAUDE_DIR, "scripts", "hub", "workers", "delegator-mcp.mjs"),
|
|
622
|
+
label: "hub/workers/delegator-mcp.mjs",
|
|
623
|
+
},
|
|
624
|
+
{
|
|
625
|
+
src: join(PKG_ROOT, "hub", "workers", "interface.mjs"),
|
|
626
|
+
dst: join(CLAUDE_DIR, "scripts", "hub", "workers", "interface.mjs"),
|
|
627
|
+
label: "hub/workers/interface.mjs",
|
|
628
|
+
},
|
|
629
|
+
{
|
|
630
|
+
src: join(PKG_ROOT, "hub", "workers", "gemini-worker.mjs"),
|
|
631
|
+
dst: join(CLAUDE_DIR, "scripts", "hub", "workers", "gemini-worker.mjs"),
|
|
632
|
+
label: "hub/workers/gemini-worker.mjs",
|
|
633
|
+
},
|
|
634
|
+
{
|
|
635
|
+
src: join(PKG_ROOT, "hub", "workers", "claude-worker.mjs"),
|
|
636
|
+
dst: join(CLAUDE_DIR, "scripts", "hub", "workers", "claude-worker.mjs"),
|
|
637
|
+
label: "hub/workers/claude-worker.mjs",
|
|
638
|
+
},
|
|
639
|
+
{
|
|
640
|
+
src: join(PKG_ROOT, "hub", "workers", "factory.mjs"),
|
|
641
|
+
dst: join(CLAUDE_DIR, "scripts", "hub", "workers", "factory.mjs"),
|
|
642
|
+
label: "hub/workers/factory.mjs",
|
|
643
|
+
},
|
|
593
644
|
];
|
|
594
645
|
}
|
|
595
646
|
|
|
@@ -865,7 +916,7 @@ async function cmdDoctor(options = {}) {
|
|
|
865
916
|
const mcpCheck = join(PKG_ROOT, "scripts", "mcp-check.mjs");
|
|
866
917
|
if (existsSync(mcpCheck)) {
|
|
867
918
|
try {
|
|
868
|
-
execFileSync(process.execPath, [mcpCheck], { timeout: 15000, stdio: "ignore" });
|
|
919
|
+
execFileSync(process.execPath, [mcpCheck], { timeout: 15000, stdio: "ignore", windowsHide: true });
|
|
869
920
|
report.actions.push({ type: "rebuild", name: "mcp-inventory", status: "ok" });
|
|
870
921
|
ok("MCP 인벤토리 재생성됨");
|
|
871
922
|
} catch {
|
|
@@ -876,7 +927,7 @@ async function cmdDoctor(options = {}) {
|
|
|
876
927
|
const hudScript = join(CLAUDE_DIR, "hud", "hud-qos-status.mjs");
|
|
877
928
|
if (existsSync(hudScript)) {
|
|
878
929
|
try {
|
|
879
|
-
execFileSync(process.execPath, [hudScript, "--refresh-claude-usage"], { timeout: 20000, stdio: "ignore" });
|
|
930
|
+
execFileSync(process.execPath, [hudScript, "--refresh-claude-usage"], { timeout: 20000, stdio: "ignore", windowsHide: true });
|
|
880
931
|
report.actions.push({ type: "rebuild", name: "claude-usage-cache", status: "ok" });
|
|
881
932
|
ok("Claude 사용량 캐시 재생성됨");
|
|
882
933
|
} catch {
|
|
@@ -884,7 +935,7 @@ async function cmdDoctor(options = {}) {
|
|
|
884
935
|
warn("Claude 사용량 캐시 재생성 실패 — 다음 API 호출 시 자동 생성");
|
|
885
936
|
}
|
|
886
937
|
try {
|
|
887
|
-
execFileSync(process.execPath, [hudScript, "--refresh-codex-rate-limits"], { timeout: 15000, stdio: "ignore" });
|
|
938
|
+
execFileSync(process.execPath, [hudScript, "--refresh-codex-rate-limits"], { timeout: 15000, stdio: "ignore", windowsHide: true });
|
|
888
939
|
report.actions.push({ type: "rebuild", name: "codex-rate-limits-cache", status: "ok" });
|
|
889
940
|
ok("Codex 레이트 리밋 캐시 재생성됨");
|
|
890
941
|
} catch {
|
|
@@ -892,7 +943,7 @@ async function cmdDoctor(options = {}) {
|
|
|
892
943
|
warn("Codex 레이트 리밋 캐시 재생성 실패");
|
|
893
944
|
}
|
|
894
945
|
try {
|
|
895
|
-
execFileSync(process.execPath, [hudScript, "--refresh-gemini-quota"], { timeout: 15000, stdio: "ignore" });
|
|
946
|
+
execFileSync(process.execPath, [hudScript, "--refresh-gemini-quota"], { timeout: 15000, stdio: "ignore", windowsHide: true });
|
|
896
947
|
report.actions.push({ type: "rebuild", name: "gemini-quota-cache", status: "ok" });
|
|
897
948
|
ok("Gemini 쿼터 캐시 재생성됨");
|
|
898
949
|
} catch {
|
|
@@ -911,21 +962,9 @@ async function cmdDoctor(options = {}) {
|
|
|
911
962
|
// ── fix 모드: 파일 동기화 + 캐시 정리 후 진단 ──
|
|
912
963
|
if (fix) {
|
|
913
964
|
section("Auto Fix");
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
"tfx-route.sh"
|
|
918
|
-
);
|
|
919
|
-
syncFile(
|
|
920
|
-
join(PKG_ROOT, "hud", "hud-qos-status.mjs"),
|
|
921
|
-
join(CLAUDE_DIR, "hud", "hud-qos-status.mjs"),
|
|
922
|
-
"hud-qos-status.mjs"
|
|
923
|
-
);
|
|
924
|
-
syncFile(
|
|
925
|
-
join(PKG_ROOT, "scripts", "notion-read.mjs"),
|
|
926
|
-
join(CLAUDE_DIR, "scripts", "notion-read.mjs"),
|
|
927
|
-
"notion-read.mjs"
|
|
928
|
-
);
|
|
965
|
+
for (const target of getSetupSyncTargets()) {
|
|
966
|
+
syncFile(target.src, target.dst, target.label);
|
|
967
|
+
}
|
|
929
968
|
// 스킬 동기화
|
|
930
969
|
const fSkillsSrc = join(PKG_ROOT, "skills");
|
|
931
970
|
const fSkillsDst = join(CLAUDE_DIR, "skills");
|
|
@@ -1955,6 +1994,7 @@ function stopHubForUpdate() {
|
|
|
1955
1994
|
execFileSync("taskkill", ["/PID", String(info.pid), "/T", "/F"], {
|
|
1956
1995
|
stdio: ["pipe", "pipe", "ignore"],
|
|
1957
1996
|
timeout: 10000,
|
|
1997
|
+
windowsHide: true,
|
|
1958
1998
|
});
|
|
1959
1999
|
} else {
|
|
1960
2000
|
process.kill(info.pid, "SIGTERM");
|
package/hub/tray.mjs
CHANGED
|
@@ -8,8 +8,26 @@ import { homedir } from "node:os";
|
|
|
8
8
|
import { join, resolve } from "node:path";
|
|
9
9
|
import { fileURLToPath } from "node:url";
|
|
10
10
|
|
|
11
|
-
const
|
|
12
|
-
const
|
|
11
|
+
const HUB_PID_FILE = join(homedir(), ".claude", "cache", "tfx-hub", "hub.pid");
|
|
12
|
+
const DEFAULT_HUB_PORT = "27888";
|
|
13
|
+
|
|
14
|
+
function getHubBaseUrl() {
|
|
15
|
+
if (process.env.TFX_HUB_URL) return process.env.TFX_HUB_URL.replace(/\/+$/, "");
|
|
16
|
+
try {
|
|
17
|
+
const info = JSON.parse(readFileSync(HUB_PID_FILE, "utf8"));
|
|
18
|
+
if (info.port) return `http://${info.host || "127.0.0.1"}:${info.port}`;
|
|
19
|
+
} catch {}
|
|
20
|
+
const port = process.env.TFX_HUB_PORT || DEFAULT_HUB_PORT;
|
|
21
|
+
return `http://127.0.0.1:${port}`;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function getDashboardUrl() {
|
|
25
|
+
return `${getHubBaseUrl()}/dashboard`;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function getHubStatusUrl() {
|
|
29
|
+
return `${getHubBaseUrl()}/status`;
|
|
30
|
+
}
|
|
13
31
|
const POLL_INTERVAL_MS = 10_000;
|
|
14
32
|
const HUB_TIMEOUT_MS = 3_000;
|
|
15
33
|
const AIMD_INITIAL = 3;
|
|
@@ -115,7 +133,7 @@ function getClaudePercent() {
|
|
|
115
133
|
|
|
116
134
|
async function getHubStatusLabel() {
|
|
117
135
|
try {
|
|
118
|
-
const response = await fetch(
|
|
136
|
+
const response = await fetch(getHubStatusUrl(), {
|
|
119
137
|
signal: AbortSignal.timeout(HUB_TIMEOUT_MS),
|
|
120
138
|
});
|
|
121
139
|
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
|
@@ -138,7 +156,8 @@ function formatMenuPercent(value) {
|
|
|
138
156
|
}
|
|
139
157
|
|
|
140
158
|
function buildTooltip(snapshot) {
|
|
141
|
-
|
|
159
|
+
const hubTag = snapshot.hubLabel.startsWith("Hub 미") ? "H:off" : "H:on";
|
|
160
|
+
return `tfx AIMD:${snapshot.aimd}/10 | C:${formatTooltipPercent(snapshot.claude)} X:${formatTooltipPercent(snapshot.codex)} G:${formatTooltipPercent(snapshot.gemini)} ${hubTag}`;
|
|
142
161
|
}
|
|
143
162
|
|
|
144
163
|
function buildUsageTitle(snapshot) {
|
|
@@ -146,10 +165,14 @@ function buildUsageTitle(snapshot) {
|
|
|
146
165
|
}
|
|
147
166
|
|
|
148
167
|
function openDashboard() {
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
}, () => {
|
|
168
|
+
const url = getDashboardUrl();
|
|
169
|
+
const shell = process.env.ComSpec || "cmd.exe";
|
|
170
|
+
// msedge --app: 주소바/탭 없는 앱 윈도우로 열기
|
|
171
|
+
exec(`start "" "msedge" "--app=${url}"`, { shell, windowsHide: true }, (err) => {
|
|
172
|
+
if (err) {
|
|
173
|
+
exec(`start "" "${url}"`, { shell, windowsHide: true }, () => {});
|
|
174
|
+
}
|
|
175
|
+
});
|
|
153
176
|
}
|
|
154
177
|
|
|
155
178
|
const openDashboardItem = {
|
|
@@ -162,19 +185,22 @@ const openDashboardItem = {
|
|
|
162
185
|
const aimdItem = {
|
|
163
186
|
title: "AIMD: 3/10",
|
|
164
187
|
tooltip: "최근 30분 AIMD 동시 워커",
|
|
165
|
-
enabled:
|
|
188
|
+
enabled: true,
|
|
189
|
+
click: openDashboard,
|
|
166
190
|
};
|
|
167
191
|
|
|
168
192
|
const quotaItem = {
|
|
169
193
|
title: "C: --% | X: --% | G: --%",
|
|
170
194
|
tooltip: "Claude | Codex | Gemini 사용률",
|
|
171
|
-
enabled:
|
|
195
|
+
enabled: true,
|
|
196
|
+
click: openDashboard,
|
|
172
197
|
};
|
|
173
198
|
|
|
174
199
|
const hubItem = {
|
|
175
200
|
title: "Hub 미연결",
|
|
176
201
|
tooltip: "Hub 연결 상태",
|
|
177
|
-
enabled:
|
|
202
|
+
enabled: true,
|
|
203
|
+
click: openDashboard,
|
|
178
204
|
};
|
|
179
205
|
|
|
180
206
|
const refreshItem = {
|
|
@@ -198,7 +224,7 @@ const exitItem = {
|
|
|
198
224
|
const menu = {
|
|
199
225
|
icon: TRAY_ICON_BASE64,
|
|
200
226
|
title: "tfx",
|
|
201
|
-
tooltip: "tfx AIMD:3/10 | C:--% X:--% G:--%",
|
|
227
|
+
tooltip: "tfx AIMD:3/10 | C:--% X:--% G:--% H:off",
|
|
202
228
|
items: [
|
|
203
229
|
openDashboardItem,
|
|
204
230
|
SysTray.separator,
|
package/package.json
CHANGED
package/scripts/setup.mjs
CHANGED
|
@@ -92,6 +92,31 @@ const SYNC_MAP = [
|
|
|
92
92
|
dst: join(CLAUDE_DIR, "hud", "hud-qos-status.mjs"),
|
|
93
93
|
label: "hud-qos-status.mjs",
|
|
94
94
|
},
|
|
95
|
+
{
|
|
96
|
+
src: join(PLUGIN_ROOT, "scripts", "notion-read.mjs"),
|
|
97
|
+
dst: join(CLAUDE_DIR, "scripts", "notion-read.mjs"),
|
|
98
|
+
label: "notion-read.mjs",
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
src: join(PLUGIN_ROOT, "scripts", "tfx-batch-stats.mjs"),
|
|
102
|
+
dst: join(CLAUDE_DIR, "scripts", "tfx-batch-stats.mjs"),
|
|
103
|
+
label: "tfx-batch-stats.mjs",
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
src: join(PLUGIN_ROOT, "scripts", "lib", "mcp-filter.mjs"),
|
|
107
|
+
dst: join(CLAUDE_DIR, "scripts", "lib", "mcp-filter.mjs"),
|
|
108
|
+
label: "lib/mcp-filter.mjs",
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
src: join(PLUGIN_ROOT, "scripts", "lib", "mcp-server-catalog.mjs"),
|
|
112
|
+
dst: join(CLAUDE_DIR, "scripts", "lib", "mcp-server-catalog.mjs"),
|
|
113
|
+
label: "lib/mcp-server-catalog.mjs",
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
src: join(PLUGIN_ROOT, "scripts", "lib", "keyword-rules.mjs"),
|
|
117
|
+
dst: join(CLAUDE_DIR, "scripts", "lib", "keyword-rules.mjs"),
|
|
118
|
+
label: "lib/keyword-rules.mjs",
|
|
119
|
+
},
|
|
95
120
|
];
|
|
96
121
|
|
|
97
122
|
function getVersion(filePath) {
|