triflux 2.1.0 → 2.2.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.
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env node
2
2
  // tfx-doctor — triflux doctor 바로가기
3
3
  import { dirname } from "path";
4
4
  import { fileURLToPath } from "url";
package/bin/tfx-setup.mjs CHANGED
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env node
2
2
  // tfx-setup — triflux setup 바로가기
3
3
  import { dirname } from "path";
4
4
  import { fileURLToPath } from "url";
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 } from "fs";
4
4
  import { join, dirname } from "path";
@@ -7,7 +7,7 @@ import https from "node:https";
7
7
  import { createHash } from "node:crypto";
8
8
  import { spawn, execSync } from "node:child_process";
9
9
 
10
- const VERSION = "1.8";
10
+ const VERSION = "1.9";
11
11
 
12
12
  // ============================================================================
13
13
  // ANSI 색상 (OMC colors.js 스키마 일치)
@@ -19,7 +19,7 @@ const RED = "\x1b[31m";
19
19
  const GREEN = "\x1b[32m";
20
20
  const YELLOW = "\x1b[33m";
21
21
  const CYAN = "\x1b[36m";
22
- const CLAUDE_ORANGE = "\x1b[38;5;214m";
22
+ const CLAUDE_ORANGE = "\x1b[38;5;173m"; // #D87656 (Claude 테라코타)
23
23
  const CODEX_WHITE = "\x1b[97m"; // bright white (SGR 37은 Windows Terminal에서 연회색 매핑)
24
24
  const GEMINI_BLUE = "\x1b[38;5;39m";
25
25
 
@@ -52,15 +52,43 @@ function colorParallel(current, cap) {
52
52
  return red(`${current}/${cap}`);
53
53
  }
54
54
 
55
- function coloredBar(percent, width = 8, baseColor = null) {
55
+ const GAUGE_WIDTH = 5;
56
+ const GAUGE_BLOCKS = ["░", "▒", "▓", "█"]; // 밝기 0~3
57
+
58
+ function coloredBar(percent, width = GAUGE_WIDTH, baseColor = null) {
56
59
  const safePercent = Math.min(100, Math.max(0, percent));
57
- const filled = Math.round((safePercent / 100) * width);
58
- const empty = width - filled;
60
+ const perBlock = 100 / width;
61
+
62
+ // 상태별 색상
59
63
  let barColor;
60
64
  if (safePercent >= 85) barColor = RED;
61
65
  else if (safePercent >= 70) barColor = YELLOW;
62
66
  else barColor = baseColor || GREEN;
63
- return `${barColor}${"█".repeat(filled)}${DIM}${"░".repeat(empty)}${RESET}`;
67
+
68
+ let bar = "";
69
+ for (let i = 0; i < width; i++) {
70
+ const blockStart = i * perBlock;
71
+ const blockEnd = (i + 1) * perBlock;
72
+
73
+ if (safePercent >= blockEnd) {
74
+ bar += "█"; // 완전 채움
75
+ } else if (safePercent > blockStart) {
76
+ // 프론티어: 구간 내 진행률
77
+ const progress = (safePercent - blockStart) / perBlock;
78
+ if (progress >= 0.75) bar += "▓";
79
+ else if (progress >= 0.33) bar += "▒";
80
+ else bar += "░";
81
+ } else {
82
+ bar += "░"; // 미도달
83
+ }
84
+ }
85
+
86
+ // 채워진 부분 = barColor, 빈 부분 = DIM
87
+ const filledEnd = Math.ceil(safePercent / perBlock);
88
+ const coloredPart = barColor + bar.slice(0, filledEnd) + RESET;
89
+ const dimPart = filledEnd < width ? DIM + bar.slice(filledEnd) + RESET : "";
90
+
91
+ return coloredPart + dimPart;
64
92
  }
65
93
 
66
94
  // 프로바이더별 색상 % (< 70%: 프로바이더 색, ≥ 70%: 경고색)
@@ -122,7 +150,7 @@ const GEMINI_SESSION_STALE_MS = 15 * 1000; // 15초
122
150
  const GEMINI_API_TIMEOUT_MS = 3000; // 3초
123
151
  const ACCOUNT_LABEL_WIDTH = 10;
124
152
  const PROVIDER_PREFIX_WIDTH = 2;
125
- const PERCENT_CELL_WIDTH = 4;
153
+ const PERCENT_CELL_WIDTH = 3;
126
154
  const TIME_CELL_INNER_WIDTH = 6;
127
155
  const CLAUDE_REFRESH_FLAG = "--refresh-claude-usage";
128
156
  const CODEX_REFRESH_FLAG = "--refresh-codex-rate-limits";
@@ -266,7 +294,7 @@ function selectTier(stdin, claudeUsage = null) {
266
294
  if (fiveHourPct >= 80) indicatorRows += 1;
267
295
 
268
296
  // 6) 각 tier에서 줄바꿈 없이 3줄 가용한지 확인
269
- const tierWidths = { full: 75, normal: 60, compact: 40, nano: 34 };
297
+ const tierWidths = { full: 70, normal: 60, compact: 40, nano: 34 };
270
298
  for (const tier of ["full", "normal", "compact", "nano"]) {
271
299
  const lineWidth = tierWidths[tier];
272
300
  const visualRowsPerLine = Math.ceil(lineWidth / Math.max(cols, 1));
@@ -278,14 +306,14 @@ function selectTier(stdin, claudeUsage = null) {
278
306
 
279
307
  // full tier 전용: 게이지 바 접두사 (normal 이하 tier에서는 빈 문자열)
280
308
  function tierBar(percent, baseColor = null) {
281
- return CURRENT_TIER === "full" ? `${coloredBar(percent, 8, baseColor)} ` : "";
309
+ return CURRENT_TIER === "full" ? coloredBar(percent, GAUGE_WIDTH, baseColor) + " " : "";
282
310
  }
283
311
  function tierDimBar() {
284
- return CURRENT_TIER === "full" ? `${dim("░".repeat(8))} ` : "";
312
+ return CURRENT_TIER === "full" ? DIM + "░".repeat(GAUGE_WIDTH) + RESET + " " : "";
285
313
  }
286
314
  // Gemini ∞% 전용: 무한 쿼터이므로 dim 회색 바
287
315
  function tierInfBar() {
288
- return CURRENT_TIER === "full" ? `${DIM}${"█".repeat(8)}${RESET} ` : "";
316
+ return CURRENT_TIER === "full" ? DIM + "█".repeat(GAUGE_WIDTH) + RESET + " " : "";
289
317
  }
290
318
 
291
319
  // ============================================================================
@@ -405,7 +433,7 @@ function normalizeTimeToken(value) {
405
433
  const text = String(value || "n/a");
406
434
  const hourMinute = text.match(/^(\d+)h(\d+)m$/);
407
435
  if (hourMinute) {
408
- return `${Number(hourMinute[1])}h${Number(hourMinute[2])}m`;
436
+ return `${Number(hourMinute[1])}h${String(Number(hourMinute[2])).padStart(2, "0")}m`;
409
437
  }
410
438
  const dayHour = text.match(/^(\d+)d(\d+)h$/);
411
439
  if (dayHour) {
@@ -416,7 +444,7 @@ function normalizeTimeToken(value) {
416
444
 
417
445
  function formatTimeCell(value) {
418
446
  const text = normalizeTimeToken(value);
419
- return `(${text.padStart(TIME_CELL_INNER_WIDTH, " ")})`;
447
+ return `(${text.padStart(TIME_CELL_INNER_WIDTH, "0")})`;
420
448
  }
421
449
 
422
450
  // 주간(d/h) 전용 — 최대 7d00h(5자)이므로 공백 불필요
@@ -748,11 +776,11 @@ function formatResetRemaining(isoOrUnix) {
748
776
  const d = typeof isoOrUnix === "string" ? new Date(isoOrUnix) : new Date(isoOrUnix * 1000);
749
777
  if (isNaN(d.getTime())) return "";
750
778
  const diffMs = d.getTime() - Date.now();
751
- if (diffMs <= 0) return "0h0m";
779
+ if (diffMs <= 0) return "0h00m";
752
780
  const totalMinutes = Math.floor(diffMs / 60000);
753
781
  const totalHours = Math.floor(totalMinutes / 60);
754
782
  const minutes = totalMinutes % 60;
755
- return `${totalHours}h${minutes}m`;
783
+ return `${totalHours}h${String(minutes).padStart(2, "0")}m`;
756
784
  }
757
785
 
758
786
  function isResetPast(isoOrUnix) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "triflux",
3
- "version": "2.1.0",
3
+ "version": "2.2.0",
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": {