@triflux/core 10.50.1 → 10.50.2
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/hub/index.mjs +2 -8
- package/hub/lib/cto-env.mjs +0 -23
- package/hub/paths.mjs +0 -6
- package/hub/pipeline/index.mjs +0 -190
- package/hub/pipeline/transitions.mjs +0 -10
- package/hub/reflexion.mjs +1 -84
- package/hud/cli-policy.mjs +1 -5
- package/hud/colors.mjs +0 -13
- package/hud/constants.mjs +4 -135
- package/hud/context-monitor.mjs +3 -64
- package/hud/hud-qos-status.mjs +43 -225
- package/hud/providers/claude.mjs +4 -16
- package/hud/providers/gemini.mjs +7 -698
- package/hud/renderers.mjs +40 -294
- package/hud/terminal.mjs +1 -63
- package/hud/utils.mjs +0 -24
- package/package.json +1 -2
- package/scripts/lib/gemini-profiles.mjs +1 -1
- package/scripts/lib/legacy-mcp-cleanup.mjs +14 -3
- package/scripts/lib/psmux-info.mjs +18 -49
- package/scripts/lib/skill-template.mjs +0 -26
- package/hub/codex-compat.mjs +0 -12
- package/hub/fullcycle.mjs +0 -113
- package/hub/gemini-adapter.mjs +0 -174
- package/hub/intent.mjs +0 -321
- package/hub/lib/mcp-response-cache.mjs +0 -239
- package/hub/lib/path-utils.mjs +0 -165
- package/hub/lib/timeline-adapter.mjs +0 -190
- package/hub/pipeline/gates/confidence.mjs +0 -75
- package/hub/pipeline/gates/consensus.mjs +0 -106
- package/hub/pipeline/gates/index.mjs +0 -9
- package/hub/pipeline/gates/selfcheck.mjs +0 -120
- package/hub/quality/deslop.mjs +0 -274
- package/hub/research.mjs +0 -155
- package/hub/role-control-events.mjs +0 -113
- package/hub/routing/complexity.mjs +0 -269
- package/hub/routing/index.mjs +0 -122
- package/hub/routing/q-learning.mjs +0 -387
- package/hub/token-mode.mjs +0 -228
- package/hud/mission-board.mjs +0 -56
- package/hud/providers/cto.mjs +0 -76
- package/scripts/lib/agent-json.mjs +0 -27
- package/scripts/lib/async.mjs +0 -174
- package/scripts/lib/cli-agy.mjs +0 -85
- package/scripts/lib/cli-codex.mjs +0 -62
- package/scripts/lib/cli-gemini.mjs +0 -37
- package/scripts/lib/env.mjs +0 -14
- package/scripts/lib/hub.mjs +0 -48
- package/scripts/lib/pid.mjs +0 -63
- package/scripts/lib/quota.mjs +0 -47
- package/scripts/lib/skill-state.mjs +0 -220
- package/scripts/lib/team.mjs +0 -75
- package/scripts/lib/timeout.mjs +0 -66
- package/scripts/lib/tmp.mjs +0 -26
- package/scripts/lib/toml.mjs +0 -132
package/hud/renderers.mjs
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
// ============================================================================
|
|
2
2
|
// 라인 렌더러 (tier별 행 생성)
|
|
3
3
|
// ============================================================================
|
|
4
|
-
import {
|
|
5
|
-
import { homedir } from "node:os";
|
|
4
|
+
import { readdirSync, statSync } from "node:fs";
|
|
6
5
|
import { join } from "node:path";
|
|
7
6
|
import {
|
|
8
7
|
bold,
|
|
@@ -13,7 +12,6 @@ import {
|
|
|
13
12
|
colorByPercent,
|
|
14
13
|
colorByProvider,
|
|
15
14
|
dim,
|
|
16
|
-
GEMINI_BLUE,
|
|
17
15
|
geminiBlue,
|
|
18
16
|
green,
|
|
19
17
|
red,
|
|
@@ -22,13 +20,11 @@ import {
|
|
|
22
20
|
import {
|
|
23
21
|
ACCOUNT_LABEL_WIDTH,
|
|
24
22
|
FIVE_HOUR_MS,
|
|
25
|
-
ONE_DAY_MS,
|
|
26
23
|
PROVIDER_PREFIX_WIDTH,
|
|
27
24
|
SEVEN_DAY_MS,
|
|
28
|
-
|
|
25
|
+
TEAM_STATE_DIR,
|
|
29
26
|
} from "./constants.mjs";
|
|
30
27
|
import { buildContextUsageView } from "./context-monitor.mjs";
|
|
31
|
-
import { deriveGeminiLimits } from "./providers/gemini.mjs";
|
|
32
28
|
import { getTerminalColumns, tierBar, tierDimBar } from "./terminal.mjs";
|
|
33
29
|
import {
|
|
34
30
|
clampPercent,
|
|
@@ -37,89 +33,40 @@ import {
|
|
|
37
33
|
formatPlaceholderPercentCell,
|
|
38
34
|
formatResetRemaining,
|
|
39
35
|
formatResetRemainingDayHour,
|
|
40
|
-
formatSavings,
|
|
41
36
|
formatTimeCell,
|
|
42
37
|
formatTimeCellDH,
|
|
43
|
-
formatTokenCount,
|
|
44
38
|
padAnsiRight,
|
|
45
39
|
readJson,
|
|
46
40
|
stripAnsi,
|
|
47
41
|
truncateAnsi,
|
|
48
42
|
} from "./utils.mjs";
|
|
49
43
|
|
|
50
|
-
function formatGeminiLimitValue(limit, provFn) {
|
|
51
|
-
if (limit?.unlimited) return provFn("\u221E");
|
|
52
|
-
const usedP = limit?.usedPct;
|
|
53
|
-
if (usedP == null) return dim(formatPlaceholderPercentCell());
|
|
54
|
-
return colorByProvider(usedP, formatPercentCell(usedP), provFn);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
function getGeminiLimitUsedPercent(bucket, limit) {
|
|
58
|
-
if (limit?.unlimited) return null;
|
|
59
|
-
if (limit?.usedPct != null) return limit.usedPct;
|
|
60
|
-
return clampPercent(Math.round((1 - (bucket?.remainingFraction ?? 1)) * 100));
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
function formatGeminiCompactValue(bucket, limit, provFn) {
|
|
64
|
-
if (limit?.unlimited) return provFn("\u221E");
|
|
65
|
-
const usedP = getGeminiLimitUsedPercent(bucket, limit);
|
|
66
|
-
return usedP != null ? colorByProvider(usedP, `${usedP}`, provFn) : dim("--");
|
|
67
|
-
}
|
|
68
|
-
|
|
69
44
|
// ============================================================================
|
|
70
|
-
//
|
|
45
|
+
// tfx-multi 상태 행 생성 (v2.2 HUD 통합)
|
|
71
46
|
// ============================================================================
|
|
72
|
-
export function
|
|
73
|
-
|
|
74
|
-
|
|
47
|
+
export function getTeamRow(currentTier, stateDir = TEAM_STATE_DIR) {
|
|
48
|
+
let latestPath = null;
|
|
49
|
+
let latestMtime = Date.now() - 24 * 60 * 60 * 1000;
|
|
75
50
|
try {
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
51
|
+
for (const name of readdirSync(stateDir)) {
|
|
52
|
+
if (!/^team-state-.+\.json$/.test(name)) continue;
|
|
53
|
+
const path = join(stateDir, name);
|
|
54
|
+
try {
|
|
55
|
+
const stat = statSync(path);
|
|
56
|
+
if (stat.isFile() && stat.mtimeMs > latestMtime) {
|
|
57
|
+
latestPath = path;
|
|
58
|
+
latestMtime = stat.mtimeMs;
|
|
59
|
+
}
|
|
60
|
+
} catch {
|
|
61
|
+
// 세션 종료 중 사라진 파일은 제외한다.
|
|
62
|
+
}
|
|
63
|
+
}
|
|
82
64
|
} catch {
|
|
83
65
|
return null;
|
|
84
66
|
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* 파이프라인 벤치마크 diff 결과를 HUD 요약 문자열로 포맷
|
|
89
|
-
*/
|
|
90
|
-
export function formatTokenSummary(diff) {
|
|
91
|
-
if (!diff?.delta?.total || !diff?.savings) return "";
|
|
92
|
-
const t = diff.delta.total;
|
|
93
|
-
const s = diff.savings;
|
|
94
|
-
|
|
95
|
-
const inputStr = formatTokenCount(t.input);
|
|
96
|
-
const outputStr = formatTokenCount(t.output);
|
|
97
|
-
const actualStr = formatSavings(s.actualCost);
|
|
98
|
-
const _claudeStr = formatSavings(s.claudeCost);
|
|
99
|
-
const savedPct =
|
|
100
|
-
s.claudeCost > 0 ? Math.round((s.saved / s.claudeCost) * 100) : 0;
|
|
101
|
-
|
|
102
|
-
return (
|
|
103
|
-
`${dim("tok:")}${inputStr}${dim("in")} ${outputStr}${dim("out")} ` +
|
|
104
|
-
`${dim("cost:")}${actualStr} ` +
|
|
105
|
-
`${dim("sv:")}${green(formatSavings(s.saved))}${dim("(")}${savedPct}%${dim(")")}`
|
|
106
|
-
);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
// ============================================================================
|
|
110
|
-
// tfx-multi 상태 행 생성 (v2.2 HUD 통합)
|
|
111
|
-
// ============================================================================
|
|
112
|
-
export function getTeamRow(currentTier) {
|
|
113
|
-
const teamState = readJson(TEAM_STATE_PATH, null);
|
|
67
|
+
const teamState = latestPath ? readJson(latestPath, null) : null;
|
|
114
68
|
if (!teamState?.sessionName) return null;
|
|
115
69
|
|
|
116
|
-
// 팀 생존 확인: startedAt 기준 24시간 초과면 stale로 간주
|
|
117
|
-
if (
|
|
118
|
-
teamState.startedAt &&
|
|
119
|
-
Date.now() - teamState.startedAt > 24 * 60 * 60 * 1000
|
|
120
|
-
)
|
|
121
|
-
return null;
|
|
122
|
-
|
|
123
70
|
const workers = (teamState.members || []).filter((m) => m.role === "worker");
|
|
124
71
|
if (!workers.length) return null;
|
|
125
72
|
|
|
@@ -177,38 +124,6 @@ export function getTeamRow(currentTier) {
|
|
|
177
124
|
};
|
|
178
125
|
}
|
|
179
126
|
|
|
180
|
-
// ============================================================================
|
|
181
|
-
// Mission Board 렌더러
|
|
182
|
-
// ============================================================================
|
|
183
|
-
|
|
184
|
-
const STATUS_ICON = {
|
|
185
|
-
active: "*",
|
|
186
|
-
idle: ".",
|
|
187
|
-
done: "+",
|
|
188
|
-
failed: "!",
|
|
189
|
-
};
|
|
190
|
-
|
|
191
|
-
/**
|
|
192
|
-
* Mission Board 상태를 1줄 compact 포맷으로 렌더링한다.
|
|
193
|
-
* 예: "MB: exec:+ ui:* perf:. [2/3 67%]"
|
|
194
|
-
* @param {{ agents: Array<{name: string, status: string, progress: number}>, dagLevel: number, totalProgress: number } | null} state
|
|
195
|
-
* @returns {string}
|
|
196
|
-
*/
|
|
197
|
-
export function renderMissionBoard(state) {
|
|
198
|
-
if (!state) return "";
|
|
199
|
-
|
|
200
|
-
const { agents, totalProgress } = state;
|
|
201
|
-
const done = agents.filter((a) => a.status === "done").length;
|
|
202
|
-
const total = agents.length;
|
|
203
|
-
|
|
204
|
-
const parts = agents.map((a) => {
|
|
205
|
-
const icon = STATUS_ICON[a.status] ?? "?";
|
|
206
|
-
return `${a.name}:${icon}`;
|
|
207
|
-
});
|
|
208
|
-
|
|
209
|
-
return `MB: ${parts.join(" ")} [${done}/${total} ${totalProgress}%]`;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
127
|
// ============================================================================
|
|
213
128
|
// 행 정렬 렌더링
|
|
214
129
|
// ============================================================================
|
|
@@ -254,15 +169,11 @@ export function getMicroLine(
|
|
|
254
169
|
contextView,
|
|
255
170
|
claudeUsage,
|
|
256
171
|
codexBuckets,
|
|
257
|
-
|
|
258
|
-
geminiBucket,
|
|
259
|
-
geminiMarker = "g",
|
|
172
|
+
antigravityReady,
|
|
260
173
|
options = {},
|
|
261
174
|
) {
|
|
262
|
-
// showCodex / showGemini 는 machine profile 의 TFX_DISABLE_* 게이트다. 기본값이
|
|
263
|
-
// true 라 8번째 인자를 주지 않는 기존 호출은 그대로 동작한다.
|
|
264
175
|
const { showCodex = true, showGemini = true } = options;
|
|
265
|
-
const ctxView = contextView || buildContextUsageView({}
|
|
176
|
+
const ctxView = contextView || buildContextUsageView({});
|
|
266
177
|
// Claude 5h/1w
|
|
267
178
|
const cF =
|
|
268
179
|
claudeUsage?.fiveHourPercent != null
|
|
@@ -294,17 +205,6 @@ export function getMicroLine(
|
|
|
294
205
|
}
|
|
295
206
|
}
|
|
296
207
|
|
|
297
|
-
// Gemini
|
|
298
|
-
let gVal;
|
|
299
|
-
if (geminiBucket) {
|
|
300
|
-
const gl = deriveGeminiLimits(geminiBucket);
|
|
301
|
-
gVal = formatGeminiCompactValue(geminiBucket, gl, geminiBlue);
|
|
302
|
-
} else if ((geminiSession?.total || 0) > 0) {
|
|
303
|
-
gVal = geminiBlue("\u221E");
|
|
304
|
-
} else {
|
|
305
|
-
gVal = dim("--");
|
|
306
|
-
}
|
|
307
|
-
|
|
308
208
|
const cols = getTerminalColumns() || 120;
|
|
309
209
|
// 세그먼트를 모아 join 한다. 차단된 프로바이더를 뺄 때 공백이 겹치지 않는다.
|
|
310
210
|
const segments = [`${bold(claudeOrange("c"))}${dim(":")}${cVal}`];
|
|
@@ -312,7 +212,9 @@ export function getMicroLine(
|
|
|
312
212
|
segments.push(`${bold(codexWhite("x"))}${dim(":")}${xVal}`);
|
|
313
213
|
}
|
|
314
214
|
if (showGemini) {
|
|
315
|
-
segments.push(
|
|
215
|
+
segments.push(
|
|
216
|
+
`${bold(geminiBlue(antigravityReady ? "a" : "g"))}${dim(":")}${antigravityReady ? "agy" : dim("--")}`,
|
|
217
|
+
);
|
|
316
218
|
}
|
|
317
219
|
segments.push(`${dim("CTX:")}${contextPercentText(ctxView)}`);
|
|
318
220
|
return truncateAnsi(segments.join(" "), cols);
|
|
@@ -328,7 +230,7 @@ function contextPercentText(ctxView) {
|
|
|
328
230
|
// Claude 행 렌더러
|
|
329
231
|
// ============================================================================
|
|
330
232
|
export function getClaudeRows(currentTier, contextView, claudeUsage) {
|
|
331
|
-
const ctxView = contextView || buildContextUsageView({}
|
|
233
|
+
const ctxView = contextView || buildContextUsageView({});
|
|
332
234
|
const prefix = `${bold(claudeOrange("c"))}:`;
|
|
333
235
|
// API 실측 데이터
|
|
334
236
|
const fiveHourPercent = claudeUsage?.fiveHourPercent ?? null;
|
|
@@ -429,91 +331,38 @@ export function getAccountLabel(
|
|
|
429
331
|
return label;
|
|
430
332
|
}
|
|
431
333
|
|
|
432
|
-
// 2슬롯: slot1 = 현재 장착 모델 약어 (Fh/Fm/Ph/Pl 등), slot2 = "Gn" Gemini family 통합
|
|
433
|
-
// realQuota.pools.{current,gemini_family} 가 있으면 실데이터, 없으면 placeholder.
|
|
434
|
-
function formatAntigravityQuotaSection(
|
|
435
|
-
currentTier,
|
|
436
|
-
realQuota,
|
|
437
|
-
provFn,
|
|
438
|
-
provAnsi,
|
|
439
|
-
) {
|
|
440
|
-
const pools = realQuota?.pools || {};
|
|
441
|
-
const abbr = realQuota?.currentAbbrev || "??";
|
|
442
|
-
const currentBucket = pools.current;
|
|
443
|
-
const familyBucket = pools.gemini_family;
|
|
444
|
-
const hasData = Boolean(currentBucket || familyBucket);
|
|
445
|
-
|
|
446
|
-
if (!hasData) {
|
|
447
|
-
// 기존 placeholder 동작 유지
|
|
448
|
-
if (currentTier === "minimal") {
|
|
449
|
-
return `${dim(`${abbr}:`)}${dim(formatPlaceholderPercentCell())} ${dim("Gn:")}${dim(formatPlaceholderPercentCell())}`;
|
|
450
|
-
}
|
|
451
|
-
if (currentTier === "compact") {
|
|
452
|
-
return `${dim(`${abbr}:`)}${dim(formatPlaceholderPercentCell())} ${dim(formatTimeCell("n/a"))} ${dim("Gn:")}${dim(formatPlaceholderPercentCell())} ${dim(formatTimeCell("n/a"))}`;
|
|
453
|
-
}
|
|
454
|
-
return `${dim(`${abbr}:`)}${tierDimBar(currentTier)}${dim(formatPlaceholderPercentCell())} ${dim(formatTimeCell("n/a"))} ${dim("Gn:")}${tierDimBar(currentTier)}${dim(formatPlaceholderPercentCell())} ${dim(formatTimeCell("n/a"))}`;
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
const slot = (bucket, label, { withBar, withTime }) => {
|
|
458
|
-
if (!bucket) {
|
|
459
|
-
const bar = withBar ? tierDimBar(currentTier) : "";
|
|
460
|
-
const base = `${dim(`${label}:`)}${bar}${dim(formatPlaceholderPercentCell())}`;
|
|
461
|
-
return withTime ? `${base} ${dim(formatTimeCell("n/a"))}` : base;
|
|
462
|
-
}
|
|
463
|
-
const gl = deriveGeminiLimits(bucket);
|
|
464
|
-
const usedP = getGeminiLimitUsedPercent(bucket, gl);
|
|
465
|
-
const bar =
|
|
466
|
-
withBar && usedP != null ? tierBar(currentTier, usedP, provAnsi) : "";
|
|
467
|
-
const base = `${dim(`${label}:`)}${bar}${formatGeminiLimitValue(gl, provFn)}`;
|
|
468
|
-
if (!withTime) return base;
|
|
469
|
-
const rstRemaining =
|
|
470
|
-
formatResetRemaining(bucket.resetTime, ONE_DAY_MS) || "n/a";
|
|
471
|
-
return `${base} ${dim(formatTimeCell(rstRemaining))}`;
|
|
472
|
-
};
|
|
473
|
-
|
|
474
|
-
if (currentTier === "minimal") {
|
|
475
|
-
return `${slot(currentBucket, abbr, { withBar: false, withTime: false })} ${slot(familyBucket, "Gn", { withBar: false, withTime: false })}`;
|
|
476
|
-
}
|
|
477
|
-
if (currentTier === "compact") {
|
|
478
|
-
return `${slot(currentBucket, abbr, { withBar: false, withTime: true })} ${slot(familyBucket, "Gn", { withBar: false, withTime: true })}`;
|
|
479
|
-
}
|
|
480
|
-
return `${slot(currentBucket, abbr, { withBar: true, withTime: true })} ${slot(familyBucket, "Gn", { withBar: true, withTime: true })}`;
|
|
481
|
-
}
|
|
482
|
-
|
|
483
334
|
export function getProviderRow(
|
|
484
335
|
currentTier,
|
|
485
336
|
provider,
|
|
486
337
|
marker,
|
|
487
338
|
markerColor,
|
|
488
|
-
qosProfile,
|
|
489
339
|
accountsConfig,
|
|
490
340
|
accountsState,
|
|
491
341
|
realQuota,
|
|
492
342
|
codexEmail,
|
|
493
|
-
modelLabel,
|
|
494
343
|
) {
|
|
495
344
|
const accountLabel = fitText(
|
|
496
345
|
getAccountLabel(provider, accountsConfig, accountsState, codexEmail),
|
|
497
346
|
ACCOUNT_LABEL_WIDTH,
|
|
498
347
|
);
|
|
499
348
|
|
|
500
|
-
const
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
349
|
+
const prefix = `${bold(markerColor(marker))}:`;
|
|
350
|
+
if (provider === "antigravity" || provider === "gemini") {
|
|
351
|
+
return {
|
|
352
|
+
prefix,
|
|
353
|
+
left:
|
|
354
|
+
provider === "antigravity"
|
|
355
|
+
? markerColor(realQuota?.currentAbbrev || "agy")
|
|
356
|
+
: dim("--"),
|
|
357
|
+
right: accountLabel ? markerColor(accountLabel) : "",
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
const provAnsi = CODEX_WHITE;
|
|
361
|
+
const provFn = codexWhite;
|
|
509
362
|
let quotaSection;
|
|
510
|
-
const _extraRightSection = "";
|
|
511
363
|
|
|
512
364
|
if (currentTier === "nano" || currentTier === "micro") {
|
|
513
365
|
const minPrefix = `${bold(markerColor(`${marker}`))}:`;
|
|
514
|
-
if (provider === "antigravity") {
|
|
515
|
-
return { prefix: minPrefix, left: dim("--"), right: "" };
|
|
516
|
-
}
|
|
517
366
|
if (realQuota?.type === "codex") {
|
|
518
367
|
const main =
|
|
519
368
|
realQuota.buckets.codex ||
|
|
@@ -542,36 +391,10 @@ export function getProviderRow(
|
|
|
542
391
|
};
|
|
543
392
|
}
|
|
544
393
|
}
|
|
545
|
-
if (provider === "gemini" && realQuota?.type === "gemini") {
|
|
546
|
-
const pools = realQuota.pools || {};
|
|
547
|
-
if (pools.pro || pools.flash) {
|
|
548
|
-
const pP = pools.pro ? deriveGeminiLimits(pools.pro) : null;
|
|
549
|
-
const pF = pools.flash ? deriveGeminiLimits(pools.flash) : null;
|
|
550
|
-
const pStr = pools.pro
|
|
551
|
-
? formatGeminiCompactValue(pools.pro, pP, provFn)
|
|
552
|
-
: dim("--");
|
|
553
|
-
const fStr = pools.flash
|
|
554
|
-
? formatGeminiCompactValue(pools.flash, pF, provFn)
|
|
555
|
-
: dim("--");
|
|
556
|
-
return {
|
|
557
|
-
prefix: minPrefix,
|
|
558
|
-
left: `${pStr}${dim("/")}${fStr}`,
|
|
559
|
-
right: "",
|
|
560
|
-
};
|
|
561
|
-
}
|
|
562
|
-
}
|
|
563
394
|
return { prefix: minPrefix, left: dim("--/--"), right: "" };
|
|
564
395
|
}
|
|
565
396
|
|
|
566
397
|
if (currentTier === "minimal") {
|
|
567
|
-
if (provider === "antigravity") {
|
|
568
|
-
quotaSection = formatAntigravityQuotaSection(
|
|
569
|
-
currentTier,
|
|
570
|
-
realQuota,
|
|
571
|
-
provFn,
|
|
572
|
-
provAnsi,
|
|
573
|
-
);
|
|
574
|
-
}
|
|
575
398
|
if (realQuota?.type === "codex") {
|
|
576
399
|
const main =
|
|
577
400
|
realQuota.buckets.codex ||
|
|
@@ -596,24 +419,9 @@ export function getProviderRow(
|
|
|
596
419
|
quotaSection = `${dim("5h:")}${fCell} ${dim("1w:")}${wCell}`;
|
|
597
420
|
}
|
|
598
421
|
}
|
|
599
|
-
if (provider === "gemini" && realQuota?.type === "gemini") {
|
|
600
|
-
const pools = realQuota.pools || {};
|
|
601
|
-
if (pools.pro || pools.flash) {
|
|
602
|
-
const slot = (bucket, label) => {
|
|
603
|
-
if (!bucket)
|
|
604
|
-
return `${dim(label + ":")}${dim(formatPlaceholderPercentCell())}`;
|
|
605
|
-
const gl = deriveGeminiLimits(bucket);
|
|
606
|
-
return `${dim(label + ":")}${formatGeminiLimitValue(gl, provFn)}`;
|
|
607
|
-
};
|
|
608
|
-
quotaSection = `${slot(pools.pro, "Pr")} ${slot(pools.flash, "Fl")}`;
|
|
609
|
-
} else {
|
|
610
|
-
quotaSection = `${dim("Pr:")}${dim(formatPlaceholderPercentCell())} ${dim("Fl:")}${dim(formatPlaceholderPercentCell())}`;
|
|
611
|
-
}
|
|
612
|
-
}
|
|
613
422
|
if (!quotaSection) {
|
|
614
423
|
quotaSection = `${dim("5h:")}${dim(formatPlaceholderPercentCell())} ${dim("1w:")}${dim(formatPlaceholderPercentCell())}`;
|
|
615
424
|
}
|
|
616
|
-
const prefix = `${bold(markerColor(`${marker}`))}:`;
|
|
617
425
|
return {
|
|
618
426
|
prefix,
|
|
619
427
|
left: quotaSection,
|
|
@@ -622,14 +430,6 @@ export function getProviderRow(
|
|
|
622
430
|
}
|
|
623
431
|
|
|
624
432
|
if (currentTier === "compact") {
|
|
625
|
-
if (provider === "antigravity") {
|
|
626
|
-
quotaSection = formatAntigravityQuotaSection(
|
|
627
|
-
currentTier,
|
|
628
|
-
realQuota,
|
|
629
|
-
provFn,
|
|
630
|
-
provAnsi,
|
|
631
|
-
);
|
|
632
|
-
}
|
|
633
433
|
if (realQuota?.type === "codex") {
|
|
634
434
|
const main =
|
|
635
435
|
realQuota.buckets.codex ||
|
|
@@ -659,27 +459,9 @@ export function getProviderRow(
|
|
|
659
459
|
if (main.mixedWindows) quotaSection += dim("*");
|
|
660
460
|
}
|
|
661
461
|
}
|
|
662
|
-
if (provider === "gemini" && realQuota?.type === "gemini") {
|
|
663
|
-
const pools = realQuota.pools || {};
|
|
664
|
-
const hasAnyPool = pools.pro || pools.flash;
|
|
665
|
-
if (hasAnyPool) {
|
|
666
|
-
const slot = (bucket, label) => {
|
|
667
|
-
if (!bucket)
|
|
668
|
-
return `${dim(label + ":")}${dim(formatPlaceholderPercentCell())} ${dim(formatTimeCell("n/a"))}`;
|
|
669
|
-
const gl = deriveGeminiLimits(bucket);
|
|
670
|
-
const rstRemaining =
|
|
671
|
-
formatResetRemaining(bucket.resetTime, ONE_DAY_MS) || "n/a";
|
|
672
|
-
return `${dim(label + ":")}${formatGeminiLimitValue(gl, provFn)} ${dim(formatTimeCell(rstRemaining))}`;
|
|
673
|
-
};
|
|
674
|
-
quotaSection = `${slot(pools.pro, "Pr")} ${slot(pools.flash, "Fl")}`;
|
|
675
|
-
} else {
|
|
676
|
-
quotaSection = `${dim("Pr:")}${dim(formatPlaceholderPercentCell())} ${dim(formatTimeCell("n/a"))} ${dim("Fl:")}${dim(formatPlaceholderPercentCell())} ${dim(formatTimeCell("n/a"))}`;
|
|
677
|
-
}
|
|
678
|
-
}
|
|
679
462
|
if (!quotaSection) {
|
|
680
463
|
quotaSection = `${dim("5h:")}${dim(formatPlaceholderPercentCell())} ${dim(formatTimeCell("n/a"))} ${dim("1w:")}${dim(formatPlaceholderPercentCell())} ${dim(formatTimeCellDH("--d--h"))}`;
|
|
681
464
|
}
|
|
682
|
-
const prefix = `${bold(markerColor(`${marker}`))}:`;
|
|
683
465
|
const compactRight = [accountLabel ? markerColor(accountLabel) : ""]
|
|
684
466
|
.filter(Boolean)
|
|
685
467
|
.join(" ");
|
|
@@ -687,14 +469,6 @@ export function getProviderRow(
|
|
|
687
469
|
}
|
|
688
470
|
|
|
689
471
|
// full tier
|
|
690
|
-
if (provider === "antigravity") {
|
|
691
|
-
quotaSection = formatAntigravityQuotaSection(
|
|
692
|
-
currentTier,
|
|
693
|
-
realQuota,
|
|
694
|
-
provFn,
|
|
695
|
-
provAnsi,
|
|
696
|
-
);
|
|
697
|
-
}
|
|
698
472
|
|
|
699
473
|
if (realQuota?.type === "codex") {
|
|
700
474
|
const main =
|
|
@@ -737,43 +511,15 @@ export function getProviderRow(
|
|
|
737
511
|
}
|
|
738
512
|
}
|
|
739
513
|
|
|
740
|
-
if (provider === "gemini" && realQuota?.type === "gemini") {
|
|
741
|
-
const pools = realQuota.pools || {};
|
|
742
|
-
const hasAnyPool = pools.pro || pools.flash;
|
|
743
|
-
|
|
744
|
-
if (hasAnyPool) {
|
|
745
|
-
const slot = (bucket, label) => {
|
|
746
|
-
if (!bucket) {
|
|
747
|
-
return `${dim(label + ":")}${tierDimBar(currentTier)}${dim(formatPlaceholderPercentCell())} ${dim(formatTimeCell("n/a"))}`;
|
|
748
|
-
}
|
|
749
|
-
const gl = deriveGeminiLimits(bucket);
|
|
750
|
-
const usedP = getGeminiLimitUsedPercent(bucket, gl);
|
|
751
|
-
const rstRemaining =
|
|
752
|
-
formatResetRemaining(bucket.resetTime, ONE_DAY_MS) || "n/a";
|
|
753
|
-
const bar = usedP != null ? tierBar(currentTier, usedP, provAnsi) : "";
|
|
754
|
-
return `${dim(label + ":")}${bar}${formatGeminiLimitValue(gl, provFn)} ${dim(formatTimeCell(rstRemaining))}`;
|
|
755
|
-
};
|
|
756
|
-
|
|
757
|
-
quotaSection = `${slot(pools.pro, "Pr")} ${slot(pools.flash, "Fl")}`;
|
|
758
|
-
} else {
|
|
759
|
-
quotaSection =
|
|
760
|
-
`${dim("Pr:")}${tierDimBar(currentTier)}${dim(formatPlaceholderPercentCell())} ${dim(formatTimeCell("n/a"))} ` +
|
|
761
|
-
`${dim("Fl:")}${tierDimBar(currentTier)}${dim(formatPlaceholderPercentCell())} ${dim(formatTimeCell("n/a"))}`;
|
|
762
|
-
}
|
|
763
|
-
}
|
|
764
|
-
|
|
765
514
|
// 폴백
|
|
766
515
|
if (!quotaSection) {
|
|
767
516
|
quotaSection = `${dim("5h:")}${tierDimBar(currentTier)}${dim(formatPlaceholderPercentCell())} ${dim(formatTimeCell("n/a"))} ${dim("1w:")}${tierDimBar(currentTier)}${dim(formatPlaceholderPercentCell())} ${dim(formatTimeCellDH("--d--h"))}`;
|
|
768
517
|
}
|
|
769
518
|
|
|
770
|
-
const prefix = `${bold(markerColor(`${marker}`))}:`;
|
|
771
519
|
const accountSection = `${markerColor(accountLabel)}`;
|
|
772
|
-
const modelLabelSection = modelLabel ? markerColor(modelLabel) : "";
|
|
773
|
-
const rightParts = [accountSection, modelLabelSection].filter(Boolean);
|
|
774
520
|
return {
|
|
775
521
|
prefix,
|
|
776
522
|
left: quotaSection,
|
|
777
|
-
right:
|
|
523
|
+
right: accountSection,
|
|
778
524
|
};
|
|
779
525
|
}
|
package/hud/terminal.mjs
CHANGED
|
@@ -60,56 +60,6 @@ export function getTerminalColumns() {
|
|
|
60
60
|
return 0;
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
let _cachedRows = 0;
|
|
64
|
-
export function getTerminalRows() {
|
|
65
|
-
if (_cachedRows > 0) return _cachedRows;
|
|
66
|
-
if (process.stdout.rows) {
|
|
67
|
-
_cachedRows = process.stdout.rows;
|
|
68
|
-
return _cachedRows;
|
|
69
|
-
}
|
|
70
|
-
if (process.stderr.rows) {
|
|
71
|
-
_cachedRows = process.stderr.rows;
|
|
72
|
-
return _cachedRows;
|
|
73
|
-
}
|
|
74
|
-
const envLines = Number(process.env.LINES);
|
|
75
|
-
if (envLines > 0) {
|
|
76
|
-
_cachedRows = envLines;
|
|
77
|
-
return _cachedRows;
|
|
78
|
-
}
|
|
79
|
-
try {
|
|
80
|
-
if (process.platform === "win32") {
|
|
81
|
-
const raw = execSync("mode con", {
|
|
82
|
-
timeout: 2000,
|
|
83
|
-
stdio: ["pipe", "pipe", "pipe"],
|
|
84
|
-
windowsHide: true,
|
|
85
|
-
}).toString();
|
|
86
|
-
const m =
|
|
87
|
-
raw.match(/Lines[^:]*:\s*(\d+)/i) || raw.match(/줄[^:]*:\s*(\d+)/);
|
|
88
|
-
if (m) {
|
|
89
|
-
_cachedRows = Number(m[1]);
|
|
90
|
-
return _cachedRows;
|
|
91
|
-
}
|
|
92
|
-
} else {
|
|
93
|
-
const raw = execSync(
|
|
94
|
-
"tput lines 2>/dev/null || stty size 2>/dev/null | awk '{print $1}'",
|
|
95
|
-
{
|
|
96
|
-
timeout: 2000,
|
|
97
|
-
stdio: ["pipe", "pipe", "pipe"],
|
|
98
|
-
},
|
|
99
|
-
)
|
|
100
|
-
.toString()
|
|
101
|
-
.trim();
|
|
102
|
-
if (raw && !Number.isNaN(Number(raw))) {
|
|
103
|
-
_cachedRows = Number(raw);
|
|
104
|
-
return _cachedRows;
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
} catch {
|
|
108
|
-
/* 감지 실패 */
|
|
109
|
-
}
|
|
110
|
-
return 0;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
63
|
export function detectCompactMode() {
|
|
114
64
|
// 1. 명시적 CLI 플래그
|
|
115
65
|
if (process.argv.includes("--compact")) return true;
|
|
@@ -153,7 +103,7 @@ export function detectMinimalMode() {
|
|
|
153
103
|
* 인디케이터 인식 + 터미널 크기 기반 tier 자동 선택.
|
|
154
104
|
* main()에서 stdin 수신 후 호출하여 CURRENT_TIER 갱신.
|
|
155
105
|
*/
|
|
156
|
-
export function selectTier(
|
|
106
|
+
export function selectTier() {
|
|
157
107
|
const hudConfig = readJson(HUD_CONFIG_PATH, null);
|
|
158
108
|
|
|
159
109
|
// 1) 명시적 tier 강제 설정
|
|
@@ -196,15 +146,3 @@ export function tierDimBar(currentTier) {
|
|
|
196
146
|
? DIM + "░".repeat(GAUGE_WIDTH) + RESET + " "
|
|
197
147
|
: "";
|
|
198
148
|
}
|
|
199
|
-
// Gemini ∞% 전용: 무한 쿼터이므로 dim 회색 바
|
|
200
|
-
export function tierInfBar(currentTier) {
|
|
201
|
-
return currentTier === "full"
|
|
202
|
-
? DIM + "█".repeat(GAUGE_WIDTH) + RESET + " "
|
|
203
|
-
: "";
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
// 테스트 지원: 캐시 초기화
|
|
207
|
-
export function _resetTerminalCache() {
|
|
208
|
-
_cachedColumns = 0;
|
|
209
|
-
_cachedRows = 0;
|
|
210
|
-
}
|
package/hud/utils.mjs
CHANGED
|
@@ -176,17 +176,6 @@ export function getCliArgValue(flag) {
|
|
|
176
176
|
return process.argv[idx + 1] || null;
|
|
177
177
|
}
|
|
178
178
|
|
|
179
|
-
export function formatDuration(ms) {
|
|
180
|
-
if (!Number.isFinite(ms) || ms <= 0) return "n/a";
|
|
181
|
-
const totalMinutes = Math.floor(ms / 60000);
|
|
182
|
-
const days = Math.floor(totalMinutes / (60 * 24));
|
|
183
|
-
const hours = Math.floor((totalMinutes % (60 * 24)) / 60);
|
|
184
|
-
const minutes = totalMinutes % 60;
|
|
185
|
-
if (days > 0) return hours > 0 ? `${days}d${hours}h` : `${days}d`;
|
|
186
|
-
if (hours > 0) return minutes > 0 ? `${hours}h${minutes}m` : `${hours}h`;
|
|
187
|
-
return `${minutes}m`;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
179
|
export function formatTokenCount(n) {
|
|
191
180
|
if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`;
|
|
192
181
|
if (n >= 1_000) return `${Math.round(n / 1_000)}K`;
|
|
@@ -261,13 +250,6 @@ export function formatResetRemainingDayHour(isoOrUnix, cycleMs = 0) {
|
|
|
261
250
|
return `${String(days).padStart(2, "0")}d${String(hours).padStart(2, "0")}h`;
|
|
262
251
|
}
|
|
263
252
|
|
|
264
|
-
export function calcCooldownLeftSeconds(isoDatetime) {
|
|
265
|
-
if (!isoDatetime) return 0;
|
|
266
|
-
const cooldownMs = new Date(isoDatetime).getTime() - Date.now();
|
|
267
|
-
if (!Number.isFinite(cooldownMs) || cooldownMs <= 0) return 0;
|
|
268
|
-
return Math.ceil(cooldownMs / 1000);
|
|
269
|
-
}
|
|
270
|
-
|
|
271
253
|
export function getProviderAccountId(provider, accountsConfig, accountsState) {
|
|
272
254
|
const providerState = accountsState?.providers?.[provider] || {};
|
|
273
255
|
const selectedId = providerState.last_selected_id;
|
|
@@ -333,9 +315,3 @@ export function createHttpsPost(https, timeoutMs) {
|
|
|
333
315
|
});
|
|
334
316
|
};
|
|
335
317
|
}
|
|
336
|
-
|
|
337
|
-
export function formatSavings(dollars) {
|
|
338
|
-
if (dollars >= 100) return `$${Math.round(dollars)}`;
|
|
339
|
-
if (dollars >= 10) return `$${dollars.toFixed(1)}`;
|
|
340
|
-
return `$${dollars.toFixed(2)}`;
|
|
341
|
-
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@triflux/core",
|
|
3
|
-
"version": "10.50.
|
|
3
|
+
"version": "10.50.2",
|
|
4
4
|
"description": "triflux core — CLI routing, pipeline, adapters. Zero native dependencies.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "hub/index.mjs",
|
|
@@ -17,7 +17,6 @@
|
|
|
17
17
|
"@iarna/toml": "^2.2.5",
|
|
18
18
|
"pino": "^10.3.1",
|
|
19
19
|
"pino-pretty": "^13.1.3",
|
|
20
|
-
"tree-kill": "^1.2.2",
|
|
21
20
|
"zod": "^4.0.0"
|
|
22
21
|
},
|
|
23
22
|
"files": [
|
|
@@ -59,7 +59,7 @@ const LEGACY_DEFAULT_MODELS = new Set(["Gemini 3.5 Flash (Medium)"]);
|
|
|
59
59
|
// ── 용도별 effort (SSOT) ──
|
|
60
60
|
// 한 세대(3.8 Flash)만 쓰고 역할에 따라 effort 를 나눈다. 키는 tfx 에이전트/역할 이름
|
|
61
61
|
// (agent-map.json 의 에이전트, tfx multi --assign 의 role). bash(tfx-route.sh)와
|
|
62
|
-
//
|
|
62
|
+
// 실행 모드와 cli-agy가 이 표를 공유한다.
|
|
63
63
|
// High : 판단이 결과를 좌우하는 역할 (검토, 설계, 디버깅, 분석)
|
|
64
64
|
// Medium : 생성/작성/실행 (기본값)
|
|
65
65
|
// Low : 분류, 요약, 추출, 번역처럼 짧고 기계적인 작업
|