triflux 2.5.1 → 3.0.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 +26 -14
- package/hud/hud-qos-status.mjs +25 -11
- package/package.json +1 -1
- package/scripts/cli-route.sh +2 -1194
- package/scripts/mcp-check.mjs +2 -2
- package/scripts/notion-read.mjs +2 -2
- package/scripts/setup.mjs +10 -5
- package/scripts/tfx-batch-stats.mjs +96 -0
- package/scripts/tfx-route-post.mjs +366 -0
- package/scripts/tfx-route.sh +448 -0
- package/skills/tfx-auto/SKILL.md +31 -31
- package/skills/tfx-codex/SKILL.md +1 -1
- package/skills/tfx-doctor/SKILL.md +2 -2
- package/skills/tfx-gemini/SKILL.md +1 -1
- package/skills/tfx-setup/SKILL.md +1 -1
package/bin/triflux.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
1
|
+
#!/usr/bin/env node
|
|
2
2
|
// triflux CLI — setup, doctor, version
|
|
3
3
|
import { copyFileSync, existsSync, readFileSync, writeFileSync, mkdirSync, chmodSync, readdirSync, unlinkSync } from "fs";
|
|
4
4
|
import { join, dirname } from "path";
|
|
@@ -145,7 +145,7 @@ function checkCliCrossShell(cmd, installHint) {
|
|
|
145
145
|
return 1;
|
|
146
146
|
}
|
|
147
147
|
if (bashMissing) {
|
|
148
|
-
warn("bash에서 미발견 —
|
|
148
|
+
warn("bash에서 미발견 — tfx-route.sh 실행 불가");
|
|
149
149
|
info('→ ~/.bashrc에 추가: export PATH="$PATH:$APPDATA/npm"');
|
|
150
150
|
return 1;
|
|
151
151
|
}
|
|
@@ -158,9 +158,9 @@ function cmdSetup() {
|
|
|
158
158
|
console.log(`\n${BOLD}triflux setup${RESET}\n`);
|
|
159
159
|
|
|
160
160
|
syncFile(
|
|
161
|
-
join(PKG_ROOT, "scripts", "
|
|
162
|
-
join(CLAUDE_DIR, "scripts", "
|
|
163
|
-
"
|
|
161
|
+
join(PKG_ROOT, "scripts", "tfx-route.sh"),
|
|
162
|
+
join(CLAUDE_DIR, "scripts", "tfx-route.sh"),
|
|
163
|
+
"tfx-route.sh"
|
|
164
164
|
);
|
|
165
165
|
|
|
166
166
|
syncFile(
|
|
@@ -175,6 +175,18 @@ function cmdSetup() {
|
|
|
175
175
|
"notion-read.mjs"
|
|
176
176
|
);
|
|
177
177
|
|
|
178
|
+
syncFile(
|
|
179
|
+
join(PKG_ROOT, "scripts", "tfx-route-post.mjs"),
|
|
180
|
+
join(CLAUDE_DIR, "scripts", "tfx-route-post.mjs"),
|
|
181
|
+
"tfx-route-post.mjs"
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
syncFile(
|
|
185
|
+
join(PKG_ROOT, "scripts", "tfx-batch-stats.mjs"),
|
|
186
|
+
join(CLAUDE_DIR, "scripts", "tfx-batch-stats.mjs"),
|
|
187
|
+
"tfx-batch-stats.mjs"
|
|
188
|
+
);
|
|
189
|
+
|
|
178
190
|
// 스킬 동기화 (~/.claude/skills/{name}/SKILL.md)
|
|
179
191
|
const skillsSrc = join(PKG_ROOT, "skills");
|
|
180
192
|
const skillsDst = join(CLAUDE_DIR, "skills");
|
|
@@ -323,9 +335,9 @@ function cmdDoctor(options = {}) {
|
|
|
323
335
|
if (fix) {
|
|
324
336
|
section("Auto Fix");
|
|
325
337
|
syncFile(
|
|
326
|
-
join(PKG_ROOT, "scripts", "
|
|
327
|
-
join(CLAUDE_DIR, "scripts", "
|
|
328
|
-
"
|
|
338
|
+
join(PKG_ROOT, "scripts", "tfx-route.sh"),
|
|
339
|
+
join(CLAUDE_DIR, "scripts", "tfx-route.sh"),
|
|
340
|
+
"tfx-route.sh"
|
|
329
341
|
);
|
|
330
342
|
syncFile(
|
|
331
343
|
join(PKG_ROOT, "hud", "hud-qos-status.mjs"),
|
|
@@ -375,9 +387,9 @@ function cmdDoctor(options = {}) {
|
|
|
375
387
|
|
|
376
388
|
let issues = 0;
|
|
377
389
|
|
|
378
|
-
// 1.
|
|
379
|
-
section("
|
|
380
|
-
const routeSh = join(CLAUDE_DIR, "scripts", "
|
|
390
|
+
// 1. tfx-route.sh
|
|
391
|
+
section("tfx-route.sh");
|
|
392
|
+
const routeSh = join(CLAUDE_DIR, "scripts", "tfx-route.sh");
|
|
381
393
|
if (existsSync(routeSh)) {
|
|
382
394
|
const ver = getVersion(routeSh);
|
|
383
395
|
ok(`설치됨 ${ver ? `${DIM}v${ver}${RESET}` : ""}`);
|
|
@@ -676,7 +688,7 @@ function cmdUpdate() {
|
|
|
676
688
|
return;
|
|
677
689
|
}
|
|
678
690
|
|
|
679
|
-
// 3. setup 재실행 (
|
|
691
|
+
// 3. setup 재실행 (tfx-route.sh, HUD, 스킬 동기화)
|
|
680
692
|
if (updated) {
|
|
681
693
|
console.log("");
|
|
682
694
|
// 업데이트 후 새 버전 읽기
|
|
@@ -742,10 +754,10 @@ function cmdList() {
|
|
|
742
754
|
}
|
|
743
755
|
|
|
744
756
|
function cmdVersion() {
|
|
745
|
-
const routeVer = getVersion(join(CLAUDE_DIR, "scripts", "
|
|
757
|
+
const routeVer = getVersion(join(CLAUDE_DIR, "scripts", "tfx-route.sh"));
|
|
746
758
|
const hudVer = getVersion(join(CLAUDE_DIR, "hud", "hud-qos-status.mjs"));
|
|
747
759
|
console.log(`\n ${AMBER}${BOLD}⬡ triflux${RESET} ${WHITE_BRIGHT}v${PKG.version}${RESET}`);
|
|
748
|
-
if (routeVer) console.log(` ${GRAY}
|
|
760
|
+
if (routeVer) console.log(` ${GRAY}tfx-route${RESET} v${routeVer}`);
|
|
749
761
|
if (hudVer) console.log(` ${GRAY}hud${RESET} v${hudVer}`);
|
|
750
762
|
console.log("");
|
|
751
763
|
}
|
package/hud/hud-qos-status.mjs
CHANGED
|
@@ -509,7 +509,7 @@ function normalizeTimeToken(value) {
|
|
|
509
509
|
}
|
|
510
510
|
const dayHour = text.match(/^(\d+)d(\d+)h$/);
|
|
511
511
|
if (dayHour) {
|
|
512
|
-
return `${Number(dayHour[1])}d${Number(dayHour[2])}h`;
|
|
512
|
+
return `${Number(dayHour[1])}d${String(Number(dayHour[2])).padStart(2, "0")}h`;
|
|
513
513
|
}
|
|
514
514
|
return text;
|
|
515
515
|
}
|
|
@@ -958,7 +958,9 @@ function getGeminiEmail() {
|
|
|
958
958
|
// ============================================================================
|
|
959
959
|
function getCodexRateLimits() {
|
|
960
960
|
const now = new Date();
|
|
961
|
-
let
|
|
961
|
+
let syntheticBucket = null; // 오늘 token_count에서 합성 (행 활성화 + 토큰 데이터용)
|
|
962
|
+
|
|
963
|
+
// 2일간 스캔: 실제 rate_limits 우선, 합성 버킷은 폴백
|
|
962
964
|
for (let dayOffset = 0; dayOffset <= 1; dayOffset++) {
|
|
963
965
|
const d = new Date(now.getTime() - dayOffset * 86_400_000);
|
|
964
966
|
const sessDir = join(
|
|
@@ -971,10 +973,7 @@ function getCodexRateLimits() {
|
|
|
971
973
|
let files;
|
|
972
974
|
try { files = readdirSync(sessDir).filter((f) => f.endsWith(".jsonl")).sort().reverse(); }
|
|
973
975
|
catch { continue; }
|
|
974
|
-
if (dayOffset === 0 && files.length > 0) todayHasFiles = true;
|
|
975
976
|
|
|
976
|
-
// 당일 모든 세션 파일을 스캔해 limit_id별 가장 최신 버킷을 병합
|
|
977
|
-
// (파일 목록은 이름 역순 정렬 → 최신 세션 우선)
|
|
978
977
|
const mergedBuckets = {};
|
|
979
978
|
for (const file of files) {
|
|
980
979
|
try {
|
|
@@ -985,7 +984,7 @@ function getCodexRateLimits() {
|
|
|
985
984
|
const evt = JSON.parse(line);
|
|
986
985
|
const rl = evt?.payload?.rate_limits;
|
|
987
986
|
if (rl?.limit_id && !mergedBuckets[rl.limit_id]) {
|
|
988
|
-
//
|
|
987
|
+
// 실제 rate_limits: limit_id별 최신 이벤트만 기록
|
|
989
988
|
mergedBuckets[rl.limit_id] = {
|
|
990
989
|
limitId: rl.limit_id, limitName: rl.limit_name,
|
|
991
990
|
primary: rl.primary, secondary: rl.secondary,
|
|
@@ -994,18 +993,33 @@ function getCodexRateLimits() {
|
|
|
994
993
|
contextWindow: evt.payload?.info?.model_context_window,
|
|
995
994
|
timestamp: evt.timestamp,
|
|
996
995
|
};
|
|
996
|
+
} else if (dayOffset === 0 && !rl && evt?.payload?.info?.total_token_usage && !syntheticBucket) {
|
|
997
|
+
// 오늘 token_count: 합성 버킷 (rate_limits가 null일 때 행 활성화용)
|
|
998
|
+
syntheticBucket = {
|
|
999
|
+
limitId: "codex", limitName: "codex-session",
|
|
1000
|
+
primary: null, secondary: null,
|
|
1001
|
+
credits: null,
|
|
1002
|
+
tokens: evt.payload.info.total_token_usage,
|
|
1003
|
+
contextWindow: evt.payload.info.model_context_window,
|
|
1004
|
+
timestamp: evt.timestamp,
|
|
1005
|
+
};
|
|
997
1006
|
}
|
|
998
1007
|
} catch { /* 라인 파싱 실패 무시 */ }
|
|
999
1008
|
if (Object.keys(mergedBuckets).length >= CODEX_MIN_BUCKETS) break;
|
|
1000
1009
|
}
|
|
1001
1010
|
} catch { /* 파일 읽기 실패 무시 */ }
|
|
1002
1011
|
}
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1012
|
+
// 실제 rate_limits 발견 → 오늘 토큰 데이터 병합 후 즉시 반환
|
|
1013
|
+
if (Object.keys(mergedBuckets).length > 0) {
|
|
1014
|
+
if (syntheticBucket) {
|
|
1015
|
+
const main = mergedBuckets.codex || mergedBuckets[Object.keys(mergedBuckets)[0]];
|
|
1016
|
+
if (main && !main.tokens) main.tokens = syntheticBucket.tokens;
|
|
1017
|
+
}
|
|
1018
|
+
return mergedBuckets;
|
|
1019
|
+
}
|
|
1007
1020
|
}
|
|
1008
|
-
|
|
1021
|
+
// 실제 rate_limits 없음 → 합성 버킷이라도 반환 (행 활성화)
|
|
1022
|
+
return syntheticBucket ? { codex: syntheticBucket } : null;
|
|
1009
1023
|
}
|
|
1010
1024
|
|
|
1011
1025
|
// ============================================================================
|