triflux 4.0.6 → 4.1.1

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
@@ -591,6 +591,56 @@ function getSetupSyncTargets() {
591
591
  dst: join(CLAUDE_DIR, "scripts", "tfx-batch-stats.mjs"),
592
592
  label: "tfx-batch-stats.mjs",
593
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
+ },
594
644
  ];
595
645
  }
596
646
 
@@ -912,21 +962,9 @@ async function cmdDoctor(options = {}) {
912
962
  // ── fix 모드: 파일 동기화 + 캐시 정리 후 진단 ──
913
963
  if (fix) {
914
964
  section("Auto Fix");
915
- syncFile(
916
- join(PKG_ROOT, "scripts", "tfx-route.sh"),
917
- join(CLAUDE_DIR, "scripts", "tfx-route.sh"),
918
- "tfx-route.sh"
919
- );
920
- syncFile(
921
- join(PKG_ROOT, "hud", "hud-qos-status.mjs"),
922
- join(CLAUDE_DIR, "hud", "hud-qos-status.mjs"),
923
- "hud-qos-status.mjs"
924
- );
925
- syncFile(
926
- join(PKG_ROOT, "scripts", "notion-read.mjs"),
927
- join(CLAUDE_DIR, "scripts", "notion-read.mjs"),
928
- "notion-read.mjs"
929
- );
965
+ for (const target of getSetupSyncTargets()) {
966
+ syncFile(target.src, target.dst, target.label);
967
+ }
930
968
  // 스킬 동기화
931
969
  const fSkillsSrc = join(PKG_ROOT, "skills");
932
970
  const fSkillsDst = join(CLAUDE_DIR, "skills");
package/hub/tray.mjs CHANGED
@@ -3,13 +3,31 @@
3
3
  import _SysTrayModule from "systray2";
4
4
  const SysTray = _SysTrayModule.default || _SysTrayModule;
5
5
  import { exec } from "node:child_process";
6
- import { readFileSync } from "node:fs";
6
+ import { existsSync, readFileSync } from "node:fs";
7
7
  import { homedir } from "node:os";
8
8
  import { join, resolve } from "node:path";
9
9
  import { fileURLToPath } from "node:url";
10
10
 
11
- const DASHBOARD_URL = "http://127.0.0.1:27888/dashboard";
12
- const HUB_STATUS_URL = "http://127.0.0.1:27888/status";
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(HUB_STATUS_URL, {
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,18 +156,40 @@ function formatMenuPercent(value) {
138
156
  }
139
157
 
140
158
  function buildTooltip(snapshot) {
141
- return `tfx AIMD:${snapshot.aimd}/10 | C:${formatTooltipPercent(snapshot.claude)} X:${formatTooltipPercent(snapshot.codex)} G:${formatTooltipPercent(snapshot.gemini)}`;
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) {
145
164
  return `C: ${formatMenuPercent(snapshot.claude)} | X: ${formatMenuPercent(snapshot.codex)} | G: ${formatMenuPercent(snapshot.gemini)}`;
146
165
  }
147
166
 
167
+ function findChromePath() {
168
+ const candidates = [
169
+ join(process.env.ProgramFiles || "", "Google", "Chrome", "Application", "chrome.exe"),
170
+ join(process.env["ProgramFiles(x86)"] || "", "Google", "Chrome", "Application", "chrome.exe"),
171
+ join(process.env.LOCALAPPDATA || "", "Google", "Chrome", "Application", "chrome.exe"),
172
+ ];
173
+ for (const p of candidates) {
174
+ try { if (existsSync(p)) return p; } catch {}
175
+ }
176
+ return null;
177
+ }
178
+
148
179
  function openDashboard() {
149
- exec(`start "" "${DASHBOARD_URL}"`, {
150
- shell: process.env.ComSpec || "cmd.exe",
151
- windowsHide: true,
152
- }, () => {});
180
+ const url = getDashboardUrl();
181
+ const shell = process.env.ComSpec || "cmd.exe";
182
+ const chrome = findChromePath();
183
+ if (chrome) {
184
+ // Chrome --app: 주소바/탭 없는 앱 윈도우로 열기
185
+ exec(`start "" "${chrome}" "--app=${url}"`, { shell, windowsHide: true }, (err) => {
186
+ if (err) {
187
+ exec(`start "" "${url}"`, { shell, windowsHide: true }, () => {});
188
+ }
189
+ });
190
+ } else {
191
+ exec(`start "" "${url}"`, { shell, windowsHide: true }, () => {});
192
+ }
153
193
  }
154
194
 
155
195
  const openDashboardItem = {
@@ -162,19 +202,22 @@ const openDashboardItem = {
162
202
  const aimdItem = {
163
203
  title: "AIMD: 3/10",
164
204
  tooltip: "최근 30분 AIMD 동시 워커",
165
- enabled: false,
205
+ enabled: true,
206
+ click: openDashboard,
166
207
  };
167
208
 
168
209
  const quotaItem = {
169
210
  title: "C: --% | X: --% | G: --%",
170
211
  tooltip: "Claude | Codex | Gemini 사용률",
171
- enabled: false,
212
+ enabled: true,
213
+ click: openDashboard,
172
214
  };
173
215
 
174
216
  const hubItem = {
175
217
  title: "Hub 미연결",
176
218
  tooltip: "Hub 연결 상태",
177
- enabled: false,
219
+ enabled: true,
220
+ click: openDashboard,
178
221
  };
179
222
 
180
223
  const refreshItem = {
@@ -198,7 +241,7 @@ const exitItem = {
198
241
  const menu = {
199
242
  icon: TRAY_ICON_BASE64,
200
243
  title: "tfx",
201
- tooltip: "tfx AIMD:3/10 | C:--% X:--% G:--%",
244
+ tooltip: "tfx AIMD:3/10 | C:--% X:--% G:--% H:off",
202
245
  items: [
203
246
  openDashboardItem,
204
247
  SysTray.separator,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "triflux",
3
- "version": "4.0.6",
3
+ "version": "4.1.1",
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": {
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) {