@triflux/core 10.1.0 → 10.26.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/hooks/agent-route-guard.mjs +14 -10
- package/hooks/cross-review-tracker.mjs +21 -8
- package/hooks/error-context.mjs +20 -8
- package/hooks/hook-adaptive-collector.mjs +18 -16
- package/hooks/hook-manager.mjs +93 -32
- package/hooks/hook-orchestrator.mjs +267 -35
- package/hooks/hook-registry.json +343 -256
- package/hooks/hooks.json +49 -1
- package/hooks/keyword-rules.json +191 -31
- package/hooks/lib/resolve-root.mjs +1 -1
- package/hooks/mcp-config-watcher.mjs +6 -2
- package/hooks/permission-safe-allow.mjs +233 -0
- package/hooks/pipeline-stop.mjs +369 -22
- package/hooks/post-tool-tips.mjs +306 -0
- package/hooks/pre-compact-snapshot.mjs +181 -0
- package/hooks/safety-guard.mjs +262 -34
- package/hooks/session-end-cleanup.mjs +345 -0
- package/hooks/session-start-fast.mjs +214 -0
- package/hooks/subagent-tracker.mjs +267 -0
- package/hooks/subagent-verifier.mjs +9 -4
- package/hub/account-broker.mjs +1036 -66
- package/hub/adaptive-diagnostic.mjs +75 -48
- package/hub/adaptive-inject.mjs +96 -58
- package/hub/adaptive-memory.mjs +156 -42
- package/hub/adaptive.mjs +60 -31
- package/hub/assign-callbacks.mjs +163 -126
- package/hub/bridge.mjs +1051 -290
- package/hub/cli-adapter-base.mjs +321 -97
- package/hub/codex-adapter.mjs +179 -93
- package/hub/codex-compat.mjs +4 -4
- package/hub/codex-preflight.mjs +113 -37
- package/hub/delegator/contracts.mjs +22 -21
- package/hub/delegator/index.mjs +14 -14
- package/hub/delegator/schema/delegator-tools.schema.json +1 -1
- package/hub/delegator/service.mjs +93 -64
- package/hub/delegator/tool-definitions.mjs +35 -35
- package/hub/dynamic-routing-engine.mjs +511 -0
- package/hub/fullcycle.mjs +34 -18
- package/hub/gemini-adapter.mjs +82 -108
- package/hub/hitl.mjs +202 -143
- package/hub/intent.mjs +167 -38
- package/hub/lib/bash-path.mjs +73 -0
- package/hub/lib/cache-guard.mjs +43 -17
- package/hub/lib/env-detect.mjs +145 -0
- package/hub/lib/hosts-compat.mjs +319 -0
- package/hub/lib/mcp-response-cache.mjs +239 -0
- package/hub/lib/memory-store.mjs +285 -111
- package/hub/lib/path-utils.mjs +165 -0
- package/hub/lib/phase-manager.mjs +493 -0
- package/hub/lib/process-utils.mjs +797 -104
- package/hub/lib/prompt-tmp.mjs +33 -0
- package/hub/lib/risk-tier.mjs +53 -0
- package/hub/lib/spawn-trace.mjs +561 -0
- package/hub/lib/ssh-command.mjs +44 -24
- package/hub/lib/ssh-retry.mjs +5 -1
- package/hub/lib/staged-file-detect.mjs +43 -0
- package/hub/lib/state-snapshot.mjs +293 -0
- package/hub/lib/tfx-route-args.mjs +309 -0
- package/hub/lib/timeline-adapter.mjs +190 -0
- package/hub/lib/trace-recorder.mjs +153 -0
- package/hub/lib/uuidv7.mjs +4 -3
- package/hub/memory-doctor.mjs +266 -106
- package/hub/middleware/quota-middleware.mjs +70 -0
- package/hub/middleware/request-logger.mjs +61 -34
- package/hub/paths.mjs +9 -9
- package/hub/pipeline/gates/confidence.mjs +34 -15
- package/hub/pipeline/gates/consensus.mjs +27 -15
- package/hub/pipeline/gates/index.mjs +7 -3
- package/hub/pipeline/gates/selfcheck.mjs +57 -19
- package/hub/pipeline/index.mjs +77 -42
- package/hub/pipeline/state.mjs +10 -10
- package/hub/pipeline/transitions.mjs +40 -23
- package/hub/platform.mjs +65 -48
- package/hub/quality/deslop.mjs +70 -49
- package/hub/reflexion.mjs +87 -13
- package/hub/research.mjs +33 -25
- package/hub/router.mjs +941 -791
- package/hub/routing/complexity.mjs +132 -29
- package/hub/routing/index.mjs +17 -12
- package/hub/routing/q-learning.mjs +78 -30
- package/hub/routing-snapshot.mjs +261 -0
- package/hub/session-fingerprint.mjs +127 -61
- package/hub/state.mjs +86 -44
- package/hub/team/claude-daemon-control.mjs +1130 -0
- package/hub/team/retry-state-machine.mjs +336 -0
- package/hub/token-mode.mjs +72 -71
- package/hub/workers/worker-utils.mjs +23 -17
- package/hud/colors.mjs +27 -9
- package/hud/constants.mjs +190 -27
- package/hud/context-monitor.mjs +133 -44
- package/hud/hud-qos-status.mjs +157 -50
- package/hud/mission-board.mjs +56 -0
- package/hud/providers/claude.mjs +398 -114
- package/hud/providers/codex.mjs +96 -21
- package/hud/providers/gemini.mjs +210 -52
- package/hud/renderers.mjs +440 -127
- package/hud/terminal.mjs +101 -31
- package/hud/utils.mjs +81 -39
- package/mesh/index.mjs +69 -0
- package/mesh/mesh-budget.mjs +137 -0
- package/mesh/mesh-heartbeat.mjs +100 -0
- package/mesh/mesh-protocol.mjs +96 -0
- package/mesh/mesh-queue.mjs +163 -0
- package/mesh/mesh-registry.mjs +78 -0
- package/mesh/mesh-router.mjs +77 -0
- package/package.json +5 -1
- package/scripts/lib/agent-json.mjs +27 -0
- package/scripts/lib/async.mjs +174 -0
- package/scripts/lib/claudemd-scanner.mjs +6 -1
- package/scripts/lib/cli-agy.mjs +62 -0
- package/scripts/lib/cli-claude.mjs +78 -0
- package/scripts/lib/cli-codex.mjs +199 -0
- package/scripts/lib/cli-gemini.mjs +37 -0
- package/scripts/lib/codex-recovery.sh +50 -0
- package/scripts/lib/context.mjs +3 -3
- package/scripts/lib/cross-review-utils.mjs +13 -5
- package/scripts/lib/doctor-env-checks.mjs +121 -0
- package/scripts/lib/dynamic-route-cli.mjs +107 -0
- package/scripts/lib/env-probe.mjs +58 -30
- package/scripts/lib/env.mjs +14 -0
- package/scripts/lib/gemini-profiles.mjs +44 -10
- package/scripts/lib/handoff.mjs +33 -17
- package/scripts/lib/hook-utils.mjs +8 -6
- package/scripts/lib/hub.mjs +48 -0
- package/scripts/lib/keyword-rules.mjs +49 -20
- package/scripts/lib/logger.mjs +24 -24
- package/scripts/lib/mcp-filter.mjs +391 -247
- package/scripts/lib/mcp-gateway-health-check.mjs +159 -0
- package/scripts/lib/mcp-gateway-servers.mjs +70 -0
- package/scripts/lib/mcp-gateway-wrapper-check.mjs +35 -0
- package/scripts/lib/mcp-guard-engine.mjs +1281 -115
- package/scripts/lib/mcp-health.mjs +773 -0
- package/scripts/lib/mcp-manifest.mjs +24 -14
- package/scripts/lib/mcp-server-catalog.mjs +355 -118
- package/scripts/lib/pid.mjs +63 -0
- package/scripts/lib/process-utils.mjs +26 -0
- package/scripts/lib/psmux-info.mjs +117 -12
- package/scripts/lib/quota.mjs +47 -0
- package/scripts/lib/remote-spawn-transfer.mjs +44 -14
- package/scripts/lib/skill-state.mjs +220 -0
- package/scripts/lib/skill-template.mjs +32 -7
- package/scripts/lib/team.mjs +75 -0
- package/scripts/lib/timeout.mjs +66 -0
- package/scripts/lib/tmp.mjs +26 -0
- package/scripts/lib/toml.mjs +113 -0
package/hud/renderers.mjs
CHANGED
|
@@ -5,26 +5,51 @@ import { existsSync, readdirSync } from "node:fs";
|
|
|
5
5
|
import { homedir } from "node:os";
|
|
6
6
|
import { join } from "node:path";
|
|
7
7
|
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
8
|
+
bold,
|
|
9
|
+
CLAUDE_ORANGE,
|
|
10
|
+
CODEX_WHITE,
|
|
11
|
+
claudeOrange,
|
|
12
|
+
codexWhite,
|
|
13
|
+
colorByPercent,
|
|
14
|
+
colorByProvider,
|
|
15
|
+
dim,
|
|
16
|
+
GEMINI_BLUE,
|
|
17
|
+
geminiBlue,
|
|
18
|
+
green,
|
|
19
|
+
red,
|
|
20
|
+
yellow,
|
|
12
21
|
} from "./colors.mjs";
|
|
13
22
|
import {
|
|
14
|
-
|
|
15
|
-
FIVE_HOUR_MS,
|
|
16
|
-
|
|
23
|
+
ACCOUNT_LABEL_WIDTH,
|
|
24
|
+
FIVE_HOUR_MS,
|
|
25
|
+
LEGACY_SV_ACCUMULATOR,
|
|
26
|
+
ONE_DAY_MS,
|
|
27
|
+
PROVIDER_PREFIX_WIDTH,
|
|
28
|
+
SEVEN_DAY_MS,
|
|
29
|
+
SV_ACCUMULATOR_PATH,
|
|
30
|
+
TEAM_STATE_PATH,
|
|
17
31
|
} from "./constants.mjs";
|
|
32
|
+
import { buildContextUsageView } from "./context-monitor.mjs";
|
|
33
|
+
import { deriveGeminiLimits } from "./providers/gemini.mjs";
|
|
34
|
+
import { getTerminalColumns, tierBar, tierDimBar } from "./terminal.mjs";
|
|
18
35
|
import {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
36
|
+
clampPercent,
|
|
37
|
+
fitText,
|
|
38
|
+
formatPercentCell,
|
|
39
|
+
formatPlaceholderPercentCell,
|
|
40
|
+
formatResetRemaining,
|
|
41
|
+
formatResetRemainingDayHour,
|
|
42
|
+
formatSavings,
|
|
43
|
+
formatSvPct,
|
|
44
|
+
formatTimeCell,
|
|
45
|
+
formatTimeCellDH,
|
|
46
|
+
formatTokenCount,
|
|
47
|
+
padAnsiRight,
|
|
48
|
+
readJson,
|
|
49
|
+
readJsonMigrate,
|
|
50
|
+
stripAnsi,
|
|
51
|
+
truncateAnsi,
|
|
24
52
|
} from "./utils.mjs";
|
|
25
|
-
import { tierBar, tierDimBar, getTerminalColumns } from "./terminal.mjs";
|
|
26
|
-
import { deriveGeminiLimits } from "./providers/gemini.mjs";
|
|
27
|
-
import { buildContextUsageView } from "./context-monitor.mjs";
|
|
28
53
|
|
|
29
54
|
// ============================================================================
|
|
30
55
|
// 최근 벤치마크 diff 파일 읽기
|
|
@@ -33,15 +58,26 @@ export function readLatestBenchmarkDiff() {
|
|
|
33
58
|
const diffsDir = join(homedir(), ".omc", "state", "cx-auto-tokens", "diffs");
|
|
34
59
|
if (!existsSync(diffsDir)) return null;
|
|
35
60
|
try {
|
|
36
|
-
const files = readdirSync(diffsDir)
|
|
61
|
+
const files = readdirSync(diffsDir)
|
|
62
|
+
.filter((f) => f.endsWith(".json"))
|
|
63
|
+
.sort()
|
|
64
|
+
.reverse();
|
|
37
65
|
if (files.length === 0) return null;
|
|
38
66
|
return readJson(join(diffsDir, files[0]), null);
|
|
39
|
-
} catch {
|
|
67
|
+
} catch {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
40
70
|
}
|
|
41
71
|
|
|
42
72
|
// 토큰 절약액 누적치 읽기 (tfx-auto token tracker)
|
|
43
73
|
export function readTokenSavings() {
|
|
44
|
-
const savingsPath = join(
|
|
74
|
+
const savingsPath = join(
|
|
75
|
+
homedir(),
|
|
76
|
+
".omc",
|
|
77
|
+
"state",
|
|
78
|
+
"tfx-auto-tokens",
|
|
79
|
+
"savings-total.json",
|
|
80
|
+
);
|
|
45
81
|
const data = readJson(savingsPath, null);
|
|
46
82
|
if (!data || data.totalSaved === 0) return null;
|
|
47
83
|
return data;
|
|
@@ -63,14 +99,15 @@ export function formatTokenSummary(diff) {
|
|
|
63
99
|
const inputStr = formatTokenCount(t.input);
|
|
64
100
|
const outputStr = formatTokenCount(t.output);
|
|
65
101
|
const actualStr = formatSavings(s.actualCost);
|
|
66
|
-
const
|
|
67
|
-
const savedPct =
|
|
68
|
-
? Math.round((s.saved / s.claudeCost) * 100)
|
|
69
|
-
: 0;
|
|
102
|
+
const _claudeStr = formatSavings(s.claudeCost);
|
|
103
|
+
const savedPct =
|
|
104
|
+
s.claudeCost > 0 ? Math.round((s.saved / s.claudeCost) * 100) : 0;
|
|
70
105
|
|
|
71
|
-
return
|
|
106
|
+
return (
|
|
107
|
+
`${dim("tok:")}${inputStr}${dim("in")} ${outputStr}${dim("out")} ` +
|
|
72
108
|
`${dim("cost:")}${actualStr} ` +
|
|
73
|
-
`${dim("sv:")}${green(formatSavings(s.saved))}${dim("(")}${savedPct}%${dim(")")}
|
|
109
|
+
`${dim("sv:")}${green(formatSavings(s.saved))}${dim("(")}${savedPct}%${dim(")")}`
|
|
110
|
+
);
|
|
74
111
|
}
|
|
75
112
|
|
|
76
113
|
// ============================================================================
|
|
@@ -78,10 +115,14 @@ export function formatTokenSummary(diff) {
|
|
|
78
115
|
// ============================================================================
|
|
79
116
|
export function getTeamRow(currentTier) {
|
|
80
117
|
const teamState = readJson(TEAM_STATE_PATH, null);
|
|
81
|
-
if (!teamState
|
|
118
|
+
if (!teamState?.sessionName) return null;
|
|
82
119
|
|
|
83
120
|
// 팀 생존 확인: startedAt 기준 24시간 초과면 stale로 간주
|
|
84
|
-
if (
|
|
121
|
+
if (
|
|
122
|
+
teamState.startedAt &&
|
|
123
|
+
Date.now() - teamState.startedAt > 24 * 60 * 60 * 1000
|
|
124
|
+
)
|
|
125
|
+
return null;
|
|
85
126
|
|
|
86
127
|
const workers = (teamState.members || []).filter((m) => m.role === "worker");
|
|
87
128
|
if (!workers.length) return null;
|
|
@@ -92,26 +133,44 @@ export function getTeamRow(currentTier) {
|
|
|
92
133
|
const total = tasks.length || workers.length;
|
|
93
134
|
|
|
94
135
|
// 경과 시간 (80col 이상에서만 표시)
|
|
95
|
-
const elapsed =
|
|
96
|
-
|
|
97
|
-
|
|
136
|
+
const elapsed =
|
|
137
|
+
teamState.startedAt && (currentTier === "full" || currentTier === "compact")
|
|
138
|
+
? `${Math.round((Date.now() - teamState.startedAt) / 60000)}m`
|
|
139
|
+
: "";
|
|
98
140
|
|
|
99
141
|
// CLI 브랜드: 단일문자 + ANSI 색상 (x=codex, g=gemini, c=claude)
|
|
100
|
-
const cliTag = (cli) =>
|
|
142
|
+
const cliTag = (cli) =>
|
|
143
|
+
cli === "codex"
|
|
144
|
+
? bold(codexWhite("x"))
|
|
145
|
+
: cli === "gemini"
|
|
146
|
+
? bold(geminiBlue("g"))
|
|
147
|
+
: bold(claudeOrange("c"));
|
|
101
148
|
// 멤버 상태: 태그 + 상태기호 (60col 이상)
|
|
102
|
-
const memberIcons =
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
149
|
+
const memberIcons =
|
|
150
|
+
currentTier === "full" ||
|
|
151
|
+
currentTier === "compact" ||
|
|
152
|
+
currentTier === "minimal"
|
|
153
|
+
? workers
|
|
154
|
+
.map((m) => {
|
|
155
|
+
const task = tasks.find((t) => t.owner === m.name);
|
|
156
|
+
const status =
|
|
157
|
+
task?.status === "completed"
|
|
158
|
+
? green("\u2713")
|
|
159
|
+
: task?.status === "in_progress"
|
|
160
|
+
? yellow("\u22EF")
|
|
161
|
+
: task?.status === "failed"
|
|
162
|
+
? red("\u2717")
|
|
163
|
+
: dim("\u25CC");
|
|
164
|
+
return `${cliTag(m.cli)}${status}`;
|
|
165
|
+
})
|
|
166
|
+
.join(" ")
|
|
167
|
+
: "";
|
|
110
168
|
|
|
111
169
|
// 진행 텍스트
|
|
112
|
-
const doneText =
|
|
113
|
-
|
|
114
|
-
|
|
170
|
+
const doneText =
|
|
171
|
+
failed > 0
|
|
172
|
+
? `${completed}/${total} ${red(`${failed}\u2717`)}`
|
|
173
|
+
: `${completed}/${total}`;
|
|
115
174
|
|
|
116
175
|
const leftText = elapsed ? `${doneText} ${dim(elapsed)}` : doneText;
|
|
117
176
|
|
|
@@ -122,13 +181,50 @@ export function getTeamRow(currentTier) {
|
|
|
122
181
|
};
|
|
123
182
|
}
|
|
124
183
|
|
|
184
|
+
// ============================================================================
|
|
185
|
+
// Mission Board 렌더러
|
|
186
|
+
// ============================================================================
|
|
187
|
+
|
|
188
|
+
const STATUS_ICON = {
|
|
189
|
+
active: "*",
|
|
190
|
+
idle: ".",
|
|
191
|
+
done: "+",
|
|
192
|
+
failed: "!",
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Mission Board 상태를 1줄 compact 포맷으로 렌더링한다.
|
|
197
|
+
* 예: "MB: exec:+ ui:* perf:. [2/3 67%]"
|
|
198
|
+
* @param {{ agents: Array<{name: string, status: string, progress: number}>, dagLevel: number, totalProgress: number } | null} state
|
|
199
|
+
* @returns {string}
|
|
200
|
+
*/
|
|
201
|
+
export function renderMissionBoard(state) {
|
|
202
|
+
if (!state) return "";
|
|
203
|
+
|
|
204
|
+
const { agents, totalProgress } = state;
|
|
205
|
+
const done = agents.filter((a) => a.status === "done").length;
|
|
206
|
+
const total = agents.length;
|
|
207
|
+
|
|
208
|
+
const parts = agents.map((a) => {
|
|
209
|
+
const icon = STATUS_ICON[a.status] ?? "?";
|
|
210
|
+
return `${a.name}:${icon}`;
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
return `MB: ${parts.join(" ")} [${done}/${total} ${totalProgress}%]`;
|
|
214
|
+
}
|
|
215
|
+
|
|
125
216
|
// ============================================================================
|
|
126
217
|
// 행 정렬 렌더링
|
|
127
218
|
// ============================================================================
|
|
128
219
|
export function renderAlignedRows(rows) {
|
|
129
220
|
const cols = getTerminalColumns() || 120;
|
|
130
|
-
const rightRows = rows.filter(
|
|
131
|
-
|
|
221
|
+
const rightRows = rows.filter(
|
|
222
|
+
(row) => stripAnsi(String(row.right || "")).trim().length > 0,
|
|
223
|
+
);
|
|
224
|
+
const rawLeftWidth = rightRows.reduce(
|
|
225
|
+
(max, row) => Math.max(max, stripAnsi(row.left).length),
|
|
226
|
+
0,
|
|
227
|
+
);
|
|
132
228
|
return rows.map((row) => {
|
|
133
229
|
const prefix = padAnsiRight(row.prefix, PROVIDER_PREFIX_WIDTH);
|
|
134
230
|
const hasRight = stripAnsi(String(row.right || "")).trim().length > 0;
|
|
@@ -147,9 +243,10 @@ export function renderAlignedRows(rows) {
|
|
|
147
243
|
return truncateAnsi(`${prefix} ${left}`, cols);
|
|
148
244
|
}
|
|
149
245
|
const rightVisible = stripAnsi(row.right).length;
|
|
150
|
-
const right =
|
|
151
|
-
|
|
152
|
-
|
|
246
|
+
const right =
|
|
247
|
+
rightVisible <= availableForRight
|
|
248
|
+
? row.right
|
|
249
|
+
: truncateAnsi(row.right, availableForRight);
|
|
153
250
|
return `${prefix} ${left} ${dim("|")} ${right}`;
|
|
154
251
|
});
|
|
155
252
|
}
|
|
@@ -157,23 +254,43 @@ export function renderAlignedRows(rows) {
|
|
|
157
254
|
// ============================================================================
|
|
158
255
|
// micro tier: 모든 프로바이더를 1줄로 압축
|
|
159
256
|
// ============================================================================
|
|
160
|
-
export function getMicroLine(
|
|
257
|
+
export function getMicroLine(
|
|
258
|
+
contextView,
|
|
259
|
+
claudeUsage,
|
|
260
|
+
codexBuckets,
|
|
261
|
+
geminiSession,
|
|
262
|
+
geminiBucket,
|
|
263
|
+
combinedSvPct,
|
|
264
|
+
geminiMarker = "g",
|
|
265
|
+
) {
|
|
161
266
|
const ctxView = contextView || buildContextUsageView({}, null);
|
|
162
|
-
|
|
163
267
|
// Claude 5h/1w
|
|
164
|
-
const cF =
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
268
|
+
const cF =
|
|
269
|
+
claudeUsage?.fiveHourPercent != null
|
|
270
|
+
? clampPercent(claudeUsage.fiveHourPercent)
|
|
271
|
+
: null;
|
|
272
|
+
const cW =
|
|
273
|
+
claudeUsage?.weeklyPercent != null
|
|
274
|
+
? clampPercent(claudeUsage.weeklyPercent)
|
|
275
|
+
: null;
|
|
276
|
+
const cVal =
|
|
277
|
+
claudeUsage != null
|
|
278
|
+
? `${cF != null ? colorByProvider(cF, `${cF}`, claudeOrange) : dim("--")}${dim("/")}${cW != null ? colorByProvider(cW, `${cW}`, claudeOrange) : dim("--")}`
|
|
279
|
+
: dim("--/--");
|
|
169
280
|
|
|
170
281
|
// Codex 5h/1w
|
|
171
282
|
let xVal = dim("--/--");
|
|
172
283
|
if (codexBuckets) {
|
|
173
284
|
const mb = codexBuckets.codex || codexBuckets[Object.keys(codexBuckets)[0]];
|
|
174
285
|
if (mb) {
|
|
175
|
-
const xF =
|
|
176
|
-
|
|
286
|
+
const xF =
|
|
287
|
+
mb.primary?.used_percent != null
|
|
288
|
+
? clampPercent(mb.primary.used_percent)
|
|
289
|
+
: null;
|
|
290
|
+
const xW =
|
|
291
|
+
mb.secondary?.used_percent != null
|
|
292
|
+
? clampPercent(mb.secondary.used_percent)
|
|
293
|
+
: null;
|
|
177
294
|
xVal = `${xF != null ? colorByProvider(xF, `${xF}`, codexWhite) : dim("--")}${dim("/")}${xW != null ? colorByProvider(xW, `${xW}`, codexWhite) : dim("--")}`;
|
|
178
295
|
}
|
|
179
296
|
}
|
|
@@ -182,7 +299,9 @@ export function getMicroLine(contextView, claudeUsage, codexBuckets, geminiSessi
|
|
|
182
299
|
let gVal;
|
|
183
300
|
if (geminiBucket) {
|
|
184
301
|
const gl = deriveGeminiLimits(geminiBucket);
|
|
185
|
-
const gU = gl
|
|
302
|
+
const gU = gl
|
|
303
|
+
? gl.usedPct
|
|
304
|
+
: clampPercent((1 - (geminiBucket.remainingFraction ?? 1)) * 100);
|
|
186
305
|
gVal = colorByProvider(gU, `${gU}`, geminiBlue);
|
|
187
306
|
} else if ((geminiSession?.total || 0) > 0) {
|
|
188
307
|
gVal = geminiBlue("\u221E");
|
|
@@ -194,9 +313,10 @@ export function getMicroLine(contextView, claudeUsage, codexBuckets, geminiSessi
|
|
|
194
313
|
const sv = formatSvPct(combinedSvPct || 0).trim();
|
|
195
314
|
|
|
196
315
|
const cols = getTerminalColumns() || 120;
|
|
197
|
-
const line =
|
|
316
|
+
const line =
|
|
317
|
+
`${bold(claudeOrange("c"))}${dim(":")}${cVal} ` +
|
|
198
318
|
`${bold(codexWhite("x"))}${dim(":")}${xVal} ` +
|
|
199
|
-
`${bold(geminiBlue(
|
|
319
|
+
`${bold(geminiBlue(geminiMarker))}${dim(":")}${gVal} ` +
|
|
200
320
|
`${dim("sv:")}${sv} ` +
|
|
201
321
|
`${dim("CTX:")}${colorByPercent(ctxView.percent, ctxView.display)}`;
|
|
202
322
|
return truncateAnsi(line, cols);
|
|
@@ -205,10 +325,14 @@ export function getMicroLine(contextView, claudeUsage, codexBuckets, geminiSessi
|
|
|
205
325
|
// ============================================================================
|
|
206
326
|
// Claude 행 렌더러
|
|
207
327
|
// ============================================================================
|
|
208
|
-
export function getClaudeRows(
|
|
328
|
+
export function getClaudeRows(
|
|
329
|
+
currentTier,
|
|
330
|
+
contextView,
|
|
331
|
+
claudeUsage,
|
|
332
|
+
combinedSvPct,
|
|
333
|
+
) {
|
|
209
334
|
const ctxView = contextView || buildContextUsageView({}, null);
|
|
210
335
|
const prefix = `${bold(claudeOrange("c"))}:`;
|
|
211
|
-
|
|
212
336
|
// 절약 퍼센트
|
|
213
337
|
const svStr = formatSvPct(combinedSvPct || 0);
|
|
214
338
|
const svSuffix = `${dim("sv:")}${svStr}`;
|
|
@@ -225,36 +349,67 @@ export function getClaudeRows(currentTier, contextView, claudeUsage, combinedSvP
|
|
|
225
349
|
|
|
226
350
|
const hasData = claudeUsage != null;
|
|
227
351
|
|
|
228
|
-
const fStr =
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
352
|
+
const fStr =
|
|
353
|
+
hasData && fiveHourPercent != null
|
|
354
|
+
? colorByProvider(
|
|
355
|
+
fiveHourPercent,
|
|
356
|
+
formatPercentCell(fiveHourPercent),
|
|
357
|
+
claudeOrange,
|
|
358
|
+
)
|
|
359
|
+
: dim(formatPlaceholderPercentCell());
|
|
360
|
+
const wStr =
|
|
361
|
+
hasData && weeklyPercent != null
|
|
362
|
+
? colorByProvider(
|
|
363
|
+
weeklyPercent,
|
|
364
|
+
formatPercentCell(weeklyPercent),
|
|
365
|
+
claudeOrange,
|
|
366
|
+
)
|
|
367
|
+
: dim(formatPlaceholderPercentCell());
|
|
368
|
+
const fBar =
|
|
369
|
+
hasData && fiveHourPercent != null
|
|
370
|
+
? tierBar(currentTier, fiveHourPercent, CLAUDE_ORANGE)
|
|
371
|
+
: tierDimBar(currentTier);
|
|
372
|
+
const wBar =
|
|
373
|
+
hasData && weeklyPercent != null
|
|
374
|
+
? tierBar(currentTier, weeklyPercent, CLAUDE_ORANGE)
|
|
375
|
+
: tierDimBar(currentTier);
|
|
232
376
|
const fTime = formatTimeCell(fiveHourReset);
|
|
233
377
|
const wTime = formatTimeCellDH(weeklyReset);
|
|
234
378
|
|
|
235
379
|
if (currentTier === "nano" || currentTier === "micro") {
|
|
236
|
-
const fShort =
|
|
237
|
-
|
|
380
|
+
const fShort =
|
|
381
|
+
hasData && fiveHourPercent != null
|
|
382
|
+
? colorByProvider(fiveHourPercent, `${fiveHourPercent}%`, claudeOrange)
|
|
383
|
+
: dim("--");
|
|
384
|
+
const wShort =
|
|
385
|
+
hasData && weeklyPercent != null
|
|
386
|
+
? colorByProvider(weeklyPercent, `${weeklyPercent}%`, claudeOrange)
|
|
387
|
+
: dim("--");
|
|
238
388
|
const quotaSection = `${fShort}${dim("/")}${wShort}`;
|
|
239
389
|
return [{ prefix, left: quotaSection, right: "" }];
|
|
240
390
|
}
|
|
241
391
|
|
|
242
392
|
if (currentTier === "minimal") {
|
|
243
|
-
const
|
|
393
|
+
const staleTag = claudeUsage?.stale ? ` ${dim("[stale]")}` : "";
|
|
394
|
+
const quotaSection = `${dim("5h:")}${fStr} ${dim("1w:")}${wStr}${staleTag}`;
|
|
244
395
|
const right = `${dim("CTX:")}${colorByPercent(ctxView.percent, ctxView.display)}`;
|
|
245
396
|
return [{ prefix, left: quotaSection, right }];
|
|
246
397
|
}
|
|
247
398
|
|
|
248
399
|
if (currentTier === "compact") {
|
|
249
400
|
const quotaSection = `${dim("5h:")}${fStr} ${dim(fTime)} ${dim("1w:")}${wStr} ${dim(wTime)}`;
|
|
250
|
-
const warning = ctxView.warningTag
|
|
401
|
+
const warning = ctxView.warningTag
|
|
402
|
+
? ` ${dim("|")} ${yellow(ctxView.warningTag)}`
|
|
403
|
+
: "";
|
|
251
404
|
const contextSection = `${svSuffix} ${dim("|")} ${dim("CTX:")}${colorByPercent(ctxView.percent, ctxView.display)}${warning}`;
|
|
252
405
|
return [{ prefix, left: quotaSection, right: contextSection }];
|
|
253
406
|
}
|
|
254
407
|
|
|
255
408
|
// full tier (>= 120 cols)
|
|
256
409
|
const quotaSection = `${dim("5h:")}${fBar}${fStr} ${dim(fTime)} ${dim("1w:")}${wBar}${wStr} ${dim(wTime)}`;
|
|
257
|
-
const warning = ctxView.warningTag
|
|
410
|
+
const warning = ctxView.warningTag
|
|
411
|
+
? ` ${dim("|")} ${yellow(ctxView.warningTag)}`
|
|
412
|
+
: "";
|
|
258
413
|
const contextSection = `${svSuffix} ${dim("|")} ${dim("CTX:")}${colorByPercent(ctxView.percent, ctxView.display)}${warning}`;
|
|
259
414
|
return [{ prefix, left: quotaSection, right: contextSection }];
|
|
260
415
|
}
|
|
@@ -262,76 +417,165 @@ export function getClaudeRows(currentTier, contextView, claudeUsage, combinedSvP
|
|
|
262
417
|
// ============================================================================
|
|
263
418
|
// 계정 라벨 + 범용 프로바이더 행 렌더러
|
|
264
419
|
// ============================================================================
|
|
265
|
-
export function getAccountLabel(
|
|
420
|
+
export function getAccountLabel(
|
|
421
|
+
provider,
|
|
422
|
+
accountsConfig,
|
|
423
|
+
accountsState,
|
|
424
|
+
codexEmail,
|
|
425
|
+
) {
|
|
266
426
|
const providerConfig = accountsConfig?.providers?.[provider] || [];
|
|
267
427
|
const providerState = accountsState?.providers?.[provider] || {};
|
|
268
428
|
const lastId = providerState.last_selected_id;
|
|
269
|
-
const picked = providerConfig.find((a) => a.id === lastId) ||
|
|
270
|
-
|| { id: `${provider}-main`, label: provider };
|
|
429
|
+
const picked = providerConfig.find((a) => a.id === lastId) ||
|
|
430
|
+
providerConfig[0] || { id: `${provider}-main`, label: provider };
|
|
271
431
|
let label = picked.label || picked.id;
|
|
272
432
|
if (codexEmail) label = codexEmail;
|
|
273
433
|
if (label.includes("@")) label = label.split("@")[0];
|
|
274
434
|
return label;
|
|
275
435
|
}
|
|
276
436
|
|
|
277
|
-
|
|
278
|
-
|
|
437
|
+
function formatAntigravityQuotaSection(currentTier) {
|
|
438
|
+
if (currentTier === "minimal") {
|
|
439
|
+
return `${dim("q:")}${dim(formatPlaceholderPercentCell())}`;
|
|
440
|
+
}
|
|
441
|
+
if (currentTier === "compact") {
|
|
442
|
+
return `${dim("q:")}${dim(formatPlaceholderPercentCell())} ${dim(formatTimeCell("n/a"))}`;
|
|
443
|
+
}
|
|
444
|
+
return `${dim("q:")}${tierDimBar(currentTier)}${dim(formatPlaceholderPercentCell())} ${dim(formatTimeCell("n/a"))}`;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
export function getProviderRow(
|
|
448
|
+
currentTier,
|
|
449
|
+
provider,
|
|
450
|
+
marker,
|
|
451
|
+
markerColor,
|
|
452
|
+
qosProfile,
|
|
453
|
+
accountsConfig,
|
|
454
|
+
accountsState,
|
|
455
|
+
realQuota,
|
|
456
|
+
codexEmail,
|
|
457
|
+
savingsMultiplier,
|
|
458
|
+
modelLabel,
|
|
459
|
+
) {
|
|
460
|
+
const accountLabel = fitText(
|
|
461
|
+
getAccountLabel(provider, accountsConfig, accountsState, codexEmail),
|
|
462
|
+
ACCOUNT_LABEL_WIDTH,
|
|
463
|
+
);
|
|
279
464
|
|
|
280
465
|
// 절약 퍼센트 섹션
|
|
281
|
-
const svPct =
|
|
466
|
+
const svPct =
|
|
467
|
+
savingsMultiplier != null ? Math.round(savingsMultiplier * 100) : null;
|
|
282
468
|
const svStr = formatSvPct(svPct);
|
|
283
|
-
const
|
|
469
|
+
const _modelLabelStr = modelLabel ? ` ${markerColor(modelLabel)}` : "";
|
|
284
470
|
|
|
285
471
|
// 프로바이더별 색상 프로필
|
|
286
|
-
const
|
|
287
|
-
const
|
|
472
|
+
const isGeminiFamily = provider === "gemini" || provider === "antigravity";
|
|
473
|
+
const provAnsi =
|
|
474
|
+
provider === "codex" ? CODEX_WHITE : isGeminiFamily ? GEMINI_BLUE : GREEN;
|
|
475
|
+
const provFn =
|
|
476
|
+
provider === "codex" ? codexWhite : isGeminiFamily ? geminiBlue : green;
|
|
288
477
|
|
|
289
478
|
let quotaSection;
|
|
290
|
-
|
|
479
|
+
const _extraRightSection = "";
|
|
291
480
|
|
|
292
481
|
if (currentTier === "nano" || currentTier === "micro") {
|
|
293
482
|
const minPrefix = `${bold(markerColor(`${marker}`))}:`;
|
|
483
|
+
if (provider === "antigravity") {
|
|
484
|
+
return { prefix: minPrefix, left: dim("--"), right: "" };
|
|
485
|
+
}
|
|
294
486
|
if (realQuota?.type === "codex") {
|
|
295
|
-
const main =
|
|
487
|
+
const main =
|
|
488
|
+
realQuota.buckets.codex ||
|
|
489
|
+
realQuota.buckets[Object.keys(realQuota.buckets)[0]];
|
|
296
490
|
if (main) {
|
|
297
|
-
const fiveP =
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
491
|
+
const fiveP =
|
|
492
|
+
main.primary?.used_percent != null
|
|
493
|
+
? clampPercent(main.primary.used_percent)
|
|
494
|
+
: null;
|
|
495
|
+
const weekP =
|
|
496
|
+
main.secondary?.used_percent != null
|
|
497
|
+
? clampPercent(main.secondary.used_percent)
|
|
498
|
+
: null;
|
|
499
|
+
const fCellN =
|
|
500
|
+
fiveP != null
|
|
501
|
+
? colorByProvider(fiveP, `${fiveP}%`, provFn)
|
|
502
|
+
: dim("--%");
|
|
503
|
+
const wCellN =
|
|
504
|
+
weekP != null
|
|
505
|
+
? colorByProvider(weekP, `${weekP}%`, provFn)
|
|
506
|
+
: dim("--%");
|
|
507
|
+
return {
|
|
508
|
+
prefix: minPrefix,
|
|
509
|
+
left: `${fCellN}${dim("/")}${wCellN}`,
|
|
510
|
+
right: "",
|
|
511
|
+
};
|
|
302
512
|
}
|
|
303
513
|
}
|
|
304
|
-
if (realQuota?.type === "gemini") {
|
|
514
|
+
if (provider === "gemini" && realQuota?.type === "gemini") {
|
|
305
515
|
const pools = realQuota.pools || {};
|
|
306
516
|
if (pools.pro || pools.flash) {
|
|
307
|
-
const pP = pools.pro
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
517
|
+
const pP = pools.pro
|
|
518
|
+
? clampPercent(
|
|
519
|
+
Math.round((1 - (pools.pro.remainingFraction ?? 1)) * 100),
|
|
520
|
+
)
|
|
521
|
+
: null;
|
|
522
|
+
const pF = pools.flash
|
|
523
|
+
? clampPercent(
|
|
524
|
+
Math.round((1 - (pools.flash.remainingFraction ?? 1)) * 100),
|
|
525
|
+
)
|
|
526
|
+
: null;
|
|
527
|
+
const pStr =
|
|
528
|
+
pP != null ? colorByProvider(pP, `${pP}`, provFn) : dim("--");
|
|
529
|
+
const fStr =
|
|
530
|
+
pF != null ? colorByProvider(pF, `${pF}`, provFn) : dim("--");
|
|
531
|
+
return {
|
|
532
|
+
prefix: minPrefix,
|
|
533
|
+
left: `${pStr}${dim("/")}${fStr}`,
|
|
534
|
+
right: "",
|
|
535
|
+
};
|
|
312
536
|
}
|
|
313
537
|
}
|
|
314
538
|
return { prefix: minPrefix, left: dim("--/--"), right: "" };
|
|
315
539
|
}
|
|
316
540
|
|
|
317
541
|
if (currentTier === "minimal") {
|
|
542
|
+
if (provider === "antigravity") {
|
|
543
|
+
quotaSection = formatAntigravityQuotaSection(currentTier);
|
|
544
|
+
}
|
|
318
545
|
if (realQuota?.type === "codex") {
|
|
319
|
-
const main =
|
|
546
|
+
const main =
|
|
547
|
+
realQuota.buckets.codex ||
|
|
548
|
+
realQuota.buckets[Object.keys(realQuota.buckets)[0]];
|
|
320
549
|
if (main) {
|
|
321
|
-
const fiveP =
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
550
|
+
const fiveP =
|
|
551
|
+
main.primary?.used_percent != null
|
|
552
|
+
? clampPercent(main.primary.used_percent)
|
|
553
|
+
: null;
|
|
554
|
+
const weekP =
|
|
555
|
+
main.secondary?.used_percent != null
|
|
556
|
+
? clampPercent(main.secondary.used_percent)
|
|
557
|
+
: null;
|
|
558
|
+
const fCell =
|
|
559
|
+
fiveP != null
|
|
560
|
+
? colorByProvider(fiveP, formatPercentCell(fiveP), provFn)
|
|
561
|
+
: dim(formatPlaceholderPercentCell());
|
|
562
|
+
const wCell =
|
|
563
|
+
weekP != null
|
|
564
|
+
? colorByProvider(weekP, formatPercentCell(weekP), provFn)
|
|
565
|
+
: dim(formatPlaceholderPercentCell());
|
|
325
566
|
quotaSection = `${dim("5h:")}${fCell} ${dim("1w:")}${wCell}`;
|
|
326
567
|
}
|
|
327
568
|
}
|
|
328
|
-
if (realQuota?.type === "gemini") {
|
|
569
|
+
if (provider === "gemini" && realQuota?.type === "gemini") {
|
|
329
570
|
const pools = realQuota.pools || {};
|
|
330
571
|
if (pools.pro || pools.flash) {
|
|
331
572
|
const slot = (bucket, label) => {
|
|
332
|
-
if (!bucket)
|
|
573
|
+
if (!bucket)
|
|
574
|
+
return `${dim(label + ":")}${dim(formatPlaceholderPercentCell())}`;
|
|
333
575
|
const gl = deriveGeminiLimits(bucket);
|
|
334
|
-
const usedP = gl
|
|
576
|
+
const usedP = gl
|
|
577
|
+
? gl.usedPct
|
|
578
|
+
: clampPercent((1 - (bucket.remainingFraction ?? 1)) * 100);
|
|
335
579
|
return `${dim(label + ":")}${colorByProvider(usedP, formatPercentCell(usedP), provFn)}`;
|
|
336
580
|
};
|
|
337
581
|
quotaSection = `${slot(pools.pro, "Pr")} ${slot(pools.flash, "Fl")}`;
|
|
@@ -343,31 +587,61 @@ export function getProviderRow(currentTier, provider, marker, markerColor, qosPr
|
|
|
343
587
|
quotaSection = `${dim("5h:")}${dim(formatPlaceholderPercentCell())} ${dim("1w:")}${dim(formatPlaceholderPercentCell())}`;
|
|
344
588
|
}
|
|
345
589
|
const prefix = `${bold(markerColor(`${marker}`))}:`;
|
|
346
|
-
return {
|
|
590
|
+
return {
|
|
591
|
+
prefix,
|
|
592
|
+
left: quotaSection,
|
|
593
|
+
right: accountLabel ? markerColor(accountLabel) : "",
|
|
594
|
+
};
|
|
347
595
|
}
|
|
348
596
|
|
|
349
597
|
if (currentTier === "compact") {
|
|
598
|
+
if (provider === "antigravity") {
|
|
599
|
+
quotaSection = formatAntigravityQuotaSection(currentTier);
|
|
600
|
+
}
|
|
350
601
|
if (realQuota?.type === "codex") {
|
|
351
|
-
const main =
|
|
602
|
+
const main =
|
|
603
|
+
realQuota.buckets.codex ||
|
|
604
|
+
realQuota.buckets[Object.keys(realQuota.buckets)[0]];
|
|
352
605
|
if (main) {
|
|
353
|
-
const fiveP =
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
const
|
|
358
|
-
|
|
606
|
+
const fiveP =
|
|
607
|
+
main.primary?.used_percent != null
|
|
608
|
+
? clampPercent(main.primary.used_percent)
|
|
609
|
+
: null;
|
|
610
|
+
const weekP =
|
|
611
|
+
main.secondary?.used_percent != null
|
|
612
|
+
? clampPercent(main.secondary.used_percent)
|
|
613
|
+
: null;
|
|
614
|
+
const fCell =
|
|
615
|
+
fiveP != null
|
|
616
|
+
? colorByProvider(fiveP, formatPercentCell(fiveP), provFn)
|
|
617
|
+
: dim(formatPlaceholderPercentCell());
|
|
618
|
+
const wCell =
|
|
619
|
+
weekP != null
|
|
620
|
+
? colorByProvider(weekP, formatPercentCell(weekP), provFn)
|
|
621
|
+
: dim(formatPlaceholderPercentCell());
|
|
622
|
+
const fiveReset =
|
|
623
|
+
formatResetRemaining(main.primary?.resets_at, FIVE_HOUR_MS) || "n/a";
|
|
624
|
+
const weekReset =
|
|
625
|
+
formatResetRemainingDayHour(
|
|
626
|
+
main.secondary?.resets_at,
|
|
627
|
+
SEVEN_DAY_MS,
|
|
628
|
+
) || "n/a";
|
|
359
629
|
quotaSection = `${dim("5h:")}${fCell} ${dim(formatTimeCell(fiveReset))} ${dim("1w:")}${wCell} ${dim(formatTimeCellDH(weekReset))}`;
|
|
360
630
|
}
|
|
361
631
|
}
|
|
362
|
-
if (realQuota?.type === "gemini") {
|
|
632
|
+
if (provider === "gemini" && realQuota?.type === "gemini") {
|
|
363
633
|
const pools = realQuota.pools || {};
|
|
364
634
|
const hasAnyPool = pools.pro || pools.flash;
|
|
365
635
|
if (hasAnyPool) {
|
|
366
636
|
const slot = (bucket, label) => {
|
|
367
|
-
if (!bucket)
|
|
637
|
+
if (!bucket)
|
|
638
|
+
return `${dim(label + ":")}${dim(formatPlaceholderPercentCell())} ${dim(formatTimeCell("n/a"))}`;
|
|
368
639
|
const gl = deriveGeminiLimits(bucket);
|
|
369
|
-
const usedP = gl
|
|
370
|
-
|
|
640
|
+
const usedP = gl
|
|
641
|
+
? gl.usedPct
|
|
642
|
+
: clampPercent((1 - (bucket.remainingFraction ?? 1)) * 100);
|
|
643
|
+
const rstRemaining =
|
|
644
|
+
formatResetRemaining(bucket.resetTime, ONE_DAY_MS) || "n/a";
|
|
371
645
|
return `${dim(label + ":")}${colorByProvider(usedP, formatPercentCell(usedP), provFn)} ${dim(formatTimeCell(rstRemaining))}`;
|
|
372
646
|
};
|
|
373
647
|
quotaSection = `${slot(pools.pro, "Pr")} ${slot(pools.flash, "Fl")}`;
|
|
@@ -379,30 +653,63 @@ export function getProviderRow(currentTier, provider, marker, markerColor, qosPr
|
|
|
379
653
|
quotaSection = `${dim("5h:")}${dim(formatPlaceholderPercentCell())} ${dim(formatTimeCell("n/a"))} ${dim("1w:")}${dim(formatPlaceholderPercentCell())} ${dim(formatTimeCellDH("--d--h"))}`;
|
|
380
654
|
}
|
|
381
655
|
const prefix = `${bold(markerColor(`${marker}`))}:`;
|
|
382
|
-
const compactRight = [
|
|
656
|
+
const compactRight = [
|
|
657
|
+
svStr ? `${dim("sv:")}${svStr}` : "",
|
|
658
|
+
accountLabel ? markerColor(accountLabel) : "",
|
|
659
|
+
]
|
|
660
|
+
.filter(Boolean)
|
|
661
|
+
.join(" ");
|
|
383
662
|
return { prefix, left: quotaSection, right: compactRight };
|
|
384
663
|
}
|
|
385
664
|
|
|
386
665
|
// full tier
|
|
666
|
+
if (provider === "antigravity") {
|
|
667
|
+
quotaSection = formatAntigravityQuotaSection(currentTier);
|
|
668
|
+
}
|
|
669
|
+
|
|
387
670
|
if (realQuota?.type === "codex") {
|
|
388
|
-
const main =
|
|
671
|
+
const main =
|
|
672
|
+
realQuota.buckets.codex ||
|
|
673
|
+
realQuota.buckets[Object.keys(realQuota.buckets)[0]];
|
|
389
674
|
if (main) {
|
|
390
|
-
const fiveP =
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
const
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
675
|
+
const fiveP =
|
|
676
|
+
main.primary?.used_percent != null
|
|
677
|
+
? clampPercent(main.primary.used_percent)
|
|
678
|
+
: null;
|
|
679
|
+
const weekP =
|
|
680
|
+
main.secondary?.used_percent != null
|
|
681
|
+
? clampPercent(main.secondary.used_percent)
|
|
682
|
+
: null;
|
|
683
|
+
const fiveReset =
|
|
684
|
+
formatResetRemaining(main.primary?.resets_at, FIVE_HOUR_MS) || "n/a";
|
|
685
|
+
const weekReset =
|
|
686
|
+
formatResetRemainingDayHour(main.secondary?.resets_at, SEVEN_DAY_MS) ||
|
|
687
|
+
"n/a";
|
|
688
|
+
const fCell =
|
|
689
|
+
fiveP != null
|
|
690
|
+
? colorByProvider(fiveP, formatPercentCell(fiveP), provFn)
|
|
691
|
+
: dim(formatPlaceholderPercentCell());
|
|
692
|
+
const wCell =
|
|
693
|
+
weekP != null
|
|
694
|
+
? colorByProvider(weekP, formatPercentCell(weekP), provFn)
|
|
695
|
+
: dim(formatPlaceholderPercentCell());
|
|
696
|
+
const fBar =
|
|
697
|
+
fiveP != null
|
|
698
|
+
? tierBar(currentTier, fiveP, provAnsi)
|
|
699
|
+
: tierDimBar(currentTier);
|
|
700
|
+
const wBar =
|
|
701
|
+
weekP != null
|
|
702
|
+
? tierBar(currentTier, weekP, provAnsi)
|
|
703
|
+
: tierDimBar(currentTier);
|
|
704
|
+
quotaSection =
|
|
705
|
+
`${dim("5h:")}${fBar}${fCell} ` +
|
|
399
706
|
`${dim(formatTimeCell(fiveReset))} ` +
|
|
400
707
|
`${dim("1w:")}${wBar}${wCell} ` +
|
|
401
708
|
`${dim(formatTimeCellDH(weekReset))}`;
|
|
402
709
|
}
|
|
403
710
|
}
|
|
404
711
|
|
|
405
|
-
if (realQuota?.type === "gemini") {
|
|
712
|
+
if (provider === "gemini" && realQuota?.type === "gemini") {
|
|
406
713
|
const pools = realQuota.pools || {};
|
|
407
714
|
const hasAnyPool = pools.pro || pools.flash;
|
|
408
715
|
|
|
@@ -412,14 +719,18 @@ export function getProviderRow(currentTier, provider, marker, markerColor, qosPr
|
|
|
412
719
|
return `${dim(label + ":")}${tierDimBar(currentTier)}${dim(formatPlaceholderPercentCell())} ${dim(formatTimeCell("n/a"))}`;
|
|
413
720
|
}
|
|
414
721
|
const gl = deriveGeminiLimits(bucket);
|
|
415
|
-
const usedP = gl
|
|
416
|
-
|
|
722
|
+
const usedP = gl
|
|
723
|
+
? gl.usedPct
|
|
724
|
+
: clampPercent((1 - (bucket.remainingFraction ?? 1)) * 100);
|
|
725
|
+
const rstRemaining =
|
|
726
|
+
formatResetRemaining(bucket.resetTime, ONE_DAY_MS) || "n/a";
|
|
417
727
|
return `${dim(label + ":")}${tierBar(currentTier, usedP, provAnsi)}${colorByProvider(usedP, formatPercentCell(usedP), provFn)} ${dim(formatTimeCell(rstRemaining))}`;
|
|
418
728
|
};
|
|
419
729
|
|
|
420
730
|
quotaSection = `${slot(pools.pro, "Pr")} ${slot(pools.flash, "Fl")}`;
|
|
421
731
|
} else {
|
|
422
|
-
quotaSection =
|
|
732
|
+
quotaSection =
|
|
733
|
+
`${dim("Pr:")}${tierDimBar(currentTier)}${dim(formatPlaceholderPercentCell())} ${dim(formatTimeCell("n/a"))} ` +
|
|
423
734
|
`${dim("Fl:")}${tierDimBar(currentTier)}${dim(formatPlaceholderPercentCell())} ${dim(formatTimeCell("n/a"))}`;
|
|
424
735
|
}
|
|
425
736
|
}
|
|
@@ -433,7 +744,9 @@ export function getProviderRow(currentTier, provider, marker, markerColor, qosPr
|
|
|
433
744
|
const accountSection = `${markerColor(accountLabel)}`;
|
|
434
745
|
const svSection = svStr ? `${dim("sv:")}${svStr}` : "";
|
|
435
746
|
const modelLabelSection = modelLabel ? markerColor(modelLabel) : "";
|
|
436
|
-
const rightParts = [svSection, accountSection, modelLabelSection].filter(
|
|
747
|
+
const rightParts = [svSection, accountSection, modelLabelSection].filter(
|
|
748
|
+
Boolean,
|
|
749
|
+
);
|
|
437
750
|
return {
|
|
438
751
|
prefix,
|
|
439
752
|
left: quotaSection,
|